예제 #1
0
        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();
        }
예제 #2
0
        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;
        }
예제 #3
0
        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);
        }
예제 #4
0
        private void DisassembleCode(UndertaleCode code)
        {
            code.UpdateAddresses();

            string text;

            if (code.DuplicateEntry)
            {
                DisassemblyEditor.IsReadOnly = true;
                text = "; Duplicate code entry; cannot edit here.";
            }
            else
            {
                DisassemblyEditor.IsReadOnly = false;

                var data = (Application.Current.MainWindow as MainWindow).Data;
                text = code.Disassemble(data.Variables, data.CodeLocals.For(code));
            }

            DisassemblyEditor.Text = text;

            CurrentDisassembled = code;
            DisassemblyChanged  = false;
        }
예제 #5
0
        private void DisassembleCode(UndertaleCode code)
        {
            code.UpdateAddresses();

            FlowDocument document = new FlowDocument();

            document.PagePadding = new Thickness(0);
            document.PageWidth   = 2048; // Speed-up.
            document.FontFamily  = new FontFamily("Lucida Console");
            Paragraph par = new Paragraph();

            par.Margin = new Thickness(0);

            if (code.Instructions.Count > 5000)
            {
                // Disable syntax highlighting. Loading it can take a few MINUTES on large scripts.
                var      data  = (Application.Current.MainWindow as MainWindow).Data;
                string[] split = code.Disassemble(data.Variables, data.CodeLocals.For(code)).Split('\n');

                for (var i = 0; i < split.Length; i++)
                { // Makes it possible to select text.
                    if (i > 0 && (i % 100) == 0)
                    {
                        document.Blocks.Add(par);
                        par        = new Paragraph();
                        par.Margin = new Thickness(0);
                    }

                    par.Inlines.Add(split[i] + (split.Length > i + 1 && ((i + 1) % 100) != 0 ? "\n" : ""));
                }
            }
            else
            {
                Brush addressBrush = new SolidColorBrush(Color.FromRgb(50, 50, 50));
                Brush opcodeBrush  = new SolidColorBrush(Color.FromRgb(0, 100, 0));
                Brush argBrush     = new SolidColorBrush(Color.FromRgb(0, 0, 150));
                Brush typeBrush    = new SolidColorBrush(Color.FromRgb(0, 0, 50));
                var   data         = (Application.Current.MainWindow as MainWindow).Data;
                par.Inlines.Add(new Run(code.GenerateLocalVarDefinitions(data.Variables, data.CodeLocals.For(code)))
                {
                    Foreground = addressBrush
                });
                foreach (var instr in code.Instructions)
                {
                    par.Inlines.Add(new Run(instr.Address.ToString("D5") + ": ")
                    {
                        Foreground = addressBrush
                    });
                    par.Inlines.Add(new Run(instr.Kind.ToString().ToLower())
                    {
                        Foreground = opcodeBrush, FontWeight = FontWeights.Bold
                    });

                    switch (UndertaleInstruction.GetInstructionType(instr.Kind))
                    {
                    case UndertaleInstruction.InstructionType.SingleTypeInstruction:
                        par.Inlines.Add(new Run("." + instr.Type1.ToOpcodeParam())
                        {
                            Foreground = typeBrush
                        });

                        if (instr.Kind == UndertaleInstruction.Opcode.Dup || instr.Kind == UndertaleInstruction.Opcode.CallV)
                        {
                            par.Inlines.Add(new Run(" "));
                            par.Inlines.Add(new Run(instr.Extra.ToString())
                            {
                                Foreground = argBrush
                            });
                        }
                        break;

                    case UndertaleInstruction.InstructionType.DoubleTypeInstruction:
                        par.Inlines.Add(new Run("." + instr.Type1.ToOpcodeParam())
                        {
                            Foreground = typeBrush
                        });
                        par.Inlines.Add(new Run("." + instr.Type2.ToOpcodeParam())
                        {
                            Foreground = typeBrush
                        });
                        break;

                    case UndertaleInstruction.InstructionType.ComparisonInstruction:
                        par.Inlines.Add(new Run("." + instr.Type1.ToOpcodeParam())
                        {
                            Foreground = typeBrush
                        });
                        par.Inlines.Add(new Run("." + instr.Type2.ToOpcodeParam())
                        {
                            Foreground = typeBrush
                        });
                        par.Inlines.Add(new Run(" "));
                        par.Inlines.Add(new Run(instr.ComparisonKind.ToString())
                        {
                            Foreground = opcodeBrush
                        });
                        break;

                    case UndertaleInstruction.InstructionType.GotoInstruction:
                        par.Inlines.Add(new Run(" "));
                        string tgt = (instr.Address + instr.JumpOffset).ToString("D5");
                        if (instr.Address + instr.JumpOffset == code.Length / 4)
                        {
                            tgt = "func_end";
                        }
                        if (instr.JumpOffsetPopenvExitMagic)
                        {
                            tgt = "[drop]";
                        }
                        par.Inlines.Add(new Run(tgt)
                        {
                            Foreground = argBrush, ToolTip = "$" + instr.JumpOffset.ToString("+#;-#;0")
                        });
                        break;

                    case UndertaleInstruction.InstructionType.PopInstruction:
                        par.Inlines.Add(new Run("." + instr.Type1.ToOpcodeParam())
                        {
                            Foreground = typeBrush
                        });
                        par.Inlines.Add(new Run("." + instr.Type2.ToOpcodeParam())
                        {
                            Foreground = typeBrush
                        });
                        par.Inlines.Add(new Run(" "));
                        if (instr.Type1 == UndertaleInstruction.DataType.Int16)
                        {
                            // Special scenario - the swap instruction
                            // TODO: Figure out the proper syntax, see #129
                            Run runType = new Run(instr.SwapExtra.ToString().ToLower())
                            {
                                Foreground = argBrush
                            };
                            par.Inlines.Add(runType);
                        }
                        else
                        {
                            if (instr.Type1 == UndertaleInstruction.DataType.Variable && instr.TypeInst != UndertaleInstruction.InstanceType.Undefined)
                            {
                                par.Inlines.Add(new Run(instr.TypeInst.ToString().ToLower())
                                {
                                    Foreground = typeBrush
                                });
                                par.Inlines.Add(new Run("."));
                            }

                            Run runDest = new Run(instr.Destination.ToString())
                            {
                                Foreground = argBrush, Cursor = Cursors.Hand
                            };
                            runDest.MouseDown += (sender, e) =>
                            {
                                (Application.Current.MainWindow as MainWindow).ChangeSelection(instr.Destination);
                            };
                            par.Inlines.Add(runDest);
                        }
                        break;

                    case UndertaleInstruction.InstructionType.PushInstruction:
                        par.Inlines.Add(new Run("." + instr.Type1.ToOpcodeParam())
                        {
                            Foreground = typeBrush
                        });
                        par.Inlines.Add(new Run(" "));
                        if (instr.Type1 == UndertaleInstruction.DataType.Variable && instr.TypeInst != UndertaleInstruction.InstanceType.Undefined)
                        {
                            par.Inlines.Add(new Run(instr.TypeInst.ToString().ToLower())
                            {
                                Foreground = typeBrush
                            });
                            par.Inlines.Add(new Run("."));
                        }
                        Run valueRun = new Run((instr.Value as IFormattable)?.ToString(null, CultureInfo.InvariantCulture) ?? instr.Value.ToString())
                        {
                            Foreground = argBrush, Cursor = (instr.Value is UndertaleObject || instr.Value is UndertaleResourceRef) ? Cursors.Hand : Cursors.Arrow
                        };
                        if (instr.Value is UndertaleResourceRef)
                        {
                            valueRun.MouseDown += (sender, e) =>
                            {
                                (Application.Current.MainWindow as MainWindow).ChangeSelection((instr.Value as UndertaleResourceRef).Resource);
                            };
                        }
                        else if (instr.Value is UndertaleObject)
                        {
                            valueRun.MouseDown += (sender, e) =>
                            {
                                (Application.Current.MainWindow as MainWindow).ChangeSelection(instr.Value);
                            };
                        }
                        par.Inlines.Add(valueRun);
                        break;

                    case UndertaleInstruction.InstructionType.CallInstruction:
                        par.Inlines.Add(new Run("." + instr.Type1.ToOpcodeParam())
                        {
                            Foreground = typeBrush
                        });
                        par.Inlines.Add(new Run(" "));
                        par.Inlines.Add(new Run(instr.Function.ToString())
                        {
                            Foreground = argBrush
                        });
                        par.Inlines.Add(new Run("(argc="));
                        par.Inlines.Add(new Run(instr.ArgumentsCount.ToString())
                        {
                            Foreground = argBrush
                        });
                        par.Inlines.Add(new Run(")"));
                        break;

                    case UndertaleInstruction.InstructionType.BreakInstruction:
                        par.Inlines.Add(new Run("." + instr.Type1.ToOpcodeParam())
                        {
                            Foreground = typeBrush
                        });
                        par.Inlines.Add(new Run(" "));
                        par.Inlines.Add(new Run(instr.Value.ToString())
                        {
                            Foreground = argBrush
                        });
                        break;
                    }

                    if (par.Inlines.Count >= 250)
                    { // Makes selecting text possible.
                        document.Blocks.Add(par);
                        par        = new Paragraph();
                        par.Margin = new Thickness(0);
                    }
                    else
                    {
                        par.Inlines.Add(new Run("\n"));
                    }
                }
            }
            document.Blocks.Add(par);

            DisassemblyView.Document = document;

            CurrentDisassembled = code;
        }
예제 #6
0
        public static void SpeedrunPatches(UndertaleData data)
        {
            UndertaleScript setboi = new UndertaleScript();

            setboi.Name      = data.Strings.MakeString("set_speedrun_category");
            setboi.Code      = new UndertaleCode();
            setboi.Code.Name = data.Strings.MakeString("gml_Script_set_speedrun_category");
            setboi.Code.ReplaceGML(RabbitRunCode.set_speedrun_category, data);
            data.Code.Add(setboi.Code);
            data.Scripts.Add(setboi);

            UndertaleScript sprun = new UndertaleScript();

            sprun.Name = new UndertaleString("menu_speedrun_script");
            data.Strings.Add(sprun.Name);
            sprun.Code = new UndertaleCode();
            data.Code.Add(sprun.Code);
            sprun.Code.Name = new UndertaleString("gml_Script_menu_speedrun_script");
            data.Strings.Add(sprun.Code.Name);
            sprun.Code.ReplaceGML(RabbitRunCode.menu_speedrun_script, data);
            sprun.Code.UpdateAddresses();
            data.Scripts.Add(sprun);

            UndertaleCode ae = data.Code.ByName("gml_Script_setfile");

            ae.AppendGML(RabbitRunCode.gml_Script_setfile, data);
            ae.UpdateAddresses();

            UndertaleCode ee = data.Code.ByName("gml_Object_obj_mainmenus_Create_0");

            ReplaceInGML("GAME\", 1, 8],", "GAME\", 1, 8], [\"SPEEDBUN\", 1, 19], ", ee, data);
            ee.UpdateAddresses();
            ReplaceInGML("i = 0", RabbitRunCode.speedrunMenuInit, ee, data);

            UndertaleCode ie = data.Code.ByName("gml_Script_cKeys_beginstep");

            ie.AppendGML(RabbitRunCode.tasBeginStepInput, data);

            UndertaleCode oe = data.Code.ByName("gml_Object_obj_init_Create_0");

            oe.AppendGML(@"global.playRun = false;
global.watchRun = false;
global.speedrunning = true;
global.inrun = false;
global.onehun = false;//one hundred percent
global.allbun = false;//all cuties
global.anyper = false;//any percent", data);

            UndertaleCode ue = data.Code.ByName("gml_Script_SaveStringToFile");

            ue.ReplaceGML(RabbitRunCode.saveStringFile, data);

            UndertaleSprite mico = data.Sprites.ByName("spr_menuicons");

            UndertaleSprite.TextureEntry te = new UndertaleSprite.TextureEntry();
            UndertaleTexturePageItem     ti = mico.Textures[1].Texture;
            UndertaleTexturePageItem     to = data.Sprites.ByName("spr_antibunidle").Textures[0].Texture;

            te.Texture                = new UndertaleTexturePageItem();
            te.Texture.TargetX        = ti.TargetX;
            te.Texture.TargetY        = ti.TargetY;
            te.Texture.SourceX        = to.SourceX;
            te.Texture.SourceY        = to.SourceY;
            te.Texture.BoundingHeight = ti.BoundingHeight;
            te.Texture.BoundingWidth  = ti.BoundingWidth;
            te.Texture.SourceWidth    = 16;
            te.Texture.TargetWidth    = 16;
            te.Texture.SourceHeight   = 15;
            te.Texture.TargetHeight   = 15;
            te.Texture.TexturePage    = to.TexturePage;
            data.TexturePageItems.Add(te.Texture);
            mico.Textures.Insert(2, te);
        }