diff --git a/ExportToGMS1Project.csx b/ExportToGMS1Project.csx index cd9269c..aa25435 100644 --- a/ExportToGMS1Project.csx +++ b/ExportToGMS1Project.csx @@ -10,12 +10,15 @@ using System.Reflection; using UndertaleModLib.Models; using UndertaleModLib.Util; using UndertaleModLib.Decompiler; +using Underanalyzer.Decompiler; +string GameName = Data.GeneralInfo.Name.ToString().Replace(@"""",""); //Name == "Project" -> Project int progress = 0; -string projFolder = GetFolder(FilePath) + "Export_Project" + Path.DirectorySeparatorChar; -TextureWorker worker = new TextureWorker(); -ThreadLocal DECOMPILE_CONTEXT = new ThreadLocal(() => new DecompileContext(Data, false)); +string projFolder = GetFolder(FilePath) + GameName + ".gmx" + Path.DirectorySeparatorChar; +TextureWorker worker = new(); +GlobalDecompileContext decompileContext = new(Data); 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)) { @@ -68,7 +71,7 @@ await ExportTimelines(); GenerateProjectFile(); // --------------- Export completed --------------- -worker.Cleanup(); +worker.Dispose(); // worker.Cleanup()? HideProgressBar(); ScriptMessage("Export Complete.\n\nLocation: " + projFolder); @@ -115,8 +118,7 @@ void ExportSprite(UndertaleSprite sprite) new XElement("For3D", "0"), new XElement("width", sprite.Width.ToString()), new XElement("height", sprite.Height.ToString()), - new XElement("frames"), - new XElement("bbox_right", sprite.MarginRight.ToString()) + new XElement("frames") ) ); @@ -134,22 +136,14 @@ void ExportSprite(UndertaleSprite sprite) } } - File.WriteAllText(projFolder + "/sprites/" + sprite.Name.Content + ".sprite.gmx", gmx.ToString()); + File.WriteAllText(projFolder + "/sprites/" + sprite.Name.Content + ".sprite.gmx", gmx.ToString() + eol); // Save sprite images for (int i = 0; i < sprite.Textures.Count; i++) { if (sprite.Textures[i]?.Texture != null) { - // 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(); + worker.ExportAsPNG(sprite.Textures[i].Texture, projFolder + "/sprites/images/" + sprite.Name.Content + "_" + i + ".png", null, true); } } } @@ -169,8 +163,8 @@ void ExportBackground(UndertaleBackground background) new XComment(gmxDeclaration), new XElement("background", new XElement("istileset", "-1"), - new XElement("tilewidth", background.Texture.BoundingWidth.ToString()), - new XElement("tileheight", background.Texture.BoundingHeight.ToString()), + new XElement("tilewidth", background.Texture == null ? "0" : background.Texture.BoundingWidth.ToString()), + new XElement("tileheight", background.Texture == null ? "0" : background.Texture.BoundingHeight.ToString()), new XElement("tilexoff", "0"), new XElement("tileyoff", "0"), new XElement("tilehsep", "0"), @@ -181,16 +175,17 @@ void ExportBackground(UndertaleBackground background) new XElement("TextureGroup0", "0") ), new XElement("For3D", "0"), - new XElement("width", background.Texture.BoundingWidth.ToString()), - new XElement("height", background.Texture.BoundingHeight.ToString()), + new XElement("width", background.Texture == null ? "0" : background.Texture.BoundingWidth.ToString()), + new XElement("height",background.Texture == null ? "0" : background.Texture.BoundingHeight.ToString()), new XElement("data", "images\\" + background.Name.Content + ".png") ) ); - File.WriteAllText(projFolder + "/background/" + background.Name.Content + ".background.gmx", gmx.ToString()); + File.WriteAllText(projFolder + "/background/" + background.Name.Content + ".background.gmx", gmx.ToString() + eol); // Save background images - worker.ExportAsPNG(background.Texture, projFolder + "/background/images/" + background.Name.Content + ".png"); + if (background.Texture != null) + worker.ExportAsPNG(background.Texture, projFolder + "/background/images/" + background.Name.Content + ".png"); } // --------------- Export Object --------------- async Task ExportGameObjects() @@ -213,10 +208,36 @@ void ExportGameObject(UndertaleGameObject gameObject) new XElement("persistent", BoolToString(gameObject.Persistent)), new XElement("parentName", gameObject.ParentId is null ? "" : gameObject.ParentId.Name.Content), new XElement("maskName", gameObject.TextureMaskId is null ? "" : 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 for (int i = 0; i < gameObject.Events.Count; i++) { @@ -249,6 +270,13 @@ void ExportGameObject(UndertaleGameObject gameObject) // Traversing the action list 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( new XElement("libid", k.LibID.ToString()), new XElement("id", k.ID.ToString()), @@ -257,7 +285,7 @@ void ExportGameObject(UndertaleGameObject gameObject) new XElement("isquestion", BoolToString(k.IsQuestion)), new XElement("useapplyto", BoolToString(k.UseApplyTo)), new XElement("exetype", k.ExeType.ToString()), - new XElement("functionname", k.ActionName.Content), + new XElement("functionname", k.ActionName != null ? k.ActionName.Content : ""), new XElement("codestring", ""), new XElement("whoName", "self"), new XElement("relative", BoolToString(k.Relative)), @@ -265,7 +293,7 @@ void ExportGameObject(UndertaleGameObject gameObject) new XElement("arguments", new XElement("argument", new XElement("kind", "1"), - new XElement("string", k.CodeId != null ? Decompiler.Decompile(k.CodeId, DECOMPILE_CONTEXT.Value) : "") + act_string ) ) ); @@ -273,12 +301,11 @@ void ExportGameObject(UndertaleGameObject gameObject) eventNode.Add(actionNode); eventsNode.Add(eventNode); - // TODO:Physics } } } - File.WriteAllText(projFolder + "/objects/" + gameObject.Name.Content + ".object.gmx", gmx.ToString()); + File.WriteAllText(projFolder + "/objects/" + gameObject.Name.Content + ".object.gmx", gmx.ToString() + eol); } // --------------- Export Room --------------- @@ -304,13 +331,29 @@ void ExportRoom(UndertaleRoom room) new XElement("speed", room.Speed.ToString()), new XElement("persistent", BoolToString(room.Persistent)), new XElement("colour", room.BackgroundColor.ToString()), - new XElement("code", room.CreationCodeId != null ? Decompiler.Decompile(room.CreationCodeId, DECOMPILE_CONTEXT.Value) : ""), + new XElement("showcolour", BoolToString(room.DrawBackgroundColor)), + new XElement("code", room.CreationCodeId != null ? new DecompileContext(decompileContext, room.CreationCodeId).DecompileToString() : ""), new XElement("enableViews", BoolToString(room.Flags.HasFlag(UndertaleRoom.RoomEntryFlags.EnableViews))), 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) + ) ) ); - // TODO:MakerSettings // Room backgrounds var backgroundsNode = new XElement("backgrounds"); @@ -322,8 +365,8 @@ void ExportRoom(UndertaleRoom room) new XAttribute("name", i.BackgroundDefinition is null ? "" : i.BackgroundDefinition.Name.Content), new XAttribute("x", i.X.ToString()), new XAttribute("y", i.Y.ToString()), - new XAttribute("htiled", i.TileX.ToString()), - new XAttribute("vtiled", i.TileY.ToString()), + new XAttribute("htiled", i.X.ToString()), + new XAttribute("vtiled", i.Y.ToString()), new XAttribute("hspeed", i.SpeedX.ToString()), new XAttribute("vspeed", i.SpeedY.ToString()), new XAttribute("stretch", "0") @@ -341,7 +384,8 @@ void ExportRoom(UndertaleRoom room) new XAttribute("objName", i.ObjectId is null ? "" : i.ObjectId.Name.Content), new XAttribute("xview", i.ViewX.ToString()), new XAttribute("yview", i.ViewY.ToString()), - new XAttribute("wview", i.ViewHeight.ToString()), + new XAttribute("wview", i.ViewWidth.ToString()), + new XAttribute("hview", i.ViewHeight.ToString()), new XAttribute("xport", i.PortX.ToString()), new XAttribute("yport", i.PortY.ToString()), new XAttribute("wport", i.PortWidth.ToString()), @@ -365,7 +409,7 @@ void ExportRoom(UndertaleRoom room) new XAttribute("y", i.Y.ToString()), new XAttribute("name", "inst_" + i.InstanceID.ToString("X")), new XAttribute("locked", "0"), - new XAttribute("code", i.CreationCode != null ? Decompiler.Decompile(i.CreationCode, DECOMPILE_CONTEXT.Value) : ""), + new XAttribute("code", i.CreationCode != null ? new DecompileContext(decompileContext, i.CreationCode).DecompileToString() : ""), new XAttribute("scaleX", i.ScaleX.ToString()), new XAttribute("scaleY", i.ScaleY.ToString()), new XAttribute("colour", i.Color.ToString()), @@ -399,9 +443,20 @@ void ExportRoom(UndertaleRoom room) } gmx.Element("room").Add(tilesNode); - // TODO:Room physics + //Room Physics + + gmx.Element("room").Add( + 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()); + File.WriteAllText(projFolder + "/rooms/" + room.Name.Content + ".room.gmx", gmx.ToString() + eol); } // --------------- Export Sound --------------- @@ -422,9 +477,13 @@ void ExportSound(UndertaleSound sound) new XElement("extension", Path.GetExtension(sound.File.Content)), new XElement("origname", "sound\\audio\\" + sound.File.Content), new XElement("effects", sound.Effects.ToString()), - new XElement("volume", sound.Volume.ToString()), + new XElement("volume", + new XElement("volume", sound.Volume.ToString()) + ), new XElement("pan", "0"), - new XElement("bitRates", "192"), + new XElement("bitRates", + new XElement("bitRate", "192") + ), new XElement("sampleRates", new XElement("sampleRate", "44100") ), @@ -443,7 +502,7 @@ void ExportSound(UndertaleSound sound) ) ); - File.WriteAllText(projFolder + "/sound/" + sound.Name.Content + ".sound.gmx", gmx.ToString()); + File.WriteAllText(projFolder + "/sound/" + sound.Name.Content + ".sound.gmx", gmx.ToString() + eol); // Save sound files if (sound.AudioFile != null) @@ -461,7 +520,7 @@ void ExportScript(UndertaleScript script) UpdateProgressBar(null, $"Exporting script: {script.Name.Content}", progress++, resourceNum); // Save GML files - File.WriteAllText(projFolder + "/scripts/" + script.Name.Content + ".gml", (script.Code != null ? Decompiler.Decompile(script.Code, DECOMPILE_CONTEXT.Value) : "")); + File.WriteAllText(projFolder + "/scripts/" + script.Name.Content + ".gml", script.Code != null ? new DecompileContext(decompileContext, script.Code).DecompileToString() : ""); } // --------------- Export Font --------------- @@ -513,7 +572,7 @@ void ExportFont(UndertaleFont font) glyphsNode.Add(glyphNode); } - File.WriteAllText(projFolder + "/fonts/" + font.Name.Content + ".font.gmx", gmx.ToString()); + File.WriteAllText(projFolder + "/fonts/" + font.Name.Content + ".font.gmx", gmx.ToString() + eol); // Save font textures worker.ExportAsPNG(font.Texture, projFolder + "/fonts/" + font.Name.Content + ".png"); @@ -550,7 +609,7 @@ void ExportPath(UndertalePath path) ); } - File.WriteAllText(projFolder + "/paths/" + path.Name.Content + ".path.gmx", gmx.ToString()); + File.WriteAllText(projFolder + "/paths/" + path.Name.Content + ".path.gmx", gmx.ToString() + eol); } // --------------- Export Timelines --------------- @@ -571,9 +630,9 @@ void ExportTimeline(UndertaleTimeline timeline) foreach (var i in timeline.Moments) { var entryNode = new XElement("entry"); - entryNode.Add(new XElement("step", i.Item1)); + entryNode.Add(new XElement("step", i.Step)); entryNode.Add(new XElement("event")); - foreach (var j in i.Item2) + foreach (var j in i.Event) { entryNode.Element("event").Add( new XElement("action", @@ -592,7 +651,7 @@ void ExportTimeline(UndertaleTimeline timeline) new XElement("arguments", new XElement("argument", new XElement("kind", "1"), - new XElement("string", j.CodeId != null ? Decompiler.Decompile(j.CodeId, DECOMPILE_CONTEXT.Value) : "") + new XElement("string", j.CodeId != null ? new DecompileContext(decompileContext, j.CodeId).DecompileToString() : "") ) ) ) @@ -601,7 +660,7 @@ void ExportTimeline(UndertaleTimeline timeline) gmx.Element("timeline").Add(entryNode); } - File.WriteAllText(projFolder + "/timelines/" + timeline.Name.Content + ".timeline.gmx", gmx.ToString()); + File.WriteAllText(projFolder + "/timelines/" + timeline.Name.Content + ".timeline.gmx", gmx.ToString() + eol); } @@ -626,7 +685,7 @@ void GenerateProjectFile() WriteIndexes(gmx.Element("assets"), "paths", "paths", Data.Paths, "path", "paths\\"); WriteIndexes(gmx.Element("assets"), "timelines", "timelines", Data.Timelines, "timeline", "timelines\\"); - File.WriteAllText(projFolder + "Export_Project.project.gmx", gmx.ToString()); + File.WriteAllText(projFolder + GameName + ".project.gmx", gmx.ToString() + eol); } void WriteIndexes(XElement rootNode, string elementName, string attributeName, IList dataList, string oneName, string resourcePath, string fileExtension = "") @@ -640,4 +699,4 @@ void WriteIndexes(XElement rootNode, string elementName, string attributeName resourcesNode.Add(resourceNode); } rootNode.Add(resourcesNode); -} +} \ No newline at end of file diff --git a/README.md b/README.md index 14d20dc..f4506b2 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,6 @@ 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. \ No newline at end of file +Currently compatible with gms1.4, will support gms2 in the future. + +Original repo: https://github.com/cubeww/UndertaleModTool-ExportToProjectScript \ No newline at end of file