Compare commits

..

No commits in common. "81e89b84fcea51f52d5d1b9799a7c920a79cf947" and "038a4c1917a1274bbac7f57d4ecf2f3d013d53bb" have entirely different histories.

2 changed files with 49 additions and 110 deletions

View file

@ -10,15 +10,12 @@ using System.Reflection;
using UndertaleModLib.Models; using UndertaleModLib.Models;
using UndertaleModLib.Util; using UndertaleModLib.Util;
using UndertaleModLib.Decompiler; using UndertaleModLib.Decompiler;
using Underanalyzer.Decompiler;
string GameName = Data.GeneralInfo.Name.ToString().Replace(@"""",""); //Name == "Project" -> Project
int progress = 0; int progress = 0;
string projFolder = GetFolder(FilePath) + GameName + ".gmx" + Path.DirectorySeparatorChar; string projFolder = GetFolder(FilePath) + "Export_Project" + Path.DirectorySeparatorChar;
TextureWorker worker = new(); TextureWorker worker = new TextureWorker();
GlobalDecompileContext decompileContext = new(Data); ThreadLocal<DecompileContext> DECOMPILE_CONTEXT = new ThreadLocal<DecompileContext>(() => new DecompileContext(Data, false));
string gmxDeclaration = "This Document is generated by GameMaker, if you edit it by hand then you do so at your own risk!"; string gmxDeclaration = "This Document is generated by GameMaker, if you edit it by hand then you do so at your own risk!";
string eol = "\n"; // Linux: "\n", Windows: "\r\n"
if (Directory.Exists(projFolder)) if (Directory.Exists(projFolder))
{ {
@ -71,7 +68,7 @@ await ExportTimelines();
GenerateProjectFile(); GenerateProjectFile();
// --------------- Export completed --------------- // --------------- Export completed ---------------
worker.Dispose(); // worker.Cleanup()? worker.Cleanup();
HideProgressBar(); HideProgressBar();
ScriptMessage("Export Complete.\n\nLocation: " + projFolder); ScriptMessage("Export Complete.\n\nLocation: " + projFolder);
@ -118,7 +115,8 @@ void ExportSprite(UndertaleSprite sprite)
new XElement("For3D", "0"), new XElement("For3D", "0"),
new XElement("width", sprite.Width.ToString()), new XElement("width", sprite.Width.ToString()),
new XElement("height", sprite.Height.ToString()), new XElement("height", sprite.Height.ToString()),
new XElement("frames") new XElement("frames"),
new XElement("bbox_right", sprite.MarginRight.ToString())
) )
); );
@ -136,14 +134,22 @@ void ExportSprite(UndertaleSprite sprite)
} }
} }
File.WriteAllText(projFolder + "/sprites/" + sprite.Name.Content + ".sprite.gmx", gmx.ToString() + eol); File.WriteAllText(projFolder + "/sprites/" + sprite.Name.Content + ".sprite.gmx", gmx.ToString());
// Save sprite images // Save sprite images
for (int i = 0; i < sprite.Textures.Count; i++) for (int i = 0; i < sprite.Textures.Count; i++)
{ {
if (sprite.Textures[i]?.Texture != null) if (sprite.Textures[i]?.Texture != null)
{ {
worker.ExportAsPNG(sprite.Textures[i].Texture, projFolder + "/sprites/images/" + sprite.Name.Content + "_" + i + ".png", null, true); // Fix sprite size
var bitmapNew = new Bitmap((int)sprite.Width, (int)sprite.Height);
var bitmapOrigin = worker.GetTextureFor(sprite.Textures[i].Texture, Path.GetFileNameWithoutExtension(projFolder + "/sprites/images/" + sprite.Name.Content + "_" + i + ".png"));
//worker.ExportAsPNG(sprite.Textures[i].Texture, projFolder + "/sprites/images/" + sprite.Name.Content + "_" + i + ".png");
var g = Graphics.FromImage(bitmapNew);
g.DrawImage(bitmapOrigin, (int)sprite.Textures[i].Texture.TargetX, (int)sprite.Textures[i].Texture.TargetY);
bitmapNew.Save(projFolder + "/sprites/images/" + sprite.Name.Content + "_" + i + ".png");
bitmapNew.Dispose();
bitmapOrigin.Dispose();
} }
} }
} }
@ -163,8 +169,8 @@ void ExportBackground(UndertaleBackground background)
new XComment(gmxDeclaration), new XComment(gmxDeclaration),
new XElement("background", new XElement("background",
new XElement("istileset", "-1"), new XElement("istileset", "-1"),
new XElement("tilewidth", background.Texture == null ? "0" : background.Texture.BoundingWidth.ToString()), new XElement("tilewidth", background.Texture.BoundingWidth.ToString()),
new XElement("tileheight", background.Texture == null ? "0" : background.Texture.BoundingHeight.ToString()), new XElement("tileheight", background.Texture.BoundingHeight.ToString()),
new XElement("tilexoff", "0"), new XElement("tilexoff", "0"),
new XElement("tileyoff", "0"), new XElement("tileyoff", "0"),
new XElement("tilehsep", "0"), new XElement("tilehsep", "0"),
@ -175,17 +181,16 @@ void ExportBackground(UndertaleBackground background)
new XElement("TextureGroup0", "0") new XElement("TextureGroup0", "0")
), ),
new XElement("For3D", "0"), new XElement("For3D", "0"),
new XElement("width", background.Texture == null ? "0" : background.Texture.BoundingWidth.ToString()), new XElement("width", background.Texture.BoundingWidth.ToString()),
new XElement("height",background.Texture == null ? "0" : background.Texture.BoundingHeight.ToString()), new XElement("height", background.Texture.BoundingHeight.ToString()),
new XElement("data", "images\\" + background.Name.Content + ".png") new XElement("data", "images\\" + background.Name.Content + ".png")
) )
); );
File.WriteAllText(projFolder + "/background/" + background.Name.Content + ".background.gmx", gmx.ToString() + eol); File.WriteAllText(projFolder + "/background/" + background.Name.Content + ".background.gmx", gmx.ToString());
// Save background images // Save background images
if (background.Texture != null) worker.ExportAsPNG(background.Texture, projFolder + "/background/images/" + background.Name.Content + ".png");
worker.ExportAsPNG(background.Texture, projFolder + "/background/images/" + background.Name.Content + ".png");
} }
// --------------- Export Object --------------- // --------------- Export Object ---------------
async Task ExportGameObjects() async Task ExportGameObjects()
@ -208,36 +213,10 @@ void ExportGameObject(UndertaleGameObject gameObject)
new XElement("persistent", BoolToString(gameObject.Persistent)), new XElement("persistent", BoolToString(gameObject.Persistent)),
new XElement("parentName", gameObject.ParentId is null ? "<undefined>" : gameObject.ParentId.Name.Content), new XElement("parentName", gameObject.ParentId is null ? "<undefined>" : gameObject.ParentId.Name.Content),
new XElement("maskName", gameObject.TextureMaskId is null ? "<undefined>" : gameObject.TextureMaskId.Name.Content), new XElement("maskName", gameObject.TextureMaskId is null ? "<undefined>" : gameObject.TextureMaskId.Name.Content),
new XElement("events"), new XElement("events")
//Physics
new XElement("PhysicsObject", BoolToString(gameObject.UsesPhysics)),
new XElement("PhysicsObjectSensor", BoolToString(gameObject.IsSensor)),
new XElement("PhysicsObjectShape", (uint)gameObject.CollisionShape),
new XElement("PhysicsObjectDensity", gameObject.Density),
new XElement("PhysicsObjectRestitution", gameObject.Restitution),
new XElement("PhysicsObjectGroup", gameObject.Group),
new XElement("PhysicsObjectLinearDamping", gameObject.LinearDamping),
new XElement("PhysicsObjectAngularDamping", gameObject.AngularDamping),
new XElement("PhysicsObjectFriction", gameObject.Friction),
new XElement("PhysicsObjectAwake", BoolToString(gameObject.Awake)),
new XElement("PhysicsObjectKinematic", BoolToString(gameObject.Kinematic)),
new XElement("PhysicsShapePoints")
) )
); );
// Loop through PhysicsShapePoints List
for (int _point = 0; _point < gameObject.PhysicsVertices.Count; _point++)
{
var _x = gameObject.PhysicsVertices[_point].X;
var _y = gameObject.PhysicsVertices[_point].Y;
var physicsPointsNode = gmx.Element("object").Element("PhysicsShapePoints");
physicsPointsNode.Add(new XElement("points",_x.ToString() + "," + _y.ToString()));
}
// Traversing the event type list // Traversing the event type list
for (int i = 0; i < gameObject.Events.Count; i++) for (int i = 0; i < gameObject.Events.Count; i++)
{ {
@ -270,13 +249,6 @@ void ExportGameObject(UndertaleGameObject gameObject)
// Traversing the action list // Traversing the action list
foreach (var k in j.Actions) foreach (var k in j.Actions)
{ {
DecompileContext dec_context = new(decompileContext, k.CodeId, Data.ToolInfo.DecompilerSettings);
XElement act_string = null;
try {
act_string = new XElement("string", (k.CodeId != null && dec_context != null) ? dec_context.DecompileToString() : "");
} catch (DecompilerException) {
act_string = new XElement("string", "");
}
actionNode.Add( actionNode.Add(
new XElement("libid", k.LibID.ToString()), new XElement("libid", k.LibID.ToString()),
new XElement("id", k.ID.ToString()), new XElement("id", k.ID.ToString()),
@ -285,7 +257,7 @@ void ExportGameObject(UndertaleGameObject gameObject)
new XElement("isquestion", BoolToString(k.IsQuestion)), new XElement("isquestion", BoolToString(k.IsQuestion)),
new XElement("useapplyto", BoolToString(k.UseApplyTo)), new XElement("useapplyto", BoolToString(k.UseApplyTo)),
new XElement("exetype", k.ExeType.ToString()), new XElement("exetype", k.ExeType.ToString()),
new XElement("functionname", k.ActionName != null ? k.ActionName.Content : ""), new XElement("functionname", k.ActionName.Content),
new XElement("codestring", ""), new XElement("codestring", ""),
new XElement("whoName", "self"), new XElement("whoName", "self"),
new XElement("relative", BoolToString(k.Relative)), new XElement("relative", BoolToString(k.Relative)),
@ -293,7 +265,7 @@ void ExportGameObject(UndertaleGameObject gameObject)
new XElement("arguments", new XElement("arguments",
new XElement("argument", new XElement("argument",
new XElement("kind", "1"), new XElement("kind", "1"),
act_string new XElement("string", k.CodeId != null ? Decompiler.Decompile(k.CodeId, DECOMPILE_CONTEXT.Value) : "")
) )
) )
); );
@ -301,11 +273,12 @@ void ExportGameObject(UndertaleGameObject gameObject)
eventNode.Add(actionNode); eventNode.Add(actionNode);
eventsNode.Add(eventNode); eventsNode.Add(eventNode);
// TODOPhysics
} }
} }
} }
File.WriteAllText(projFolder + "/objects/" + gameObject.Name.Content + ".object.gmx", gmx.ToString() + eol); File.WriteAllText(projFolder + "/objects/" + gameObject.Name.Content + ".object.gmx", gmx.ToString());
} }
// --------------- Export Room --------------- // --------------- Export Room ---------------
@ -331,29 +304,13 @@ void ExportRoom(UndertaleRoom room)
new XElement("speed", room.Speed.ToString()), new XElement("speed", room.Speed.ToString()),
new XElement("persistent", BoolToString(room.Persistent)), new XElement("persistent", BoolToString(room.Persistent)),
new XElement("colour", room.BackgroundColor.ToString()), new XElement("colour", room.BackgroundColor.ToString()),
new XElement("showcolour", BoolToString(room.DrawBackgroundColor)), new XElement("code", room.CreationCodeId != null ? Decompiler.Decompile(room.CreationCodeId, DECOMPILE_CONTEXT.Value) : ""),
new XElement("code", room.CreationCodeId != null ? new DecompileContext(decompileContext, room.CreationCodeId).DecompileToString() : ""),
new XElement("enableViews", BoolToString(room.Flags.HasFlag(UndertaleRoom.RoomEntryFlags.EnableViews))), new XElement("enableViews", BoolToString(room.Flags.HasFlag(UndertaleRoom.RoomEntryFlags.EnableViews))),
new XElement("clearViewBackground", BoolToString(room.Flags.HasFlag(UndertaleRoom.RoomEntryFlags.ShowColor))), new XElement("clearViewBackground", BoolToString(room.Flags.HasFlag(UndertaleRoom.RoomEntryFlags.ShowColor))),
//new XElement("clearDisplayBuffer", BoolToString(room.Flags.HasFlag(UndertaleRoom.RoomEntryFlags.ClearDisplayBuffer))), new XElement("clearDisplayBuffer", BoolToString(room.Flags.HasFlag(UndertaleRoom.RoomEntryFlags.ClearDisplayBuffer)))
new XElement("makerSettings",
new XElement("isSet", 0),
new XElement("w", 0),
new XElement("h", 0),
new XElement("showGrid", 0),
new XElement("showObjects", 0),
new XElement("showTiles", 0),
new XElement("showBackgrounds", 0),
new XElement("showForegrounds", 0),
new XElement("showViews", 0),
new XElement("deleteUnderlyingObj", 0),
new XElement("deleteUnderlyingTiles", 0),
new XElement("page", 0),
new XElement("xoffset", 0),
new XElement("yoffset", 0)
)
) )
); );
// TODOMakerSettings
// Room backgrounds // Room backgrounds
var backgroundsNode = new XElement("backgrounds"); var backgroundsNode = new XElement("backgrounds");
@ -365,8 +322,8 @@ void ExportRoom(UndertaleRoom room)
new XAttribute("name", i.BackgroundDefinition is null ? "" : i.BackgroundDefinition.Name.Content), new XAttribute("name", i.BackgroundDefinition is null ? "" : i.BackgroundDefinition.Name.Content),
new XAttribute("x", i.X.ToString()), new XAttribute("x", i.X.ToString()),
new XAttribute("y", i.Y.ToString()), new XAttribute("y", i.Y.ToString()),
new XAttribute("htiled", i.X.ToString()), new XAttribute("htiled", i.TileX.ToString()),
new XAttribute("vtiled", i.Y.ToString()), new XAttribute("vtiled", i.TileY.ToString()),
new XAttribute("hspeed", i.SpeedX.ToString()), new XAttribute("hspeed", i.SpeedX.ToString()),
new XAttribute("vspeed", i.SpeedY.ToString()), new XAttribute("vspeed", i.SpeedY.ToString()),
new XAttribute("stretch", "0") new XAttribute("stretch", "0")
@ -384,8 +341,7 @@ void ExportRoom(UndertaleRoom room)
new XAttribute("objName", i.ObjectId is null ? "<undefined>" : i.ObjectId.Name.Content), new XAttribute("objName", i.ObjectId is null ? "<undefined>" : i.ObjectId.Name.Content),
new XAttribute("xview", i.ViewX.ToString()), new XAttribute("xview", i.ViewX.ToString()),
new XAttribute("yview", i.ViewY.ToString()), new XAttribute("yview", i.ViewY.ToString()),
new XAttribute("wview", i.ViewWidth.ToString()), new XAttribute("wview", i.ViewHeight.ToString()),
new XAttribute("hview", i.ViewHeight.ToString()),
new XAttribute("xport", i.PortX.ToString()), new XAttribute("xport", i.PortX.ToString()),
new XAttribute("yport", i.PortY.ToString()), new XAttribute("yport", i.PortY.ToString()),
new XAttribute("wport", i.PortWidth.ToString()), new XAttribute("wport", i.PortWidth.ToString()),
@ -409,7 +365,7 @@ void ExportRoom(UndertaleRoom room)
new XAttribute("y", i.Y.ToString()), new XAttribute("y", i.Y.ToString()),
new XAttribute("name", "inst_" + i.InstanceID.ToString("X")), new XAttribute("name", "inst_" + i.InstanceID.ToString("X")),
new XAttribute("locked", "0"), new XAttribute("locked", "0"),
new XAttribute("code", i.CreationCode != null ? new DecompileContext(decompileContext, i.CreationCode).DecompileToString() : ""), new XAttribute("code", i.CreationCode != null ? Decompiler.Decompile(i.CreationCode, DECOMPILE_CONTEXT.Value) : ""),
new XAttribute("scaleX", i.ScaleX.ToString()), new XAttribute("scaleX", i.ScaleX.ToString()),
new XAttribute("scaleY", i.ScaleY.ToString()), new XAttribute("scaleY", i.ScaleY.ToString()),
new XAttribute("colour", i.Color.ToString()), new XAttribute("colour", i.Color.ToString()),
@ -443,20 +399,9 @@ void ExportRoom(UndertaleRoom room)
} }
gmx.Element("room").Add(tilesNode); gmx.Element("room").Add(tilesNode);
//Room Physics // TODORoom physics
gmx.Element("room").Add( File.WriteAllText(projFolder + "/rooms/" + room.Name.Content + ".room.gmx", gmx.ToString());
new XElement("PhysicsWorld", room.World),
new XElement("PhysicsWorldTop", room.Top),
new XElement("PhysicsWorldLeft", room.Left),
new XElement("PhysicsWorldRight", room.Right),
new XElement("PhysicsWorldBottom", room.Bottom),
new XElement("PhysicsWorldGravityX", room.GravityX),
new XElement("PhysicsWorldGravityY", room.GravityY),
new XElement("PhysicsWorldPixToMeters", room.MetersPerPixel)
);
File.WriteAllText(projFolder + "/rooms/" + room.Name.Content + ".room.gmx", gmx.ToString() + eol);
} }
// --------------- Export Sound --------------- // --------------- Export Sound ---------------
@ -477,13 +422,9 @@ void ExportSound(UndertaleSound sound)
new XElement("extension", Path.GetExtension(sound.File.Content)), new XElement("extension", Path.GetExtension(sound.File.Content)),
new XElement("origname", "sound\\audio\\" + sound.File.Content), new XElement("origname", "sound\\audio\\" + sound.File.Content),
new XElement("effects", sound.Effects.ToString()), new XElement("effects", sound.Effects.ToString()),
new XElement("volume", new XElement("volume", sound.Volume.ToString()),
new XElement("volume", sound.Volume.ToString())
),
new XElement("pan", "0"), new XElement("pan", "0"),
new XElement("bitRates", new XElement("bitRates", "192"),
new XElement("bitRate", "192")
),
new XElement("sampleRates", new XElement("sampleRates",
new XElement("sampleRate", "44100") new XElement("sampleRate", "44100")
), ),
@ -502,7 +443,7 @@ void ExportSound(UndertaleSound sound)
) )
); );
File.WriteAllText(projFolder + "/sound/" + sound.Name.Content + ".sound.gmx", gmx.ToString() + eol); File.WriteAllText(projFolder + "/sound/" + sound.Name.Content + ".sound.gmx", gmx.ToString());
// Save sound files // Save sound files
if (sound.AudioFile != null) if (sound.AudioFile != null)
@ -520,7 +461,7 @@ void ExportScript(UndertaleScript script)
UpdateProgressBar(null, $"Exporting script: {script.Name.Content}", progress++, resourceNum); UpdateProgressBar(null, $"Exporting script: {script.Name.Content}", progress++, resourceNum);
// Save GML files // Save GML files
File.WriteAllText(projFolder + "/scripts/" + script.Name.Content + ".gml", script.Code != null ? new DecompileContext(decompileContext, script.Code).DecompileToString() : ""); File.WriteAllText(projFolder + "/scripts/" + script.Name.Content + ".gml", (script.Code != null ? Decompiler.Decompile(script.Code, DECOMPILE_CONTEXT.Value) : ""));
} }
// --------------- Export Font --------------- // --------------- Export Font ---------------
@ -572,7 +513,7 @@ void ExportFont(UndertaleFont font)
glyphsNode.Add(glyphNode); glyphsNode.Add(glyphNode);
} }
File.WriteAllText(projFolder + "/fonts/" + font.Name.Content + ".font.gmx", gmx.ToString() + eol); File.WriteAllText(projFolder + "/fonts/" + font.Name.Content + ".font.gmx", gmx.ToString());
// Save font textures // Save font textures
worker.ExportAsPNG(font.Texture, projFolder + "/fonts/" + font.Name.Content + ".png"); worker.ExportAsPNG(font.Texture, projFolder + "/fonts/" + font.Name.Content + ".png");
@ -609,7 +550,7 @@ void ExportPath(UndertalePath path)
); );
} }
File.WriteAllText(projFolder + "/paths/" + path.Name.Content + ".path.gmx", gmx.ToString() + eol); File.WriteAllText(projFolder + "/paths/" + path.Name.Content + ".path.gmx", gmx.ToString());
} }
// --------------- Export Timelines --------------- // --------------- Export Timelines ---------------
@ -630,9 +571,9 @@ void ExportTimeline(UndertaleTimeline timeline)
foreach (var i in timeline.Moments) foreach (var i in timeline.Moments)
{ {
var entryNode = new XElement("entry"); var entryNode = new XElement("entry");
entryNode.Add(new XElement("step", i.Step)); entryNode.Add(new XElement("step", i.Item1));
entryNode.Add(new XElement("event")); entryNode.Add(new XElement("event"));
foreach (var j in i.Event) foreach (var j in i.Item2)
{ {
entryNode.Element("event").Add( entryNode.Element("event").Add(
new XElement("action", new XElement("action",
@ -651,7 +592,7 @@ void ExportTimeline(UndertaleTimeline timeline)
new XElement("arguments", new XElement("arguments",
new XElement("argument", new XElement("argument",
new XElement("kind", "1"), new XElement("kind", "1"),
new XElement("string", j.CodeId != null ? new DecompileContext(decompileContext, j.CodeId).DecompileToString() : "") new XElement("string", j.CodeId != null ? Decompiler.Decompile(j.CodeId, DECOMPILE_CONTEXT.Value) : "")
) )
) )
) )
@ -660,7 +601,7 @@ void ExportTimeline(UndertaleTimeline timeline)
gmx.Element("timeline").Add(entryNode); gmx.Element("timeline").Add(entryNode);
} }
File.WriteAllText(projFolder + "/timelines/" + timeline.Name.Content + ".timeline.gmx", gmx.ToString() + eol); File.WriteAllText(projFolder + "/timelines/" + timeline.Name.Content + ".timeline.gmx", gmx.ToString());
} }
@ -685,7 +626,7 @@ void GenerateProjectFile()
WriteIndexes<UndertalePath>(gmx.Element("assets"), "paths", "paths", Data.Paths, "path", "paths\\"); WriteIndexes<UndertalePath>(gmx.Element("assets"), "paths", "paths", Data.Paths, "path", "paths\\");
WriteIndexes<UndertaleTimeline>(gmx.Element("assets"), "timelines", "timelines", Data.Timelines, "timeline", "timelines\\"); WriteIndexes<UndertaleTimeline>(gmx.Element("assets"), "timelines", "timelines", Data.Timelines, "timeline", "timelines\\");
File.WriteAllText(projFolder + GameName + ".project.gmx", gmx.ToString() + eol); File.WriteAllText(projFolder + "Export_Project.project.gmx", gmx.ToString());
} }
void WriteIndexes<T>(XElement rootNode, string elementName, string attributeName, IList<T> dataList, string oneName, string resourcePath, string fileExtension = "") void WriteIndexes<T>(XElement rootNode, string elementName, string attributeName, IList<T> dataList, string oneName, string resourcePath, string fileExtension = "")

View file

@ -3,5 +3,3 @@
This is a script for UndertaleModTool, which can export game files as project files of GameMaker Studio. This is a script for UndertaleModTool, which can export game files as project files of GameMaker Studio.
Currently compatible with gms1.4, will support gms2 in the future. Currently compatible with gms1.4, will support gms2 in the future.
Original repo: https://github.com/cubeww/UndertaleModTool-ExportToProjectScript