Skip to content

Commit

Permalink
Adds a system for printing stats to the disassembler (#2067)
Browse files Browse the repository at this point in the history
  • Loading branch information
wixoaGit authored Dec 11, 2024
2 parents c7c89ae + 5ead2e3 commit 82693c1
Showing 1 changed file with 103 additions and 14 deletions.
117 changes: 103 additions & 14 deletions DMDisassembler/Program.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using DMCompiler.Json;
using JetBrains.Annotations;

namespace DMDisassembler;

Expand All @@ -13,6 +15,7 @@ internal class Program {
public static DMProc GlobalInitProc = null;
public static List<DMProc> Procs = null;
public static Dictionary<string, DMType> AllTypes = null;
public static List<DMType> TypesById = null;

private static readonly string NoTypeSelectedMessage = "No type is selected";

Expand Down Expand Up @@ -52,6 +55,8 @@ static void Main(string[] args) {
}
}

Console.WriteLine("DM Disassembler for OpenDream. Enter a command or \"help\" for more information.");

bool acceptingCommands = true;
while (acceptingCommands) {
if (_selectedType != null) {
Expand All @@ -71,32 +76,113 @@ static void Main(string[] args) {

switch (command) {
case "quit":
case "exit":
case "q": acceptingCommands = false; break;
case "search": Search(split); break;
case "sel":
case "select": Select(split); break;
case "list": List(split); break;
case "d":
case "decompile": Decompile(split); break;
case "stats": Stats(GetArg()); break;
case "test-all": TestAll(); break;
case "dump-all": DumpAll(); break;
case "help": PrintHelp(); break;
default: Console.WriteLine("Invalid command \"" + command + "\""); break;
case "help": {
PrintHelp(GetArg());
break;
}
default: Console.WriteLine($"Invalid command \"{command}\""); break;
}

[CanBeNull]
string GetArg() {
if (split.Length > 2) {
Console.WriteLine($"Command \"{command}\" takes 0 or 1 arguments. Ignoring extra arguments.");
}

return split.Length > 1 ? split[1] : null;
}
}
}

private static void PrintHelp() {
Console.WriteLine("DM Disassembler for OpenDream");
Console.WriteLine("Commands and arguments:");
Console.WriteLine("help : Show this help");
Console.WriteLine("quit|q : Exits the disassembler");
Console.WriteLine("search type|proc [name] : Search for a particular typepath or a proc on a selected type");
Console.WriteLine("select|sel : Select a typepath to run further commands on");
Console.WriteLine("list procs|globals : List all globals, or all procs on a selected type");
Console.WriteLine("decompile|d [name] : Decompiles the proc on the selected type");
Console.WriteLine("dump-all : Decompiles every proc and writes the output to a file");
Console.WriteLine("test-all : Tries to decompile every single proc to check for issues with this disassembler; not for production use");
private static void PrintHelp([CanBeNull] string command) {
if (string.IsNullOrEmpty(command)) {
AllCommands();
return;
}

command = command.ToLower();

switch (command) {
case "stats": {
Console.WriteLine("Prints various statistics. Usage: stats [type]");
Console.WriteLine("Options for [type]:");
Console.WriteLine("procs-by-type : Prints the number of proc declarations (not overrides) on each type in descending order");
break;
}
default: {
Console.WriteLine($"No additional help for \"{command}\"");
AllCommands();
break;
}
}

void AllCommands() {
Console.WriteLine("DM Disassembler for OpenDream");
Console.WriteLine("Commands and arguments:");
Console.WriteLine("help [command] : Show additional help for [command] if applicable");
Console.WriteLine("exit|quit|q : Exits the disassembler");
Console.WriteLine("search type|proc [name] : Search for a particular typepath or a proc on a selected type");
Console.WriteLine("select|sel : Select a typepath to run further commands on");
Console.WriteLine("list procs|globals : List all globals, or all procs on a selected type");
Console.WriteLine("decompile|d [name] : Decompiles the proc on the selected type");
Console.WriteLine("stats [type] : Prints various stats about the game. Use \"help stats\" for more info");
Console.WriteLine("dump-all : Decompiles every proc and writes the output to a file");
Console.WriteLine("test-all : Tries to decompile every single proc to check for issues with this disassembler; not for production use");
}
}

private static void Stats([CanBeNull] string statType) {
if (string.IsNullOrEmpty(statType)) {
PrintHelp("stats");
return;
}

switch (statType) {
case "procs-by-type": {
ProcsByType();
return;
}
default: {
Console.WriteLine($"Unknown stat \"{statType}\"");
PrintHelp("stats");
return;
}
}

void ProcsByType() {
Console.WriteLine("Counting all proc declarations (no overrides) by type. This may take a moment.");
Dictionary<int, int> typeIdToProcCount = new Dictionary<int, int>();
foreach (DMProc proc in Procs) {
if(proc.IsOverride || proc.Name == "<init>") continue; // Don't count overrides or <init> procs
if (typeIdToProcCount.TryGetValue(proc.OwningTypeId, out var count)) {
typeIdToProcCount[proc.OwningTypeId] = count + 1;
} else {
typeIdToProcCount[proc.OwningTypeId] = 1;
}
}

Console.WriteLine("Type: Proc Declarations");
foreach (var pair in typeIdToProcCount.OrderByDescending(kvp => kvp.Value)) {

var type = TypesById[pair.Key];
if (pair.Key == 0) {
Console.WriteLine($"<global>: {pair.Value}");
} else {
Console.WriteLine($"{type.Path}: {pair.Value}");
}
}
}
}

private static void Search(string[] args) {
Expand Down Expand Up @@ -224,9 +310,12 @@ private static void LoadAllProcs() {

private static void LoadAllTypes() {
AllTypes = new Dictionary<string, DMType>(CompiledJson.Types.Length);
TypesById = new List<DMType>(CompiledJson.Types.Length);

foreach (DreamTypeJson json in CompiledJson.Types) {
AllTypes.Add(json.Path, new DMType(json));
var dmType = new DMType(json);
AllTypes.Add(json.Path, dmType);
TypesById.Add(dmType);
}

//Add global procs to the root type
Expand Down

0 comments on commit 82693c1

Please sign in to comment.