Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds a system for printing stats to the disassembler #2067

Merged
merged 7 commits into from
Dec 11, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
public static DMProc GlobalInitProc = null;
public static List<DMProc> Procs = null;
public static Dictionary<string, DMType> AllTypes = null;
public static List<DMType> TypesById = null;
wixoaGit marked this conversation as resolved.
Show resolved Hide resolved

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

Expand Down Expand Up @@ -52,6 +55,8 @@
}
}

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 @@

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];

Check warning

Code scanning / InspectCode

Incorrect blank lines: Incorrect number of blank lines near braces Warning

Incorrect number of blank lines near braces, expected maximum 0 instead of 1
if (pair.Key == 0) {
wixoaGit marked this conversation as resolved.
Show resolved Hide resolved
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 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
Loading