public string GetDecompiledText(UndertaleCode code, GlobalDecompileContext context = null) { string output = "GetDecompiledText(): " + code?.ToString(); Console.Write(output); return(output); }
private void DisassemblyEditor_LostFocus(object sender, RoutedEventArgs e) { UndertaleCode code = this.DataContext as UndertaleCode; if (code == null) { return; // Probably loaded another data.win or something. } UndertaleData data = (Application.Current.MainWindow as MainWindow).Data; try { var instructions = Assembler.Assemble(DisassemblyEditor.Text, data); code.Replace(instructions); } catch (Exception ex) { MessageBox.Show(ex.ToString(), "Assembler error", MessageBoxButton.OK, MessageBoxImage.Error); return; } CurrentDisassembled = null; CurrentDecompiled = null; CurrentGraphed = null; DisassembleCode(code); DisassemblyView.Visibility = Visibility.Visible; DisassemblyEditor.Visibility = Visibility.Collapsed; }
public string GetDisassemblyText(UndertaleCode code) { string output = "GetDisassemblyText(): " + code?.ToString(); Console.Write(output); return(output); }
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e) { UndertaleCode code = this.DataContext as UndertaleCode; Directory.CreateDirectory(MainPath); Directory.CreateDirectory(TempPath); if (code == null) { return; } DecompiledSearchPanel.Close(); DisassemblySearchPanel.Close(); DecompiledEditor_LostFocus(sender, null); DisassemblyEditor_LostFocus(sender, null); if (DisassemblyTab.IsSelected && code != CurrentDisassembled) { DisassembleCode(code); } if (DecompiledTab.IsSelected && code != CurrentDecompiled) { DecompileCode(code); } if (GraphTab.IsSelected && code != CurrentGraphed) { GraphCode(code); } }
private void Details_Click(object sender, RoutedEventArgs e) { if (ObjectReference is null) { MessageBox.Show("This feature is very WIP, so expect it to be broken."); MainWindow mainWindow = Application.Current.MainWindow as MainWindow; if (mainWindow.Selected is null) { MainWindow.ShowError("Nothing currently selected! This is currently unsupported."); return; } else if (mainWindow.Selected is UndertaleGameObject gameObject) { // Generate the code entry UndertaleCode code = gameObject.EventHandlerFor(ObjectEventType, ObjectEventSubtype, mainWindow.Data.Strings, mainWindow.Data.Code, mainWindow.Data.CodeLocals); ObjectReference = code; } else { MainWindow.ShowError("Adding to non-objects is currently unsupported."); return; } } else { (Application.Current.MainWindow as MainWindow).ChangeSelection(ObjectReference); } }
public static string GenerateLocalVarDefinitions(this UndertaleCode code, IList <UndertaleVariable> vars, UndertaleCodeLocals locals) { if (code.WeirdLocalFlag) { return(""); } if (locals == null) { return("; Missing code locals- possibly due to unsupported bytecode version or brand new code entry.\n"); } StringBuilder sb = new StringBuilder(); var referenced = code.FindReferencedLocalVars(); if (locals.Name != code.Name) { throw new Exception("Name of the locals block does not match name of the code block"); } foreach (var arg in locals.Locals) { sb.Append(".localvar " + arg.Index + " " + arg.Name.Content); var refvar = referenced.Where((x) => x.Name == arg.Name && x.VarID == arg.Index).FirstOrDefault(); if (refvar != null) { sb.Append(" " + vars.IndexOf(refvar)); } sb.Append('\n'); } return(sb.ToString()); }
static void AddAsyncEvent(string path) { string eventSrc = File.ReadAllText(path); string name = "gml_Object_objControlerN_Other_75"; // Make a code entry. UndertaleCode codeEntry = new UndertaleCode { Name = Data.Strings.MakeString(name) }; Data.Code.Add(codeEntry); // Make a code locals entry. UndertaleCodeLocals locals = new UndertaleCodeLocals { Name = codeEntry.Name }; // Make a `var arguments;` entry. UndertaleCodeLocals.LocalVar argsLocal = new UndertaleCodeLocals.LocalVar { Name = Data.Strings.MakeString("arguments"), Index = 0 }; // Glue everything together. locals.Locals.Add(argsLocal); Data.CodeLocals.Add(locals); // Set code locals entry for the code entry. codeEntry.LocalsCount = 1; //codeEntry.GenerateLocalVarDefinitions(codeEntry.FindReferencedLocalVars(), locals); // fails here. // FINALLY compile our script. Data.Code.ByName(name).ReplaceGML(eventSrc, Data); // Add this code entry to Async System event in objControllerN... var obj = Data.GameObjects.ByName("objControlerN"); int OtherEventInd = 7; uint MethodNumber = 75; UndertaleGameObject.EventAction action = new UndertaleGameObject.EventAction { ActionName = codeEntry.Name, CodeId = codeEntry }; UndertaleGameObject.Event evnt = new UndertaleGameObject.Event { EventSubtype = MethodNumber }; evnt.Actions.Add(action); var eventList = obj.Events[OtherEventInd]; eventList.Add(evnt); }
public static void ReplaceInGML(string str1, string str2, UndertaleCode code, UndertaleData data) { string decomp = Decompiler.Decompile(code, new DecompileContext(data, false)); decomp = decomp.Replace(str1, str2); code.ReplaceGML(decomp, data); code.UpdateAddresses(); }
private static void IntroPatch(UndertaleData data) { Console.WriteLine("for skipping intros in normal saves on version 1.1.0.2 and up, see SETTINGS>GAME OPTIONS>Speedrun mode"); UndertaleCode ea = data.Code.ByName("gml_Script_start_new_game"); ReplaceInGML("loadroom = rm_intro", "if (global.CurrentFile == \"savedfile4.sav\")loadroom = rm_house;\n" + "else loadroom = rm_intro", ea, data); }
private async void GraphCode(UndertaleCode code) { if (code.DuplicateEntry) { GraphView.Source = null; CurrentGraphed = code; return; } LoaderDialog dialog = new LoaderDialog("Generating graph", "Generating graph, please wait..."); dialog.Owner = Window.GetWindow(this); Task t = Task.Run(() => { ImageSource image = null; try { code.UpdateAddresses(); var blocks = Decompiler.DecompileFlowGraph(code); string dot = Decompiler.ExportFlowGraph(blocks); try { var getStartProcessQuery = new GetStartProcessQuery(); var getProcessStartInfoQuery = new GetProcessStartInfoQuery(); var registerLayoutPluginCommand = new RegisterLayoutPluginCommand(getProcessStartInfoQuery, getStartProcessQuery); var wrapper = new GraphGeneration(getStartProcessQuery, getProcessStartInfoQuery, registerLayoutPluginCommand); byte[] output = wrapper.GenerateGraph(dot, Enums.GraphReturnType.Png); // TODO: Use SVG instead image = new ImageSourceConverter().ConvertFrom(output) as ImageSource; } catch (Exception e) { Debug.WriteLine(e.ToString()); if (MessageBox.Show("Unable to execute GraphViz: " + e.Message + "\nMake sure you have downloaded it and set the path in settings.\nDo you want to open the download page now?", "Graph generation failed", MessageBoxButton.YesNo, MessageBoxImage.Error) == MessageBoxResult.Yes) { Process.Start("https://graphviz.gitlab.io/_pages/Download/Download_windows.html"); } } } catch (Exception e) { Debug.WriteLine(e.ToString()); MessageBox.Show(e.Message, "Graph generation failed", MessageBoxButton.OK, MessageBoxImage.Error); } Dispatcher.Invoke(() => { GraphView.Source = image; CurrentGraphed = code; dialog.Hide(); }); }); dialog.ShowDialog(); await t; }
public void ReplaceTextInGML(UndertaleCode code, string keyword, string replacement, bool caseSensitive = false, bool isRegex = false, GlobalDecompileContext context = null) { EnsureDataLoaded(); string passBack = ""; string codeName = code.Name.Content; GlobalDecompileContext DECOMPILE_CONTEXT = context is null ? new(Data, false) : context; if (!Data.ToolInfo.ProfileMode) { try { passBack = GetPassBack((code != null ? Decompiler.Decompile(code, DECOMPILE_CONTEXT) : ""), keyword, replacement, caseSensitive, isRegex); code.ReplaceGML(passBack, Data); } catch (Exception exc) { throw new Exception("Error during GML code replacement:\n" + exc.ToString()); } } else { try { string path = Path.Combine(ProfilesFolder, Data.ToolInfo.CurrentMD5, "Temp", codeName + ".gml"); if (File.Exists(path)) { passBack = GetPassBack(File.ReadAllText(path), keyword, replacement, caseSensitive, isRegex); File.WriteAllText(path, passBack); code.ReplaceGML(passBack, Data); } else { try { if (context is null) { passBack = GetPassBack((code != null ? Decompiler.Decompile(code, new GlobalDecompileContext(Data, false)) : ""), keyword, replacement, caseSensitive, isRegex); } else { passBack = GetPassBack((code != null ? Decompiler.Decompile(code, context) : ""), keyword, replacement, caseSensitive, isRegex); } code.ReplaceGML(passBack, Data); } catch (Exception exc) { throw new Exception("Error during GML code replacement:\n" + exc.ToString()); } } } catch (Exception exc) { throw new Exception("Error during writing of GML code to profile:\n" + exc.ToString() + "\n\nCode:\n\n" + passBack); } } }
public static void DebugPatches(UndertaleData data) { UndertaleCode ee = data.Code.ByName("gml_Object_obj_menus_Create_0"); ReplaceInGML("1, 2], [\"\", 9],", "1, 2], [\"EXTRAS\", 1, 9], ", ee, data); ee.UpdateAddresses(); data.Code.ByName("gml_Object_obj_constant_Draw_64").AppendGML(RabbitRunCode.constBruhwer, data); }
public void ReplaceTextInGML(string codeName, string keyword, string replacement, bool case_sensitive = false, bool isRegex = false, GlobalDecompileContext context = null) { UndertaleCode code = Data.Code.ByName(codeName); if (code is null) { throw new ScriptException($"No code named \"{codeName}\" was found!"); } ReplaceTextInGML(code, keyword, replacement, case_sensitive, isRegex, context); }
static void AddScriptFromFile(string path) { string scriptSource = File.ReadAllText(path); string gmlWeirdName = "gml_Script_" + Path.GetFileNameWithoutExtension(path); // Make a code entry. UndertaleCode codeEntry = new UndertaleCode { Name = Data.Strings.MakeString(gmlWeirdName) }; Data.Code.Add(codeEntry); // Make a code locals entry. UndertaleCodeLocals locals = new UndertaleCodeLocals { Name = codeEntry.Name }; // Make a `var arguments;` entry. UndertaleCodeLocals.LocalVar argsLocal = new UndertaleCodeLocals.LocalVar { Name = Data.Strings.MakeString("arguments"), Index = 0 }; // Glue everything together. locals.Locals.Add(argsLocal); Data.CodeLocals.Add(locals); // Set code locals entry for the code entry. codeEntry.LocalsCount = 1; //codeEntry.GenerateLocalVarDefinitions(codeEntry.FindReferencedLocalVars(), locals); // fails here. // FINALLY compile our script. Data.Code.ByName(gmlWeirdName).ReplaceGML(scriptSource, Data); // ... and actually add it like a script... var scr = new UndertaleScript { Code = Data.Code.ByName(gmlWeirdName), Name = Data.Strings.MakeString(Path.GetFileNameWithoutExtension(path)) }; Data.Scripts.Add(scr); // ... oh, and don't forget to add a *function* reference. var funcentry = new UndertaleFunction { Name = Data.Strings.MakeString(Path.GetFileNameWithoutExtension(path)) }; Data.Functions.Add(funcentry); }
public string GetDisassemblyText(UndertaleCode code) { try { return(code != null?code.Disassemble(Data.Variables, Data.CodeLocals.For(code)) : ""); } catch (Exception e) { return("/*\nDISASSEMBLY FAILED!\n\n" + e.ToString() + "\n*/"); // Please don't } }
private void UpdateGettext(UndertaleCode gettextCode) { gettext = new Dictionary <string, int>(); foreach (var line in Decompiler.Decompile(gettextCode, new DecompileContext(null, true)).Replace("\r\n", "\n").Split('\n')) { Match m = Regex.Match(line, "^ds_map_add\\(global.text_data_en, \"(.*)\"@([0-9]+), \"(.*)\"@([0-9]+)\\)"); if (m.Success) { gettext.Add(m.Groups[1].Value, Int32.Parse(m.Groups[4].Value)); } } }
public string GetDecompiledText(UndertaleCode code, GlobalDecompileContext context = null) { GlobalDecompileContext DECOMPILE_CONTEXT = context is null ? new(Data, false) : context; try { return(code != null?Decompiler.Decompile(code, DECOMPILE_CONTEXT) : ""); } catch (Exception e) { return("/*\nDECOMPILER FAILED!\n\n" + e.ToString() + "\n*/"); } }
/// <inheritdoc/> public void ReplaceTextInGML(UndertaleCode code, string keyword, string replacement, bool caseSensitive = false, bool isRegex = false, GlobalDecompileContext context = null) { if (code == null) { throw new ArgumentNullException(nameof(code)); } EnsureDataLoaded(); string passBack = ""; GlobalDecompileContext decompileContext = context is null ? new(Data, false) : context; if (!Data.ToolInfo.ProfileMode) { try { passBack = GetPassBack(Decompiler.Decompile(code, decompileContext), keyword, replacement, caseSensitive, isRegex); code.ReplaceGML(passBack, Data); } catch (Exception exc) { throw new Exception("Error during GML code replacement:\n" + exc); } } else if (Data.ToolInfo.ProfileMode) { try { try { if (context is null) { passBack = GetPassBack(Decompiler.Decompile(code, new GlobalDecompileContext(Data, false)), keyword, replacement, caseSensitive, isRegex); } else { passBack = GetPassBack(Decompiler.Decompile(code, context), keyword, replacement, caseSensitive, isRegex); } code.ReplaceGML(passBack, Data); } catch (Exception exc) { throw new Exception("Error during GML code replacement:\n" + exc); } } catch (Exception exc) { throw new Exception("Error during writing of GML code to profile:\n" + exc + "\n\nCode:\n\n" + passBack); } } }
public string GetDecompiledText(string codeName) { UndertaleCode code = Data.Code.ByName(codeName); ThreadLocal <GlobalDecompileContext> DECOMPILE_CONTEXT = new ThreadLocal <GlobalDecompileContext>(() => new GlobalDecompileContext(Data, false)); try { return(code != null?Decompiler.Decompile(code, DECOMPILE_CONTEXT.Value) : ""); } catch (Exception e) { return("/*\nDECOMPILER FAILED!\n\n" + e.ToString() + "\n*/"); } }
public static string Disassemble(this UndertaleCode code, IList <UndertaleVariable> vars, UndertaleCodeLocals locals) { StringBuilder sb = new StringBuilder(); if (locals == null && !code.WeirdLocalFlag) { sb.Append("; WARNING: Missing code locals, possibly due to unsupported bytecode version or a brand new code entry.\n"); } else { sb.Append(code.GenerateLocalVarDefinitions(vars, locals)); } Dictionary <uint, string> fragments = new Dictionary <uint, string>(); foreach (var dup in code.Duplicates) { fragments.Add(dup.Offset / 4, (dup.Name?.Content ?? "<null>") + $" (locals={dup.LocalsCount}, argc={dup.ArgumentsCount})"); } List <uint> blocks = FindBlockAddresses(code); foreach (var inst in code.Instructions) { bool doNewline = true; if (fragments.TryGetValue(inst.Address, out string entry)) { sb.AppendLine(); sb.AppendLine($"> {entry}"); doNewline = false; } int ind = blocks.IndexOf(inst.Address); if (ind != -1) { if (doNewline) { sb.AppendLine(); } sb.AppendLine($":[{ind}]"); } sb.AppendLine(inst.ToString(code, blocks)); } sb.AppendLine(); sb.Append(":[end]"); return(sb.ToString()); }
private void DecompiledEditor_LostFocus(object sender, RoutedEventArgs e) { UndertaleCode code = this.DataContext as UndertaleCode; if (code == null) { return; // Probably loaded another data.win or something. } if (code.DuplicateEntry) { return; } UndertaleData data = (Application.Current.MainWindow as MainWindow).Data; CompileContext compileContext = Compiler.CompileGMLText(DecompiledEditor.Text, data, code); if (compileContext.HasError) { MessageBox.Show(compileContext.ResultError, "Compiler error", MessageBoxButton.OK, MessageBoxImage.Error); return; } if (!compileContext.SuccessfulCompile) { MessageBox.Show(compileContext.ResultAssembly, "Compile failed", MessageBoxButton.OK, MessageBoxImage.Error); return; } try { var instructions = Assembler.Assemble(compileContext.ResultAssembly, data); code.Replace(instructions); } catch (Exception ex) { MessageBox.Show(ex.ToString(), "Assembler error", MessageBoxButton.OK, MessageBoxImage.Error); return; } // Show new code, decompiled. CurrentDisassembled = null; CurrentDecompiled = null; CurrentGraphed = null; DecompileCode(code); DecompiledView.Visibility = Visibility.Visible; DecompiledEditor.Visibility = Visibility.Collapsed; }
public void ReplaceTextInGML(UndertaleCode code, string keyword, string replacement, bool case_sensitive = false, bool isRegex = false, GlobalDecompileContext context = null) { EnsureDataLoaded(); string passBack = ""; string codeName = code.Name.Content; GlobalDecompileContext DECOMPILE_CONTEXT = context is null ? new(Data, false) : context; if (Data.ToolInfo.ProfileMode == false || Data.GMS2_3) { try { passBack = GetPassBack((code != null ? Decompiler.Decompile(code, DECOMPILE_CONTEXT) : ""), keyword, replacement, case_sensitive, isRegex); code.ReplaceGML(passBack, Data); } catch (Exception exc) { throw new Exception("Error during GML code replacement:\n" + exc.ToString()); } } else if (Data.ToolInfo.ProfileMode && !Data.GMS2_3) { try { try { if (context is null) { passBack = GetPassBack((code != null ? Decompiler.Decompile(code, new GlobalDecompileContext(Data, false)) : ""), keyword, replacement, case_sensitive, isRegex); } else { passBack = GetPassBack((code != null ? Decompiler.Decompile(code, context) : ""), keyword, replacement, case_sensitive, isRegex); } code.ReplaceGML(passBack, Data); } catch (Exception exc) { throw new Exception("Error during GML code replacement:\n" + exc.ToString()); } } catch (Exception exc) { throw new Exception("Error during writing of GML code to profile:\n" + exc.ToString() + "\n\nCode:\n\n" + passBack); } } }
private void UpdateGettext(UndertaleCode gettextCode) { gettext = new Dictionary <string, int>(); string[] DecompilationOutput; if (!SettingsWindow.ProfileModeEnabled) { DecompilationOutput = Decompiler.Decompile(gettextCode, new DecompileContext(null, true)).Replace("\r\n", "\n").Split('\n'); } else { try { string path = Path.Combine(TempPath, gettextCode.Name.Content + ".gml"); if (File.Exists(path)) { DecompilationOutput = File.ReadAllText(path).Replace("\r\n", "\n").Split('\n'); } else { DecompilationOutput = Decompiler.Decompile(gettextCode, new DecompileContext(null, true)).Replace("\r\n", "\n").Split('\n'); } } catch { DecompilationOutput = Decompiler.Decompile(gettextCode, new DecompileContext(null, true)).Replace("\r\n", "\n").Split('\n'); } } foreach (var line in DecompilationOutput) { Match m = Regex.Match(line, "^ds_map_add\\(global.text_data_en, \"(.*)\"@([0-9]+), \"(.*)\"@([0-9]+)\\)"); if (m.Success) { try { gettext.Add(m.Groups[1].Value, Int32.Parse(m.Groups[4].Value)); } catch (ArgumentException) { MessageBox.Show("There is a duplicate key in textdata_en. This may cause errors in the comment display of text.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } catch { MessageBox.Show("Unknown error in textdata_en. This may cause errors in the comment display of text.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } } }
/// <summary> /// Replaces a code entry with text from another file. /// </summary> /// <param name="codeEntry">The code entry to replace</param> /// <param name="fileToReplace">File path which should replace the code entry.</param> private void ReplaceCodeEntryWithFile(string codeEntry, FileInfo fileToReplace) { UndertaleCode code = Data.Code.ByName(codeEntry); if (code == null) { Console.Error.WriteLine($"Data file does not contain a code entry named {codeEntry}!"); return; } if (Verbose) { Console.WriteLine("Replacing " + codeEntry); } ImportGMLString(codeEntry, File.ReadAllText(fileToReplace.FullName)); }
void SafeImport(string codeName, string gmlCode, bool IsGML, bool destroyASM = true, bool CheckDecompiler = false, bool throwOnError = false) { UndertaleCode code = Data.Code.ByName(codeName); try { if (IsGML) { code.ReplaceGML(gmlCode, Data); // Write to profile if necessary. string path = Path.Combine(ProfilesFolder, Data.ToolInfo.CurrentMD5, "Temp", codeName + ".gml"); if (File.Exists(path)) { File.WriteAllText(path, GetDecompiledText(code)); } } else { var instructions = Assembler.Assemble(gmlCode, Data); code.Replace(instructions); if (destroyASM) { NukeProfileGML(codeName); } } } catch (Exception ex) { if (!CheckDecompiler) { string errorText = $"Code import error at {(IsGML ? "GML" : "ASM")} code \"{codeName}\":\n\n{ex.Message}"; this.ShowWarning(errorText); if (throwOnError) { throw new ScriptException("*codeImportError*"); } } else { code.ReplaceGML("", Data); } } }
private void UserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { UndertaleCode code = this.DataContext as UndertaleCode; if (code == null) { return; } if (DisassemblyTab.IsSelected && code != CurrentDisassembled) { DisassembleCode(code); } if (DecompiledTab.IsSelected && code != CurrentDecompiled) { DecompileCode(code); } if (GraphTab.IsSelected && code != CurrentGraphed) { GraphCode(code); } }
public static List <uint> FindBlockAddresses(UndertaleCode code) { HashSet <uint> addresses = new HashSet <uint>(); if (code.Instructions.Count != 0) { addresses.Add(0); } foreach (var inst in code.Instructions) { switch (inst.Kind) { case UndertaleInstruction.Opcode.B: case UndertaleInstruction.Opcode.Bf: case UndertaleInstruction.Opcode.Bt: case UndertaleInstruction.Opcode.PushEnv: addresses.Add(inst.Address + 1); addresses.Add((uint)(inst.Address + inst.JumpOffset)); break; case UndertaleInstruction.Opcode.PopEnv: if (!inst.JumpOffsetPopenvExitMagic) { addresses.Add((uint)(inst.Address + inst.JumpOffset)); } break; case UndertaleInstruction.Opcode.Exit: case UndertaleInstruction.Opcode.Ret: addresses.Add(inst.Address + 1); break; } } List <uint> res = addresses.ToList(); res.Sort(); return(res); }
public static void ClockPatches(UndertaleData data) { UndertaleGameObject go = new UndertaleGameObject(); go.Name = data.Strings.MakeString("obj_clock"); go.Sprite = null; go.Persistent = true; go.CollisionShape = 0; go.Depth = -1; go.Awake = true; go.Visible = true; CreateEvent(RabbitRunCode.coinstants, data, go, EventType.Create, 0u); CreateEvent(RabbitRunCode.yote, data, go, EventType.Other, (uint)EventSubtypeOther.RoomEnd); CreateEvent(RabbitRunCode.rabstart, data, go, EventType.Other, (uint)EventSubtypeOther.RoomStart); CreateEvent(RabbitRunCode.constantDrawer, data, go, EventType.Draw, (uint)EventSubtypeDraw.DrawGUIEnd); CreateEvent(RabbitRunCode.constantStepper, data, go, EventType.Step, (uint)EventSubtypeStep.Step); CreateEvent(RabbitRunCode.doneThisShit, data, go, EventType.Other, (uint)EventSubtypeOther.User0); data.GameObjects.Add(go); data.Code.ByName("gml_Script_pausegame").AppendGML("instance_activate_object(obj_clock);", data); UndertaleCode c = data.Code.ByName("gml_Script_goto_mainmenu"); c.AppendGML(RabbitRunCode.gohomebyebye, data); UndertaleCode endingCutscene = data.Code.ByName("gml_RoomCC_rm_n4_760_Create"); ReplaceInGML("t_scene_info = [", @"t_scene_info = [[cutscene_checkiflist, obj_constant.flagList, 191, 1, 1],[cutscene_activate_userevent, obj_clock,0],", data.Code.ByName("gml_RoomCC_rm_n4_760_Create"), data); ReplaceInGML("t_scene_info = [", @"t_scene_info = [[cutscene_activate_userevent, obj_clock,0],", data.Code.ByName("gml_RoomCC_rm_n5_33_Create"), data); var house = data.Rooms.ByName("rm_init"); UndertaleRoom.GameObject rogo = new UndertaleRoom.GameObject { ObjectDefinition = go, InstanceID = 108990u, GMS2_2_2 = true }; house.GameObjects.Add(rogo); house.Layers.Single((layer) => layer.LayerName.Content == "Instances").InstancesData.Instances.Add(rogo); }
/// <summary> /// Dumps a code entry from a data file. /// </summary> /// <param name="codeEntry">The code entry that should get dumped</param> private void DumpCodeEntry(string codeEntry) { UndertaleCode code = Data.Code.ByName(codeEntry); if (code == null) { Console.Error.WriteLine($"Data file does not contain a code entry named {codeEntry}!"); return; } string directory = $"{Output.FullName}/CodeEntries/"; Directory.CreateDirectory(directory); if (Verbose) { Console.WriteLine($"Dumping {codeEntry}"); } File.WriteAllText($"{directory}/{codeEntry}.gml", GetDecompiledText(code)); }
void SafeImport(string codeName, string gmlCode, bool IsGML, bool destroyASM = true, bool CheckDecompiler = false, bool throwOnError = false) { UndertaleCode code = Data.Code.ByName(codeName); try { if (IsGML) { code.ReplaceGML(gmlCode, Data); } else { var instructions = Assembler.Assemble(gmlCode, Data); code.Replace(instructions); if (destroyASM) { NukeProfileGML(codeName); } } } catch (Exception ex) { if (!CheckDecompiler) { string errorText = $"Code import error at {(IsGML ? "GML" : "ASM")} code \"{codeName}\":\n\n{ex.Message}"; Console.Error.WriteLine(errorText); if (throwOnError) { throw new ScriptException("*codeImportError*"); } } else { code.ReplaceGML("", Data); } } }