This commit is contained in:
cubeww 2019-11-02 17:24:04 +08:00
parent 18ff91dc96
commit aa17b9622b
2 changed files with 889 additions and 1 deletions

885
ExportToProject.csx Normal file
View file

@ -0,0 +1,885 @@
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using UndertaleModLib.Models;
using UndertaleModLib.Util;
using UndertaleModLib.Decompiler;
int progress = 0;
string projFolder = GetFolder(FilePath) + "Export_Project" + Path.DirectorySeparatorChar;
var context = new DecompileContext(Data, true);
TextureWorker worker = new TextureWorker();
ThreadLocal<DecompileContext> DECOMPILE_CONTEXT = new ThreadLocal<DecompileContext>(() => new DecompileContext(Data, false));
if (Directory.Exists(projFolder))
{
ScriptError("A project export already exists. Please remove it.", "Error");
return;
}
Directory.CreateDirectory(projFolder);
//UpdateProgressBar (null, "Exporting backgrounds...", progress++, 8);
// --------------- 开始导出 ---------------
// 执行导出精灵
UpdateProgressBar(null, "Exporting sprites...", progress++, 8);
await ExportSprites();
// 执行导出背景
UpdateProgressBar(null, "Exporting backgrounds...", progress++, 8);
await ExportBackground();
// 执行导出对象
UpdateProgressBar(null, "Exporting objects...", progress++, 8);
await ExportGameObjects();
// 执行导出房间
UpdateProgressBar(null, "Exporting rooms...", progress++, 8);
await ExportRooms();
// 执行导出声音
UpdateProgressBar(null, "Exporting sounds...", progress++, 8);
await ExportSounds();
// 执行导出脚本
UpdateProgressBar(null, "Exporting scripts...", progress++, 8);
await ExportScripts();
// 执行导出字体
UpdateProgressBar(null, "Exporting fonts...", progress++, 8);
await ExportFonts();
// 执行导出项目文件
UpdateProgressBar(null, "Exporting project file...", progress++, 8);
ExportProjectFile();
// --------------- 导出完毕 ---------------
worker.Cleanup();
HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + projFolder);
string GetFolder(string path)
{
return Path.GetDirectoryName(path) + Path.DirectorySeparatorChar;
}
string BoolToString(bool value)
{
return value ? "-1" : "0";
}
// --------------- 导出精灵 ---------------
async Task ExportSprites()
{
Directory.CreateDirectory(projFolder + "/sprites/images");
await Task.Run(() => Parallel.ForEach(Data.Sprites, ExportSprite));
}
void ExportSprite(UndertaleSprite sprite)
{
// 保存精灵GMX
var xmlWriter = XmlWriter.Create(projFolder + "/sprites/" + sprite.Name.Content + ".sprite.gmx");
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("sprite");
xmlWriter.WriteStartElement("type");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("xorig");
xmlWriter.WriteString(sprite.OriginX.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("yorig");
xmlWriter.WriteString(sprite.OriginY.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("colkind");
xmlWriter.WriteString(sprite.BBoxMode.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("coltolerance");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("sepmasks");
xmlWriter.WriteString(sprite.SepMasks.ToString("D"));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("bboxmode");
xmlWriter.WriteString(sprite.BBoxMode.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("bbox_left");
xmlWriter.WriteString(sprite.MarginLeft.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("bbox_right");
xmlWriter.WriteString(sprite.MarginRight.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("bbox_top");
xmlWriter.WriteString(sprite.MarginTop.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("bbox_bottom");
xmlWriter.WriteString(sprite.MarginBottom.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("HTile");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("VTile");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("TextureGroups");
xmlWriter.WriteStartElement("TextureGroup0");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("For3D");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("width");
xmlWriter.WriteString(sprite.Width.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("height");
xmlWriter.WriteString(sprite.Height.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("frames");
for (int i = 0; i < sprite.Textures.Count; i++)
{
if (sprite.Textures[i]?.Texture != null)
{
xmlWriter.WriteStartElement("frame");
xmlWriter.WriteAttributeString("index", i.ToString());
xmlWriter.WriteString("images\\" + sprite.Name.Content + "_" + i + ".png");
xmlWriter.WriteEndElement();
}
}
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
xmlWriter.Close();
// 保存精灵图像
for (int i = 0; i < sprite.Textures.Count; i++)
if (sprite.Textures[i]?.Texture != null)
worker.ExportAsPNG(sprite.Textures[i].Texture, projFolder + "/sprites/images/" + sprite.Name.Content + "_" + i + ".png");
}
// --------------- 导出背景 ---------------
async Task ExportBackground()
{
Directory.CreateDirectory(projFolder + "/backgrounds/images");
await Task.Run(() => Parallel.ForEach(Data.Backgrounds, ExportBackground));
}
void ExportBackground(UndertaleBackground background)
{
// 保存背景GMX
var xmlWriter = XmlWriter.Create(projFolder + "/backgrounds/" + background.Name.Content + ".background.gmx");
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("background");
xmlWriter.WriteStartElement("istileset");
xmlWriter.WriteString("-1");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("tilewidth");
xmlWriter.WriteString(background.Texture.BoundingWidth.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("tileheight");
xmlWriter.WriteString(background.Texture.BoundingHeight.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("tilexoff");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("tileyoff");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("tilehsep");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("tilevsep");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("HTile");
xmlWriter.WriteString("-1");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("VTile");
xmlWriter.WriteString("-1");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("TextureGroups");
xmlWriter.WriteStartElement("TextureGroup0");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("For3D");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("width");
xmlWriter.WriteString(background.Texture.BoundingWidth.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("height");
xmlWriter.WriteString(background.Texture.BoundingHeight.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("data");
xmlWriter.WriteString("images\\" + background.Name.Content + ".png");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
xmlWriter.Close();
// 保存背景图像
worker.ExportAsPNG(background.Texture, projFolder + "/backgrounds/images/" + background.Name.Content + ".png");
}
// --------------- 导出对象 ---------------
async Task ExportGameObjects()
{
Directory.CreateDirectory(projFolder + "/objects");
await Task.Run(() => Parallel.ForEach(Data.GameObjects, ExportGameObject));
}
void ExportGameObject(UndertaleGameObject gameObject)
{
//try
{
// 保存对象GMX
var xmlWriter = XmlWriter.Create(projFolder + "/objects/" + gameObject.Name.Content + ".object.gmx");
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("object");
xmlWriter.WriteStartElement("spriteName");
xmlWriter.WriteString(gameObject.Sprite is null ? "<undefined>" : gameObject.Sprite.Name.Content);
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("solid");
xmlWriter.WriteString(BoolToString(gameObject.Solid));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("visible");
xmlWriter.WriteString(BoolToString(gameObject.Visible));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("depth");
xmlWriter.WriteString(gameObject.Depth.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("persistent");
xmlWriter.WriteString(BoolToString(gameObject.Persistent));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("parentName");
xmlWriter.WriteString(gameObject.ParentId is null ? "<undefined>" : gameObject.ParentId.Name.Content);
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("maskName");
xmlWriter.WriteString(gameObject.TextureMaskId is null ? "<undefined>" : gameObject.TextureMaskId.Name.Content);
xmlWriter.WriteEndElement();
// 保存事件
xmlWriter.WriteStartElement("events");
// 遍历事件类型列表
for (int i = 0; i < gameObject.Events.Count; i++)
{
// 判断某个事件类型是否为空
if (gameObject.Events[i].Count > 0)
{
// 遍历事件列表
foreach (var j in gameObject.Events[i])
{
xmlWriter.WriteStartElement("event");
xmlWriter.WriteAttributeString("eventtype", i.ToString());
if (j.EventSubtype == 4)
{
// 当事件类型为碰撞事件时,要获取碰撞对象的实际名字
xmlWriter.WriteAttributeString("ename", Data.GameObjects[(int)j.EventSubtype].Name.Content);
}
else
{
// 直接获取子事件编号
xmlWriter.WriteAttributeString("enumb", j.EventSubtype.ToString());
}
// 保存动作
xmlWriter.WriteStartElement("action");
// 遍历动作列表
foreach (var k in j.Actions)
{
xmlWriter.WriteStartElement("libid");
xmlWriter.WriteString(k.LibID.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("id");
xmlWriter.WriteString(k.ID.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("kind");
xmlWriter.WriteString(k.Kind.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("userelative");
xmlWriter.WriteString(BoolToString(k.UseRelative));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("isquestion");
xmlWriter.WriteString(BoolToString(k.IsQuestion));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("useapplyto");
xmlWriter.WriteString(BoolToString(k.UseApplyTo));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("exetype");
xmlWriter.WriteString(k.ExeType.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("functionname");
xmlWriter.WriteString(k.ActionName.Content);
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("codestring");
xmlWriter.WriteString("");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("whoName");
// 在data.win中所有DND动作被转换为字节码自动处理执行者
xmlWriter.WriteString("self");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("relative");
xmlWriter.WriteString(BoolToString(k.Relative));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("isnot");
xmlWriter.WriteString(BoolToString(k.IsNot));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("arguments");
xmlWriter.WriteStartElement("argument");
xmlWriter.WriteStartElement("kind");
xmlWriter.WriteString("1");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("string");
xmlWriter.WriteString(k.CodeId != null ? Decompiler.Decompile(k.CodeId, DECOMPILE_CONTEXT.Value) : "");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
}
// TODOUTMT没有给出关于对象物理的属性
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
}
}
}
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
xmlWriter.Close();
}
//catch { }
}
// --------------- 导出房间 ---------------
async Task ExportRooms()
{
Directory.CreateDirectory(projFolder + "/rooms");
await Task.Run(() => Parallel.ForEach(Data.Rooms, ExportRoom));
}
void ExportRoom(UndertaleRoom room)
{
// 保存房间GMX
var xmlWriter = XmlWriter.Create(projFolder + "/rooms/" + room.Name.Content + ".room.gmx");
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("room");
// 基本设定
xmlWriter.WriteStartElement("caption");
xmlWriter.WriteString(room.Caption.Content);
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("width");
xmlWriter.WriteString(room.Width.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("height");
xmlWriter.WriteString(room.Height.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("vsnap");
xmlWriter.WriteString("32");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("hsnap");
xmlWriter.WriteString("32");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("isometric");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("speed");
xmlWriter.WriteString(room.Speed.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("persistent");
xmlWriter.WriteString(BoolToString(room.Persistent));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("colour");
xmlWriter.WriteString(room.BackgroundColor.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("showcolour");
xmlWriter.WriteString(BoolToString(room.DrawBackgroundColor));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("code");
xmlWriter.WriteString(room.CreationCodeId is null ? "" : Decompiler.Decompile(room.CreationCodeId, context));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("enableViews");
xmlWriter.WriteString(BoolToString(room.Flags.HasFlag(UndertaleRoom.RoomEntryFlags.EnableViews)));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("clearViewBackground");
xmlWriter.WriteString(BoolToString(room.Flags.HasFlag(UndertaleRoom.RoomEntryFlags.ShowColor)));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("clearDisplayBuffer");
xmlWriter.WriteString(BoolToString(room.Flags.HasFlag(UndertaleRoom.RoomEntryFlags.ClearDisplayBuffer)));
xmlWriter.WriteEndElement();
// TODO这里原room文件有一些makerSettings看似不必要就没有生成
// 背景
xmlWriter.WriteStartElement("backgrounds");
foreach (var i in room.Backgrounds)
{
xmlWriter.WriteStartElement("background");
xmlWriter.WriteAttributeString("visible", BoolToString(i.Enabled));
xmlWriter.WriteAttributeString("foreground", BoolToString(i.Foreground));
xmlWriter.WriteAttributeString("name", i.BackgroundDefinition is null ? "" : i.BackgroundDefinition.Name.Content);
xmlWriter.WriteAttributeString("x", i.X.ToString());
xmlWriter.WriteAttributeString("y", i.Y.ToString());
xmlWriter.WriteAttributeString("htiled", i.TileX.ToString());
xmlWriter.WriteAttributeString("vtiled", i.TileY.ToString());
xmlWriter.WriteAttributeString("hspeed", i.SpeedX.ToString());
xmlWriter.WriteAttributeString("vspeed", i.SpeedY.ToString());
// TODO这里stretch属性UTMT中没有给出
xmlWriter.WriteAttributeString("stretch", "0");
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
// 视野
xmlWriter.WriteStartElement("views");
foreach (var i in room.Views)
{
xmlWriter.WriteStartElement("view");
xmlWriter.WriteAttributeString("visible", BoolToString(i.Enabled));
xmlWriter.WriteAttributeString("objName", i.ObjectId is null ? "<undefined>" : i.ObjectId.Name.Content);
xmlWriter.WriteAttributeString("xview", i.ViewX.ToString());
xmlWriter.WriteAttributeString("yview", i.ViewY.ToString());
xmlWriter.WriteAttributeString("wview", i.ViewWidth.ToString());
xmlWriter.WriteAttributeString("hview", i.ViewHeight.ToString());
xmlWriter.WriteAttributeString("xport", i.PortX.ToString());
xmlWriter.WriteAttributeString("yport", i.PortY.ToString());
xmlWriter.WriteAttributeString("wport", i.PortWidth.ToString());
xmlWriter.WriteAttributeString("hport", i.PortHeight.ToString());
xmlWriter.WriteAttributeString("hborder", i.BorderX.ToString());
xmlWriter.WriteAttributeString("vborder", i.BorderY.ToString());
xmlWriter.WriteAttributeString("hspeed", i.SpeedX.ToString());
xmlWriter.WriteAttributeString("vspeed", i.SpeedY.ToString());
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
// 实例
xmlWriter.WriteStartElement("instances");
foreach (var i in room.GameObjects)
{
xmlWriter.WriteStartElement("instance");
xmlWriter.WriteAttributeString("objName", i.ObjectDefinition.Name.Content);
xmlWriter.WriteAttributeString("x", i.X.ToString());
xmlWriter.WriteAttributeString("y", i.Y.ToString());
xmlWriter.WriteAttributeString("name", "inst_" + i.InstanceID.ToString("X"));
// TODO这里的locked属性UTMT里没有给出
xmlWriter.WriteAttributeString("locked", "0");
xmlWriter.WriteAttributeString("code", i.CreationCode != null ? Decompiler.Decompile(i.CreationCode, DECOMPILE_CONTEXT.Value) : "");
xmlWriter.WriteAttributeString("scaleX", i.ScaleX.ToString());
xmlWriter.WriteAttributeString("scaleY", i.ScaleY.ToString());
xmlWriter.WriteAttributeString("colour", i.Color.ToString());
xmlWriter.WriteAttributeString("rotation", i.Rotation.ToString());
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
// 贴图
xmlWriter.WriteStartElement("tiles");
foreach (var i in room.Tiles)
{
xmlWriter.WriteStartElement("tile");
xmlWriter.WriteAttributeString("bgName", i.BackgroundDefinition.Name.Content);
xmlWriter.WriteAttributeString("x", i.X.ToString());
xmlWriter.WriteAttributeString("y", i.Y.ToString());
xmlWriter.WriteAttributeString("w", i.Width.ToString());
xmlWriter.WriteAttributeString("h", i.Height.ToString());
xmlWriter.WriteAttributeString("xo", i.SourceX.ToString());
xmlWriter.WriteAttributeString("yo", i.SourceY.ToString());
xmlWriter.WriteAttributeString("id", i.InstanceID.ToString());
xmlWriter.WriteAttributeString("name", "inst_" + i.InstanceID.ToString("X"));
xmlWriter.WriteAttributeString("depth", i.TileDepth.ToString());
// TODO这里的locked属性UTMT里没有给出
xmlWriter.WriteAttributeString("locked", "0");
xmlWriter.WriteAttributeString("colour", i.Color.ToString());
xmlWriter.WriteAttributeString("scaleX", i.ScaleX.ToString());
xmlWriter.WriteAttributeString("scaleY", i.ScaleY.ToString());
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
// TODOUTMT没有给出关于房间物理的属性
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
xmlWriter.Close();
}
// --------------- 导出声音 ---------------
async Task ExportSounds()
{
Directory.CreateDirectory(projFolder + "/sound/audio");
await Task.Run(() => Parallel.ForEach(Data.Sounds, ExportSound));
}
void ExportSound(UndertaleSound sound)
{
// 保存声音GMX
var xmlWriter = XmlWriter.Create(projFolder + "/sound/" + sound.Name.Content + ".sound.gmx");
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("sound");
xmlWriter.WriteStartElement("kind");
// TODOUTMT没有给出kind属性这里通过文件扩展名进行推断
xmlWriter.WriteString(Path.GetExtension(sound.File.Content) == ".ogg" ? "3" : "0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("extension");
xmlWriter.WriteString(Path.GetExtension(sound.File.Content));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("origname");
xmlWriter.WriteString("sound\\audio\\" + sound.File.Content);
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("effects");
xmlWriter.WriteString(sound.Effects.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("volume");
xmlWriter.WriteString(sound.Volume.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("pan");
// TODOUTMT中未给出声道属性
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("bitRates");
// TODOUTMT中未给出比特率属性
xmlWriter.WriteString("192");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("sampleRates");
// TODOUTMT中未给出采样率属性
xmlWriter.WriteStartElement("sampleRate");
xmlWriter.WriteString("44100");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("types");
// TODOUTMT中未给出类型属性
xmlWriter.WriteStartElement("type");
xmlWriter.WriteString("1");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("bitDepths");
// TODOUTMT中未给出bitDepths属性
xmlWriter.WriteStartElement("bitDepth");
xmlWriter.WriteString("16");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("preload");
// TODOUTMT中未给出preload属性
xmlWriter.WriteString("-1");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("data");
xmlWriter.WriteString(Path.GetFileName(sound.File.Content));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("compressed");
// TODOUTMT中未给出compressed属性这里通过文件扩展名进行推断
xmlWriter.WriteString(Path.GetExtension(sound.File.Content) == ".ogg" ? "1" : "0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("streamed");
// TODOUTMT中未给出streamed属性这里通过文件扩展名进行推断
xmlWriter.WriteString(Path.GetExtension(sound.File.Content) == ".ogg" ? "1" : "0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("uncompressOnLoad");
// TODOUTMT中未给出uncompressOnLoad属性
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("audioGroup");
// TODOUTMT中给出了音频组但并不明确
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
xmlWriter.Close();
// 保存音频文件
if (sound.AudioFile != null)
File.WriteAllBytes(projFolder + "/sound/audio/" + sound.File.Content, sound.AudioFile.Data);
}
// --------------- 导出脚本 ---------------
async Task ExportScripts()
{
Directory.CreateDirectory(projFolder + "/scripts/");
await Task.Run(() => Parallel.ForEach(Data.Scripts, ExportScript));
}
void ExportScript(UndertaleScript script)
{
// 保存脚本GML
File.WriteAllText(projFolder + "/scripts/" + script.Name.Content + ".gml", (script.Code != null ? Decompiler.Decompile(script.Code, DECOMPILE_CONTEXT.Value) : ""));
}
// --------------- 导出字体 ---------------
async Task ExportFonts()
{
Directory.CreateDirectory(projFolder + "/fonts/");
await Task.Run(() => Parallel.ForEach(Data.Fonts, ExportFont));
}
void ExportFont(UndertaleFont font)
{
// 保存字体GMX
var xmlWriter = XmlWriter.Create(projFolder + "/fonts/" + font.Name.Content + ".font.gmx");
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("font");
xmlWriter.WriteStartElement("name");
xmlWriter.WriteString(font.Name.Content);
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("size");
xmlWriter.WriteString(font.EmSize.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("bold");
xmlWriter.WriteString(BoolToString(font.Bold));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("renderhq");
xmlWriter.WriteString("-1");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("italic");
xmlWriter.WriteString(BoolToString(font.Italic));
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("charset");
xmlWriter.WriteString(font.Charset.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("aa");
xmlWriter.WriteString(font.AntiAliasing.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("includeTTF");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("TTFName");
xmlWriter.WriteString("");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("texgroups");
xmlWriter.WriteStartElement("texgroup");
xmlWriter.WriteString("0");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("ranges");
xmlWriter.WriteStartElement("range0");
xmlWriter.WriteString(font.RangeStart.ToString() + "," + font.RangeEnd.ToString());
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("glyphs");
foreach (var i in font.Glyphs)
{
xmlWriter.WriteStartElement("glyph");
xmlWriter.WriteAttributeString("character", i.Character.ToString());
xmlWriter.WriteAttributeString("x", i.SourceX.ToString());
xmlWriter.WriteAttributeString("y", i.SourceY.ToString());
xmlWriter.WriteAttributeString("w", i.SourceWidth.ToString());
xmlWriter.WriteAttributeString("h", i.SourceHeight.ToString());
xmlWriter.WriteAttributeString("shift", i.Shift.ToString());
xmlWriter.WriteAttributeString("offset", i.Offset.ToString());
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("kerningPairs");
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("image");
xmlWriter.WriteString(font.Name.Content + ".png");
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
xmlWriter.Close();
// 保存字体图像
worker.ExportAsPNG(font.Texture, projFolder + "/fonts/" + font.Name.Content + ".png");
}
// --------------- 导出项目文件 ---------------
void ExportProjectFile()
{
// 保存字体GMX
var xmlWriter = XmlWriter.Create(projFolder + "Export_Project.project.gmx");
xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement("assets");
xmlWriter.WriteStartElement("sounds");
xmlWriter.WriteAttributeString("name", "sound");
foreach (var i in Data.Sounds)
{
xmlWriter.WriteStartElement("sound");
xmlWriter.WriteString("sound\\" + i.Name.Content);
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("sprites");
xmlWriter.WriteAttributeString("name", "sprites");
foreach (var i in Data.Sprites)
{
xmlWriter.WriteStartElement("sprite");
xmlWriter.WriteString("sprites\\" + i.Name.Content);
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("backgrounds");
xmlWriter.WriteAttributeString("name", "background");
foreach (var i in Data.Backgrounds)
{
xmlWriter.WriteStartElement("background");
xmlWriter.WriteString("backgrounds\\" + i.Name.Content);
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("scripts");
xmlWriter.WriteAttributeString("name", "scripts");
foreach (var i in Data.Scripts)
{
xmlWriter.WriteStartElement("script");
xmlWriter.WriteString("scripts\\" + i.Name.Content + ".gml");
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("fonts");
xmlWriter.WriteAttributeString("name", "fonts");
foreach (var i in Data.Fonts)
{
xmlWriter.WriteStartElement("font");
xmlWriter.WriteString("fonts\\" + i.Name.Content);
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("objects");
xmlWriter.WriteAttributeString("name", "objects");
foreach (var i in Data.GameObjects)
{
xmlWriter.WriteStartElement("object");
xmlWriter.WriteString("objects\\" + i.Name.Content);
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
xmlWriter.WriteStartElement("rooms");
xmlWriter.WriteAttributeString("name", "rooms");
foreach (var i in Data.Rooms)
{
xmlWriter.WriteStartElement("room");
xmlWriter.WriteString("rooms\\" + i.Name.Content);
xmlWriter.WriteEndElement();
}
xmlWriter.WriteEndElement();
xmlWriter.WriteEndElement();
xmlWriter.WriteEndDocument();
xmlWriter.Close();
}