mirror of
https://github.com/izzy2lost/Diddy-Kong-Racing.git
synced 2026-06-19 01:16:26 -07:00
feat: allow score script to generate treemap file for decomp progress (#598)
This commit is contained in:
+2
-1
@@ -7,4 +7,5 @@ Levenshtein>=0.26.1
|
||||
cxxfilt>=0.3.0
|
||||
mapfile-parser>=2.7.5
|
||||
PyYAML>=6.0.2
|
||||
colour>=0.1.5
|
||||
colour>=0.1.5
|
||||
plotly>=6.1.0
|
||||
+113
-3
@@ -1,10 +1,10 @@
|
||||
import re
|
||||
import sys
|
||||
import argparse
|
||||
import time
|
||||
import os
|
||||
from file_util import FileUtil
|
||||
from score_display import ScoreDisplay
|
||||
import plotly.graph_objects as go
|
||||
|
||||
ASM_FOLDERS = [
|
||||
'./asm',
|
||||
@@ -62,7 +62,7 @@ FUNCTION_REGEX = r'^(?<!static\s)(?:(\/[*][*!][*]*\n(?:[^\/]*\n)+?\s*[*]\/\n)(?:
|
||||
GLOBAL_ASM_REGEX = r'\#pragma\sGLOBAL_ASM[(]".*(?=\/)\/([^.]+).s"[)]'
|
||||
WIP_REGEX = r'ifdef\s+(?:NON_MATCHING|NON_EQUIVALENT)(?:.|\n)*?\#else\s*(\#pragma\sGLOBAL_ASM[(][^)]*[)])(.|\n)*?'
|
||||
NON_MATCHING_REGEX = re.compile(r'^#ifdef[ ]+NON_MATCHING(?:.|\n)*?(?:\s*UNUSED\s+)?(?:[^\s]+)\s(?:\s|[*])*?([0-9A-Za-z_]+)\s*[(][^)]*[)]\s*{', re.MULTILINE)
|
||||
NON_EQUVIALENT_REGEX = re.compile(r'^#ifdef[ ]+NON_EQUIVALENT', re.MULTILINE)
|
||||
NON_EQUVIALENT_REGEX = re.compile(r'^#ifdef[ ]+NON_EQUIVALENT(?:.|\n)*?(?:\s*UNUSED\s+)?(?:[^\s]+)\s(?:\s|[*])*?([0-9A-Za-z_]+)\s*[(][^)]*[)]\s*{', re.MULTILINE)
|
||||
|
||||
CODE_START = 0x80000400
|
||||
CODE_END = 0x800D75F4
|
||||
@@ -142,12 +142,19 @@ class ScoreFile:
|
||||
def read_file(self):
|
||||
with open(self.path, "r") as inFile:
|
||||
self.text = inFile.read()
|
||||
|
||||
self.nonMatchings = re.findall(NON_MATCHING_REGEX, self.text)
|
||||
self.nonMatchingsSizes = 0
|
||||
for nonMatching in self.nonMatchings:
|
||||
self.nonMatchingsSizes += MAP_FILE.functionSizes[nonMatching]
|
||||
self.numNonMatchings = len(self.nonMatchings)
|
||||
self.numNonEquivalents = len(re.findall(NON_EQUVIALENT_REGEX, self.text))
|
||||
|
||||
self.nonEquivalents = re.findall(NON_EQUVIALENT_REGEX, self.text)
|
||||
self.nonEquivalentsSizes = 0
|
||||
for nonEquivalent in self.nonEquivalents:
|
||||
self.nonEquivalentsSizes += MAP_FILE.functionSizes[nonEquivalent]
|
||||
self.numNonEquivalents = len(self.nonEquivalents)
|
||||
|
||||
self.text = re.sub(WIP_REGEX, r"GLOBAL_ASM(\1)", self.text)
|
||||
|
||||
def get_matches(self):
|
||||
@@ -198,6 +205,7 @@ def main():
|
||||
parser.add_argument("-t", "--top", help="(Optional) Shows the top N files remaining.")
|
||||
parser.add_argument("-a", "--adventure", help="(Optional) Only shows adventure 1 or 2 based on passed in value.", choices=['1', '2'])
|
||||
parser.add_argument("-s", "--summary", help="(Optional) Only prints the percentages for adventure 1 and 2", action='store_true')
|
||||
parser.add_argument("--treemap", help="(Optional) Generates a treemap .html file", default="progress-treemap.html", metavar="path/to/treemap-file.html")
|
||||
args = parser.parse_args()
|
||||
adventureSelect = 3 # Show both adventures by default
|
||||
if args.adventure != None:
|
||||
@@ -267,6 +275,108 @@ def main():
|
||||
print(f"Decomp progress: {adventureOnePercentage:5.2f}%")
|
||||
print(f"Documentation progress: {adventureTwoPercentage:5.2f}%")
|
||||
sys.exit(0)
|
||||
|
||||
if args.treemap:
|
||||
print(f"Generating progress treemap, outputting file to {args.treemap}")
|
||||
|
||||
# Prepare data
|
||||
labels = ["Decomp"]
|
||||
parents = [None]
|
||||
values = [0]
|
||||
colours = [None]
|
||||
legends = [None]
|
||||
|
||||
for scoreFile in scoreFiles:
|
||||
parentName = scoreFile.path.replace('./src/', '')
|
||||
|
||||
for func in scoreFile.functions:
|
||||
color = '#92ac68'
|
||||
legend = 'matched'
|
||||
if func.isDocumented:
|
||||
color = 'green'
|
||||
legend = 'documented'
|
||||
|
||||
labels.append(func.functionName)
|
||||
parents.append(parentName)
|
||||
values.append(func.size)
|
||||
colours.append(color)
|
||||
legends.append(legend)
|
||||
|
||||
matches = re.finditer(GLOBAL_ASM_REGEX, scoreFile.text, re.MULTILINE)
|
||||
for match in matches:
|
||||
funcName = match.groups()[0]
|
||||
size = MAP_FILE.functionSizes[funcName]
|
||||
|
||||
color = "grey"
|
||||
legend = "N/A"
|
||||
if funcName in scoreFile.nonMatchings:
|
||||
color = 'orange'
|
||||
legend = "non matching"
|
||||
elif funcName in scoreFile.nonEquivalents:
|
||||
color = 'red'
|
||||
legend = "non equivalent"
|
||||
|
||||
labels.append(funcName)
|
||||
parents.append(parentName)
|
||||
values.append(size)
|
||||
colours.append(color)
|
||||
legends.append(legend)
|
||||
|
||||
labels.append(parentName)
|
||||
parents.append("Decomp")
|
||||
values.append(0)
|
||||
colours.append(None)
|
||||
legends.append(None)
|
||||
|
||||
matchPercents = []
|
||||
for value in values:
|
||||
if value > 0:
|
||||
matchPercents.append(f"Size: {value} bytes<br>Total: {value / CODE_SIZE * 100:.2f}%")
|
||||
else:
|
||||
matchPercents.append(None)
|
||||
|
||||
fig = go.Figure(go.Treemap(
|
||||
labels = labels,
|
||||
parents = parents,
|
||||
values = values,
|
||||
text=matchPercents,
|
||||
hovertemplate='<b>%{label}</b><br>Size: %{value} bytes<extra></extra>',
|
||||
marker = dict(colors = colours),
|
||||
root_color="lightgrey"
|
||||
))
|
||||
|
||||
# Add custom legend using annotations
|
||||
legend_items = [
|
||||
("green", "documented"),
|
||||
("#92ac68", "matched"),
|
||||
("orange", "non matching"),
|
||||
("red", "non equivalent"),
|
||||
("grey", "N/A")
|
||||
]
|
||||
|
||||
annotations = []
|
||||
for i, (color, label) in enumerate(legend_items):
|
||||
annotations.append(dict(
|
||||
x=1.05,
|
||||
y=1 - (i * 0.05),
|
||||
xref="paper",
|
||||
yref="paper",
|
||||
showarrow=False,
|
||||
text=f"<span style='color:{color}'>■</span> {label}",
|
||||
font=dict(size=12)
|
||||
))
|
||||
|
||||
|
||||
fig.update_layout(
|
||||
margin=dict(t=50, l=25, r=150, b=25), # Extra right margin for legend
|
||||
title="Decomp Progress",
|
||||
annotations=annotations
|
||||
)
|
||||
output_path = "treemap.html"
|
||||
# This will raise an error if writing fails
|
||||
fig.write_html(output_path)
|
||||
sys.exit(0)
|
||||
|
||||
scoreDisplay = ScoreDisplay()
|
||||
print(scoreDisplay.getDisplay(adventureOnePercentage, adventureOnePercentageWithNonMatching, adventureTwoPercentage, adventureSelect, totalNumberOfDecompiledFunctions, totalNumberOfGlobalAsms, totalNumberOfNonMatching, totalNumberOfNonEquivalent, totalNumberOfDocumentedFunctions, (totalNumberOfFunctions - ignoreNumberDocumentedFunctions) - totalNumberOfDocumentedFunctions))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user