make building partly possible

This commit is contained in:
SwareJonge 2022-06-11 03:31:09 +02:00
parent a48ca9d654
commit 6b626613a3
625 changed files with 9393 additions and 641 deletions

7
.gitignore vendored
View File

@ -1,5 +1,10 @@
*.o
*.s
*.dol
*.elf
*.exe
*.MAP
*.MAP
*.ninja
.ninja_log
/deps/
/include

168
build.py Normal file
View File

@ -0,0 +1,168 @@
import subprocess
import sys
import os
import shutil
import pathlib
import shutil
def deleteDFiles():
dirs = os.listdir(os.getcwd())
for dire in dirs:
if dire.endswith(".d"):
os.remove(os.path.join(os.getcwd(), dire))
def main(compile_non_matching, use_ninja, clean_ninja):
if not os.path.exists("deps"):
print("deps folder not created, please run setup.py!")
sys.exit(1)
isNotWindows = os.name != "nt"
flags = "-c -Cpp_exceptions off -proc gekko -fp_contract on -fp fmadd -fp hard -lang=c++ -use_lmw_stmw on -inline on -O4 -sdata 4 -sdata2 4 -align powerpc -enum int -DRVL_SDK -DEPPC -DHOLLYWOOD_REV -DTRK_INTEGRATION -DGEKKO -DMTX_USE_PS -D_MSL_USING_MW_C_HEADERS -msgstyle gcc "
includes = "-i . -I- -i include "
default_compiler_path = pathlib.Path("GC/2.5/")
compiler_exceptions = {
#"source\JSystem\JKernel\JKRThread.cpp": "GC/2.5/"
}
compiler_flags = {
#"GC/2.5", flags
}
if compile_non_matching:
print("Using nonmatching functions")
flags = flags + " -DNON_MATCHING "
trk_path = pathlib.Path("deps/EABI/PowerPC_EABI_Support/MetroTRK")
runtime_path = pathlib.Path("deps/EABI/PowerPC_EABI_Support/Runtime/Inc")
runtimesrc_path = pathlib.Path("deps/EABI/PowerPC_EABI_Support/Runtime/Src")
msl_c_path = pathlib.Path("deps/EABI/PowerPC_EABI_Support/MSL/MSL_C/PPC_EABI/Include")
msl_cpp_path = pathlib.Path("deps/EABI/PowerPC_EABI_Support/MSL/MSL_C++/MSL_Common/Include")
msl_c_common_path = pathlib.Path("deps/EABI/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include")
includes += f"-I- -i {trk_path} -I- -i {runtime_path} -I- -i {runtimesrc_path} -I- -i {msl_c_path} -I- -i {msl_cpp_path} -I- -i {msl_c_common_path} "
flags += includes
tasks = list()
ninjaFound = shutil.which("ninja") is not None
if not ninjaFound and use_ninja:
print("Ninja was not found in your PATH. Compilation will be slow!")
useNinja = ninjaFound and use_ninja
if not useNinja:
if os.path.exists("build"):
shutil.rmtree("build", ignore_errors=True)
for root, dirs, files in os.walk("src"):
for file in files:
if file.endswith(".cpp"):
source_path = os.path.join(root, file)
build_path = source_path.replace("src", "build", 1).replace(".cpp", ".o")
os.makedirs(os.path.dirname(build_path), exist_ok=True)
tasks.append((source_path, build_path))
elif file.endswith(".c"):
source_path = os.path.join(root, file)
build_path = source_path.replace("src", "build", 1).replace(".c", ".o")
os.makedirs(os.path.dirname(build_path), exist_ok=True)
tasks.append((source_path, build_path))
compiler_path = pathlib.Path(f"deps/Compilers/{default_compiler_path}/mwcceppc.exe ")
if isNotWindows:
compiler_path = pathlib.Path(f"wine {compiler_path} ")
if useNinja:
# Use ninja build system to generate a build script.
from ninja import ninja_syntax
bo = open("build.ninja", "w")
nw = ninja_syntax.Writer(bo)
# Create main compiler rule and exception compilers.
nw.rule("cc", f"{compiler_path} $flags $in -o $out", "Compiling $in...")
exceptionsToRules = { "sample": "value" }
cc_num = 1
for exc in compiler_exceptions.values():
if not exc in exceptionsToRules.keys():
exceptionsToRules[exc] = f"cc_{cc_num}"
cc_num += 1
nw.newline()
for task in tasks:
source_path, build_path = task
rule = "cc"
try:
if compiler_exceptions[source_path]:
rule = exceptionsToRules[compiler_exceptions[source_path]]
except:
pass
nw.build(build_path, rule, source_path, variables={ 'flags': flags })
nw.close()
# Run clean
if clean_ninja:
subprocess.call("ninja -t clean", shell=True)
# Call ninja to run said build script.
if subprocess.call("ninja", shell=True) == 1:
deleteDFiles()
sys.exit(1)
else:
for task in tasks:
source_path, build_path = task
try:
if compiler_exceptions[source_path]:
compiler_path = pathlib.Path(f"deps/Compilers/{compiler_exceptions[source_path]}/mwcceppc.exe ")
if isNotWindows:
compiler_path = pathlib.Path(f"wine {compiler_path} ")
except:
pass
print(f"Compiling {source_path}...")
if subprocess.call(f"{compiler_path} {flags} {source_path} -o {build_path}", shell=True) == 1:
deleteDFiles()
sys.exit(1)
deleteDFiles()
print("Complete.")
def print_help_and_exit():
print("Usage: build.py [flags...]")
print("\t-non-matching: Compile non-matching code.")
print("\t-no-ninja: Do not use ninja even if available.")
print("\t-clean: Clean old build files before building new when using ninja.")
print("\t-help: Displays this help text")
sys.exit(0)
if __name__ == "__main__":
compile_non_matching = False
use_ninja = True
clean_ninja = False
for arg in sys.argv[1:]:
if arg == "-non-matching":
compile_non_matching = True
elif arg == "-no-ninja":
use_ninja = False
elif arg == "-clean":
clean_ninja = True
elif arg == "-help":
print_help_and_exit()
else:
print(f"Invalid argument: {arg}")
print()
print_help_and_exit()
main(compile_non_matching, use_ninja, clean_ninja)

559
check.py Normal file
View File

@ -0,0 +1,559 @@
# check.py
# script that marks functions as decompiled based on matching status
import os
from typing import overload
from elftools.elf.elffile import ELFFile
from colorama import Fore, Style
import glob
import hashlib
import sys
import struct
from capstone import *
from capstone.ppc import *
import pathlib
from collections import OrderedDict
class FunctionLibrary:
def __init__(self):
self.libraries = dict()
self.functions = dict()
def load(self):
self.libraries.clear()
self.functions.clear()
# Load CSV files
for file in os.listdir("csv"):
library = file[0:file.rfind(".")]
symbols = OrderedDict()
with open(pathlib.Path(f"csv/{file}"), "r") as input:
is_first_line = True
for line in input:
if is_first_line:
is_first_line = False
continue
line_split = line.rstrip().split(",")
symbol = line_split[0]
obj_file = line_split[1]
library_name = line_split[2]
matches = line_split[3] == "true"
if (symbol, obj_file) in symbols:
print(f"Duplicate symbol {symbol} in .o file {obj_file}.")
sys.exit(1)
symbols[(symbol, obj_file)] = (library_name, matches)
self.libraries[library] = symbols
# Load addresses from symbol map
with open("data/map_for_dol.map", "r") as input:
for line in input:
line_split = line.rstrip().split("=")
symbol = line_split[1].split(":")[0]
number_split = line_split[0].split(" ")
address = int(number_split[4], 16)
size = int(number_split[3], 16)
self.functions[symbol] = (address, size)
def save(self):
for library, symbols in self.libraries.items():
with open(f"csv/{library}.csv", "w") as output:
output.write("Symbol Name, Object File, Library Archive, Matching\n")
for (symbol, obj_file), values in symbols.items():
output.write(f"{symbol},{obj_file},{values[0]},{str(values[1]).lower()}\n")
def get_obj_names_from_symbol(self, symbol_lookup):
names = []
for symbols in self.libraries.values():
for (symbol, obj_name) in symbols.keys():
if symbol == symbol_lookup:
names.append(obj_name)
return names
def is_marked_decompiled(self, library_name, symbol, obj_file):
if library_name in self.libraries:
library = self.libraries[library_name]
if (symbol, obj_file) in library:
return library[(symbol, obj_file)][1]
return False
def mark_symbol_decompiled(self, library_name, symbol, obj_file, decompiled):
if library_name in self.libraries:
library = self.libraries[library_name]
if (symbol, obj_file) in library:
library[(symbol, obj_file)] = (library[(symbol, obj_file)][0], decompiled)
def get_library_from_symbol(self, symbol, obj_file):
for library, symbols in self.libraries.items():
if (symbol, obj_file) in symbols:
return library
return None
def get_address_from_symbol(self, symbol):
if symbol in self.functions:
return self.functions[symbol][0]
return None
def get_size_from_symbol(self, symbol):
if symbol in self.functions:
return self.functions[symbol][1]
return None
def get_symbols_marked_as_decompiled(self):
for symbols in self.libraries.values():
for (symbol, obj_file), values in symbols.items():
if values[1] == True:
yield (symbol, obj_file)
def print_help_and_exit():
print("Usage: check.py [mangled_symbol] [flags...]")
print("\t[mangled_symbol]: name of the symbol that should be checked.")
print("\t[-all]: run checks on all functions which has been marked as decompiled.")
print("\t[-compare]: compares decompiled functions.")
print("\t[-help]: displays this help text.")
print("\t[-only-errors]: displays only error messages.")
print("\t[-no-hints]: don't display hint messages.")
print("\t[-no-warnings]: don't display warning messages.")
print("\t[-no-errors]: don't display error messages.")
print("\t[-readonly]: don't mark or unmark any functions as decompiled.")
sys.exit(0)
def is_dol_correct():
with open("baserom.dol", "rb") as input:
data = input.read()
hash = hashlib.sha256(data).hexdigest().upper()
return hash == "8B7F28D193170F998F92E02EA638107822FB72073691D0893EB18857BE0C6FCF" or hash == "69F93FCC0FA34837347B5AC05168BC783ADCACB3C02697CFDA087A3B63ABC9E0"
def get_code_from_dol(address, size):
with open("baserom.dol", "rb") as input:
data = input.read()
# Grab .text offset and start offset
txt_offset, = struct.unpack_from(">I", data, 4)
start_address, = struct.unpack_from(">I", data, 0x4C)
offset = address - start_address
return data[txt_offset + offset:txt_offset + offset + size]
def print_error(message):
global show_errors
if show_errors:
print(f"ERROR: {message}")
def print_warning(message):
global show_warnings
if show_warnings:
print(f"WARNING: {message}")
def print_hint(message):
global show_hints
if show_hints:
print(f"HINT: {message}")
def print_instruction_comparison_error(message, original, custom):
global show_errors
if show_errors:
print_error(message)
print_instruction_comparison(original, custom)
def print_instruction_comparison_warning(message, original, custom):
global show_warnings
if show_warnings:
print_warning(message)
print_instruction_comparison(original, custom)
def print_instruction_comparison_hint(message, original, custom):
global show_hints
if show_hints:
print_hint(message)
print_instruction_comparison(original, custom)
def print_instruction_comparison(original, custom):
print(f"\tOriginal: {original}")
print(f"\tCustom: {custom}")
def check_symbol(function_library, mangled_symbol, obj_name, readonly):
black_listed_instructions = {
PPC_INS_VMSUMSHM, PPC_INS_VMHADDSHS, PPC_INS_XXSLDWI, PPC_INS_VSEL,
PPC_INS_XVSUBSP, PPC_INS_XXSEL, PPC_INS_XVMULSP, PPC_INS_XVDIVSP,
PPC_INS_VADDUHM, PPC_INS_XXPERMDI, PPC_INS_XVMADDASP, PPC_INS_XVMADDMSP,
PPC_INS_XVCMPGTSP, PPC_INS_XXMRGHD, PPC_INS_XSMSUBMDP, PPC_INS_XSTDIVDP,
PPC_INS_XVADDSP, PPC_INS_XVCMPEQSP, PPC_INS_XVMSUBASP, PPC_INS_XVCMPGESP,
PPC_INS_MFESR, PPC_INS_MFDEAR, PPC_INS_MTESR, PPC_INS_MTDEAR, PPC_INS_MFICCR, PPC_INS_MFASR
}
unsupported_libraries = { "TRK_Hollywood_Revolution" }
library = function_library.get_library_from_symbol(mangled_symbol, obj_name)
if library == None:
print("Could not find library of symbol.")
return False
if library in unsupported_libraries:
print(f"Library {library} is currently not supported.")
return False
obj_files = glob.glob(f"build/*/{library}/{obj_name}", recursive=True)
if len(obj_files) > 1:
print("Found multiple .o files. This should not happen.")
return False
if len(obj_files) == 0:
print("Could not find any .o files for the function.")
return False
with open(pathlib.Path(obj_files[0]), "rb") as input:
elf_file = ELFFile(input)
symtab = elf_file.get_section_by_name('.symtab')
if symtab.get_symbol_by_name(mangled_symbol) is None:
print("Could not find symbol in object file. This may be caused by the code not being compiled, the function being in the wrong C++ source file or the function signature being wrong.")
return False
compiled_symbol = symtab.get_symbol_by_name(mangled_symbol)[0]
# Get custom code
custom_offset = compiled_symbol["st_value"]
custom_size = compiled_symbol['st_size']
text = elf_file.get_section_by_name('.text')
custom_data = text.data()[custom_offset:custom_offset + custom_size]
# Get original code
original_address = function_library.get_address_from_symbol(mangled_symbol)
original_size = function_library.get_size_from_symbol(mangled_symbol)
if original_address == None or original_size == None:
print("Could not find address and/or size for symbol")
return False
original_data = get_code_from_dol(original_address, original_size)
if original_data == None:
print("Could not get data from DOL file.")
return False
cs = Cs(CS_ARCH_PPC, CS_MODE_32 | CS_MODE_BIG_ENDIAN)
cs.detail = True
cs.imm_unsigned = False
original_instructions = list(cs.disasm(original_data, 0))
custom_instructions = list(cs.disasm(custom_data, 0))
error_count = 0
warning_count = 0
hint_count = 0
# Capstone doesn't seem to handle paired single instructions
# If any is found, it just stops disassembling
if 4 * len(original_instructions) != original_size:
print_warning(f"Only {len(original_instructions)} out of the {original_size // 4} original instructions were loaded.")
warning_count += 1
if 4 * len(custom_instructions) != custom_size:
print_warning(f"Only {len(custom_instructions)} out of the {custom_size // 4} custom instructions were loaded.")
warning_count += 1
if original_size > custom_size:
print_error("Original code contains more instructions than custom code.")
error_count += 1
elif original_size < custom_size:
print_error("Original code contains less instructions than custom code.")
error_count += 1
for i in range(min(len(original_instructions), len(custom_instructions))):
line = i * 4
line_string = f"{hex(line)} (Original: {hex(original_address + line)})"
original_instruction = original_instructions[i]
custom_instruction = custom_instructions[i]
original_operands = original_instruction.operands
custom_operands = custom_instruction.operands
if str(original_instruction) == str(custom_instruction):
print(f"{Fore.GREEN}{str(original_instruction):<80}{custom_instruction}{Style.RESET_ALL}")
# Fully identical, nothing to be checked
continue
if original_instruction in black_listed_instructions:
print_warning(f"Skipping blacklisted instruction at line {line_string}.")
warning_count += 1
continue
if original_instruction.id == custom_instruction.id:
assert(len(original_operands) == len(custom_operands))
# First check common r2 and r13 issues
if original_instruction.id in { PPC_INS_LBZ, PPC_INS_LWZ, PPC_INS_STW, PPC_INS_LFS }:
assert(len(original_operands) == 2 and len(custom_operands) == 2)
# lbz, lwz, stw and lfs are sometimes used with r13, which is a pointer to a read-write
# small data area (SDA). When compiling custom code, this SDA is not generated,
# so the register is set to r0 and the displacement is set to 0.
# Original must be (instr) rX, X(r13) and custom must be (instr) rX, 0(r0)
if original_operands[1].reg == PPC_REG_R13 and custom_operands[1].reg == PPC_REG_R0 and\
custom_operands[1].mem.disp == 0 and original_operands[0].reg == custom_operands[0].reg:
print(f"{Fore.YELLOW}{str(original_instruction):<80}{custom_instruction}{Style.RESET_ALL}")
#print_instruction_comparison_hint(f"Skipping r13 issue at line {line_string}.", original_instruction, custom_instruction)
hint_count += 1
continue
if original_instruction.id in { PPC_INS_LWZ, PPC_INS_LFS, PPC_INS_LHZ, PPC_INS_LFS }:
assert(len(original_operands) == 2 and len(custom_operands) == 2)
# Same as above, except with r2 instead of r13. r2 is a pointer to a read-only SDA.
# Original must be (instr) rX, X(r2) and custom must be (instr) rX, 0(0)
if original_operands[1].reg == PPC_REG_R2 and custom_operands[1].reg == PPC_REG_R0 and\
custom_operands[1].mem.disp == 0 and original_operands[0].reg == custom_operands[0].reg:
print(f"{Fore.YELLOW}{str(original_instruction):<80}{custom_instruction}{Style.RESET_ALL}")
#print_instruction_comparison_hint(f"Skipping r2 issue at line {line_string}.", original_instruction, custom_instruction)
hint_count += 1
continue
# Check if all registers are equal
registers_equal = True
for j in range(len(original_operands)):
if original_operands[j].reg != custom_operands[j].reg:
registers_equal = False
break
if registers_equal:
print(f"{Fore.YELLOW}{str(original_instruction):<80}{custom_instruction}{Style.RESET_ALL}")
#print_instruction_comparison_warning(f"Registers are identical but the instruction is not identical at line {line_string}.", original_instruction, custom_instruction)
warning_count += 1
elif original_instruction.id == PPC_INS_ADDI:
# addi is commonly used when loading addresses
print(f"{Fore.YELLOW}{str(original_instruction):<80}{custom_instruction}{Style.RESET_ALL}")
#print_instruction_comparison_warning(f"Skipping addi instruction at line {line_string}.", original_instruction, custom_instruction)
warning_count += 1
elif original_instruction.id == PPC_INS_LIS:
# Same as addi
print(f"{Fore.YELLOW}{str(original_instruction):<80}{custom_instruction}{Style.RESET_ALL}")
#print_instruction_comparison_warning(f"Skipping lis instruction at line {line_string}.", original_instruction, custom_instruction)
warning_count += 1
elif original_instruction.id in { PPC_INS_B, PPC_INS_BL }:
# bl is used to call most functions, and since the functions are likely to be placed
# differently it's not possible to compare it
# If a function ends with a function call, and the returned value from the function, then b is sometimes used for branching
# to that function. Then it's not possible to compare this
print(f"{Fore.YELLOW}{str(original_instruction):<80}{custom_instruction}{Style.RESET_ALL}")
#print_instruction_comparison_warning(f"Skipping branch instruction at line {line_string}.", original_instruction, custom_instruction)
warning_count += 1
else:
print(f"{Fore.RED}{str(original_instruction):<80}{custom_instruction}{Style.RESET_ALL}")
#print_instruction_comparison_error(f"Instruction mismatch on line {line_string}.", original_instruction, custom_instruction)
error_count += 1
elif original_instruction.id == PPC_INS_ADDI and custom_instruction.id == PPC_INS_LI:
assert(len(original_operands) == 3 and len(custom_operands) == 2)
# This is caused by the read-write SDA, pointed by r13, is not generated in the custom code.
# Original must be addi rX, r13, X and custom must be li rX, 0
if original_operands[1].reg == PPC_REG_R13 and custom_operands[1].imm == 0 and\
original_operands[0].reg == custom_operands[0].reg:
print(f"{Fore.YELLOW}{str(original_instruction):<80}{custom_instruction}{Style.RESET_ALL}")
#print_instruction_comparison_hint(f"Found addi / li mismatch at line {line_string}.", original_instruction, custom_instruction)
hint_count += 1
else:
print(f"{Fore.RED}{str(original_instruction):<80}{custom_instruction}{Style.RESET_ALL}")
#print_instruction_comparison_error(f"Instruction mismatch on line {line_string}.", original_instruction, custom_instruction)
error_count += 1
else:
print(f"{Fore.RED}{str(original_instruction):<80}{custom_instruction}{Style.RESET_ALL}")
#print_instruction_comparison_error(f"Instruction mismatch on line {line_string}.", original_instruction, custom_instruction)
error_count += 1
print()
print(f"Check finished with {error_count} error(s), {warning_count} warning(s) and {hint_count} hint(s).")
is_decompiled = function_library.is_marked_decompiled(library, mangled_symbol, obj_name)
passed = error_count == 0
if not readonly:
if passed:
if is_decompiled:
print("Function already marked as decompiled.")
else:
print("Marking as decompiled...")
function_library.mark_symbol_decompiled(library, mangled_symbol, obj_name, True)
else:
if is_decompiled:
print("Function is marked as decompiled, but does not match.")
print("Unmarking as decompiled...")
function_library.mark_symbol_decompiled(library, mangled_symbol, obj_name, False)
else:
print("Function is not marked as decompiled, and does not match either.")
return passed
mangled_symbol = None
check_all = False
compare = False
show_hints = True
show_warnings = True
show_errors = True
readonly = False
for i in range(1, len(sys.argv)):
arg = sys.argv[i]
if arg == "-all":
check_all = True
elif arg == "-compare":
compare = True
elif arg == "-help":
print_help_and_exit()
elif arg == "-only-errors":
show_hints = False
show_warnings = False
show_errors = True
elif arg == "-no-hints":
show_hints = False
elif arg == "-no-warnings":
show_warnings = False
elif arg == "-no-errors":
show_errors = False
elif arg == "-readonly":
readonly = True
elif mangled_symbol == None:
mangled_symbol = arg
else:
print(f"Invalid argument: {arg}")
print()
print_help_and_exit()
if mangled_symbol == None and not check_all and not compare:
print_help_and_exit()
if not is_dol_correct():
print("DOL file is not valid.")
sys.exit(1)
function_library = FunctionLibrary()
function_library.load()
if check_all:
success_count = 0
total_count = 0
for (symbol, obj_name) in function_library.get_symbols_marked_as_decompiled():
print(f"Checking {symbol}...")
total_count += 1
if check_symbol(function_library, symbol, obj_name, True):
success_count += 1
print()
print(f"{success_count} function(s) out of the {total_count} function(s), which were marked as decompiled, passed the check.")
print(f"{total_count - success_count} function(s) failed the check.")
if compare:
success_count_a = 0
fail_count_a = 0
matched_a = set()
failed_a = set()
for (symbol, obj_name) in function_library.get_symbols_marked_as_decompiled():
print(f"Checking {symbol}...")
if check_symbol(function_library, symbol, obj_name, True):
success_count_a += 1
matched_a.add((symbol, obj_name))
else:
fail_count_a += 1
failed_a.add((symbol, obj_name))
print()
print()
print()
print("First run of tests are now done.")
print("Now, please make the code changes you wish to test, and then recompile everything.")
input("Press Enter to contiue...")
success_count_b = 0
fail_count_b = 0
matched_b = set()
failed_b = set()
for (symbol, obj_name) in function_library.get_symbols_marked_as_decompiled():
print(f"Checking {symbol}...")
if check_symbol(function_library, symbol, obj_name, True):
success_count_b += 1
matched_b.add((symbol, obj_name))
else:
fail_count_b += 1
failed_b.add((symbol, obj_name))
print()
print()
print()
print("Second run of tests are now done.")
print()
print(f"First run: {success_count_a} matched and {fail_count_a} failed.")
print(f"Second run: {success_count_b} matched and {fail_count_b} failed.")
print()
print("The following functions matched during the first run and failed during the second test:")
for matched in matched_a:
if matched in failed_b:
print(f"{matched[0]} in {matched[1]}")
print()
print("The following functions failed during the first run and matched during the second test:")
for failed in failed_a:
if failed in matched_b:
print(f"{failed[0]} in {failed[1]}")
if mangled_symbol != None:
obj_names = function_library.get_obj_names_from_symbol(mangled_symbol)
if len(obj_names) == 0:
print("Could not find any .o files for the specified symbol.")
sys.exit(1)
elif len(obj_names) > 1:
print("There are multiple .o files found for the specified symbol. This is currently not supported by the script.")
sys.exit(1)
check_symbol(function_library, mangled_symbol, obj_names[0], readonly)
function_library.save()

View File

@ -1,8 +0,0 @@
#ifndef OSTIME_H
#define OSTIME_H
#include <types>
u64 OSGetTime();
#endif // !OSTIME_H

View File

@ -1,6 +1,8 @@
#ifndef JGEOMETRY_H
#define JGEOMETRY_H
#include "types.h"
// from SMS decomp
namespace JGeometry {
template <typename T> class TVec3 {
@ -21,7 +23,7 @@ namespace JGeometry {
void scale(f32 scale);
void scale(f32 scale, const TVec3& operand);
void scaleAdd(f32 scale, const TVec3& operand, const TVec3& translate);
void set(const Vec&);
//void set(const Vec&);
template <typename TY> void set(TY x, TY y, TY z);
template <typename TY> void set(const TVec3<TY>&);

View File

@ -1,6 +1,8 @@
#ifndef JKRDISPOSER_H
#define JKRDISPOSER_H
#include "types.h"
#include "JSystem/JSupport/JSUList.h"
class JKRHeap;

View File

@ -1,8 +1,8 @@
#ifndef JKRHEAP_H
#define JKRHEAP_H
#include <JSystem/JKernel/JKRDisposer.h>
#include <JSystem/JSupport/JSUList.h>
#include "types.h"
#include "JSystem/JKernel/JKRDisposer.h"
class JKRHeap : public JKRDisposer {
public:

View File

@ -1,7 +1,7 @@
#ifndef JMATRIGONOMETRIC_H
#define JMATRIGONOMETRIC_H
#include <types.h>
#include "types.h"
#include <utility> // std::pair
// from TP decomp

View File

@ -1,15 +1,20 @@
#ifndef JMATH_H
#define JMATH_H
#include <types.h>
#include "JMATrigonometric.h"
#include "types.h"
#include "JSystem/JMath/JMATrigonometric.h"
namespace JMath {
TSinCosTable sincosTable_;
class TRandom_fast_
{
public:
TRandom_fast_(u32 num);
inline u32 get();
inline TRandom_fast_(u32 num);
u32 get() {
seed = (seed * 0x19660d) + 0x3c6ef35f;
return seed;
}
// from TP decomp
float get_ufloat_1() {
@ -23,7 +28,9 @@ namespace JMath {
return out.f - 1;
}
inline setSeed(u32 Seed);
void setSeed(u32 Seed) {
seed = Seed;
}
private:
u32 seed;

View File

@ -1,7 +1,7 @@
#ifndef JSULIST_H
#define JSULIST_H
#include <types.h>
#include "types.h"
class JSUPtrLink;
@ -11,47 +11,52 @@ public:
initiate();
}
JSUPtrList(bool hasBeenInit);
JSUPtrList(bool);
~JSUPtrList();
void initiate();
void setFirst(JSUPtrLink *pNode);
void append(JSUPtrLink *pNode);
void prepend(JSUPtrLink *pNode);
void insert(JSUPtrLink *, JSUPtrLink *);
void remove(JSUPtrLink *pNode);
void setFirst(JSUPtrLink *);
bool append(JSUPtrLink *);
bool prepend(JSUPtrLink *);
bool insert(JSUPtrLink *, JSUPtrLink *);
bool remove(JSUPtrLink *);
JSUPtrLink* mHead; // _0
JSUPtrLink* mTail; // _4
u32 mNodeCount; // _8
JSUPtrLink *mHead; // _0
JSUPtrLink *mTail; // _4
u32 mNodeCount; // _8
};
class JSUPtrLink {
public:
JSUPtrLink(void *pData);
JSUPtrLink(void *);
~JSUPtrLink();
void *mData; // _0
JSUPtrList* mPtrList; // _4
JSUPtrLink* mPrev; // _8
JSUPtrLink* mNext; // _C
void *mData; // _0
JSUPtrList *mPtrList; // _4
JSUPtrLink *mPrev; // _8
JSUPtrLink *mNext; // _C
};
template<typename T>
template<class T>
class JSULink : public JSUPtrLink {
public:
JSULink(void *pData) : JSUPtrLink(pData) { }
JSULink(void *pData) : JSUPtrLink(pData) {
}
~JSULink();
};
template<typename T>
template<class T>
class JSUList : public JSUPtrList {
public:
JSUList() : JSUPtrList() { }
JSUList(bool hasBeenInit) : JSUPtrList(hasBeenInit) { }
JSUList() : JSUPtrList() {
~JSUList();
}
JSUList(bool thing) : JSUPtrList(thing) {
}
};
#endif
#endif /* JSULIST_H */

View File

@ -1,6 +0,0 @@
#ifndef JUTDBPPRINT_H
#define JUTDBPPRINT_H
void JUTReport(int, int, const char *, ...);
#endif // !JUTDBPPRINT_H

View File

@ -29,4 +29,4 @@ typedef volatile f64 vf64;
typedef int BOOL;
#endif // !TYPES_H
#endif // !TYPES_H

7998
info/Symbols(Game).txt Normal file

File diff suppressed because it is too large Load Diff

331
progress.py Normal file
View File

@ -0,0 +1,331 @@
import csv, glob, math, os, sys
from pathlib import Path
libraries = { }
def truncate(number, digits) -> float:
stepper = 10.0 ** digits
return math.trunc(stepper * number) / stepper
class Function:
name = ""
isCompleted = False
funcSize = 0
def __init__(self, name, isComplete, funcSize):
self.name = name
self.isCompleted = isComplete
self.funcSize = funcSize
class Object:
name = ""
functions = []
totalFunctions = 0
totalCompletedFunctions = 0
def __init__(self, name):
self.name = name
self.functions = list()
self.totalFunctions = 0
self.totalCompletedFunctions = 0
def addFunction(self, function):
self.functions.append(function)
if function.isCompleted:
self.totalCompletedFunctions += 1
self.totalFunctions += 1
def getFunctions(self):
return self.functions
def calculateProgress(self):
fullSize = 0
doneSize = 0
for function in self.functions:
fullSize += function.funcSize
if function.isCompleted:
doneSize += function.funcSize
return doneSize, fullSize
class Library:
name = ""
objects = []
def __init__(self, name):
self.name = name
self.objects = list()
def addObject(self, object):
self.objects.append(object)
def addFunctionToObject(self, obj, function):
if self.containsObject(obj.name):
self.findObject(obj.name).addFunction(function)
else:
self.addObject(obj)
self.addFunctionToObject(obj, function)
def findObject(self, objectName):
for obj in self.objects:
if obj.name == objectName:
return obj
return None
def getObjects(self):
return self.objects
def containsObject(self, object):
for obj in self.objects:
if obj.name == object:
return True
return False
def calculateProgress(self):
fullSize = 0
doneSize = 0
for obj in self.objects:
d, f = obj.calculateProgress()
fullSize += f
doneSize += d
return doneSize, fullSize
def getName(self):
return self.name
def generateJSONTag(self, percent, color):
json = []
json.append("{\n")
json.append("\t\"schemaVersion\": 1,\n")
json.append(f"\t\"label\": \"{self.name}\",\n")
json.append(f"\t\"message\": \"{truncate(percent, 5)}%\",\n")
json.append(f"\t\"color\": \"{color}\"\n")
json.append("}")
with open(f"data/json/{self.name}.json", "w") as w:
w.writelines(json)
def generateMarkdown(self):
# first we are going to generate the tables for the object files themselves in the library
page = []
page.append(f"# {self.name}\n")
page.append("| Object | Percentage (of Bytes) | Functions Done / Total Functions | Percentage (Functions) \n")
page.append("| ------------- | ------------- | ------------- | ------------- |\n")
for obj in self.objects:
d, f = obj.calculateProgress()
prog = (d / f) * 100.0
funcProg = (obj.totalCompletedFunctions / obj.totalFunctions) * 100.0
page.append(f"| {obj.name} | {prog}% | {obj.totalCompletedFunctions} / {obj.totalFunctions} | {funcProg}% |\n")
page.append("\n\n")
# now we can do it per object in the library
for obj in self.objects:
page.append(f"# {obj.name}\n")
page.append("| Symbol | Decompiled? |\n")
page.append("| ------------- | ------------- |\n")
for func in obj.getFunctions():
marker = ":x:"
if func.isCompleted:
marker = ":white_check_mark:"
funcName = func.name.replace("<", "&lt;")
funcName = funcName.replace(">", "&gt;")
page.append(f"| {funcName} | {marker} |\n")
page.append("\n\n")
with open(f"docs/lib/{self.name}.md", "w") as w:
w.writelines(page)
excludedLibraries = [
"ai.a",
"aralt.a",
"arc.a",
"ax.a",
"axfx.a",
"base.a",
"bte.a",
"db.a",
"dsp.a",
"dvd.a",
"esp.a",
"euart.a",
"exi.a",
"fs.a",
"gd.a",
"gx.a",
"ipc.a",
"libnw4Fr_ut.a",
"libnw4r_db.a",
"libnw4r_lyt.a",
"libnw4r_math.a",
"libnw4r_ut.a",
"MSL_C.PPCEABI.bare.H.a",
"mem.a",
"mtx.a",
"nand.a",
"net.a",
"nwc24.a",
"NWC24.a",
"os.a",
"pad.a",
"rso.a",
"Runtime.PPCEABI.H.a",
"RVLFaceLib.a",
"sc.a",
"si.a",
"thp.a",
"tpl.a",
"TRK_Hollywood_Revolution.a",
"usb.a",
"vf.a",
"vi.a",
"wenc.a",
"wpad.a",
"wud.a",
"JAudio2.a",
"JKernel.a",
"JSupport.a",
"JGadget.a",
"JUtility.a",
"J2DGraph.a",
"J3DGraphBase.a",
"J3DGraphAnimator.a",
"J3DGraphLoader.a",
"JMath.a",
"JParticle.a",
"NdevExi2A.a"
]
lib_percent_colors = {
"Animation": "brightgreen",
"AreaObj": "green",
"AudioLib": "yellow",
"Boss": "orange",
"Camera": "red",
"Demo": "D65076",
"Effect": "pink",
"Enemy": "magenta",
"GameAudio": "teal",
"Gravity": "maroon",
"LiveActor": "cyan",
"Map": "silver",
"MapObj": "tan",
"NameObj": "indigo",
"NPC": "7fffd4",
"Player": "ff7f50",
"RhythmLib": "088da5",
"Ride": "ffff66",
"Scene": "a0db8e",
"Screen": "ff4040",
"Speaker": "daa520",
"System": "696969",
"Util": "ff6666"
}
func_sizes = {}
# start by reading function sizes
with open("data/funcSizes.txt", "r") as file:
lines = file.readlines()
for line in lines:
spl = line.split('=')
sym = spl[0]
func_sizes[sym] = spl[1].split(',', 1)[1]
csv_files = glob.glob("csv/*.csv")
for csv_file in csv_files:
lib_name = Path(csv_file).stem
lib_arch_name = Path(csv_file).stem + ".a"
# we are just going to ignore non-SMG libraries
if lib_arch_name not in excludedLibraries:
library = Library(lib_name)
with open(csv_file, "r") as c:
csv_reader = csv.reader(c)
for row in csv_reader:
symbol = row[0]
symbol = symbol.replace("&#44;", ",")
if symbol == "Symbol Name":
continue
obj = row[1]
lib = row[2]
done = row[3] == "true"
funcSize = int(func_sizes[symbol].strip("\n"))
func = Function(symbol, done, funcSize)
obj = Object(obj)
library.addFunctionToObject(obj, func)
libraries[lib_name] = library
fullSize = 0
doneSize = 0
print("Calculating percentages...")
for key in libraries:
lib = libraries[key]
d, f = lib.calculateProgress()
fullSize += f
doneSize += d
lib.generateJSONTag((d / f ) * 100.0, lib_percent_colors[lib.getName()])
progPercent = (doneSize / fullSize ) * 100.0
progNonPercent = int((doneSize / fullSize) * 120.0)
print(f"Progress: {progPercent}% [{doneSize} / {fullSize}] bytes")
print(f"You currently have {progNonPercent} / 120 stars.")
print("Generating JSON...")
json = []
json.append("{\n")
json.append("\t\"schemaVersion\": 1,\n")
json.append("\t\"label\": \"decompiled\",\n")
json.append(f"\t\"message\": \"{progPercent}%\",\n")
json.append("\t\"color\": \"blue\"\n")
json.append("}")
with open("data/percent.json", "w") as w:
w.writelines(json)
print("Generating markdown pages...")
# now we generate our progress page
progressPage = []
progressPage.append("| Library | Percentage |\n")
progressPage.append("| ------------- | ------------- |\n")
for key in libraries:
lib = libraries[key]
d, f = lib.calculateProgress()
libprog = (d / f) * 100.0
progressPage.append(f"| [{key}](https://github.com/shibbo/Petari/blob/master/docs/lib/{key}.md) | {libprog}% |\n")
with open("docs/PROGRESS.md", "w") as w:
w.writelines(progressPage)
# now we write the progress page for each library
for key in libraries:
lib = libraries[key]
lib.generateMarkdown()
print("Done.")

17
sanity_check.py Normal file
View File

@ -0,0 +1,17 @@
import os
import pathlib
error_count = 0
for path, subdirs, files in os.walk(pathlib.Path("include")):
for file_name in files:
full_name = os.path.join(path, file_name)
with open(full_name, "r") as input:
first_line = input.readline().rstrip()
if first_line != "#pragma once":
print(f"ERROR: Missing pragma once in {full_name}")
error_count += 1
print(f"Check finished with {error_count} error(s).")

66
setup.py Normal file
View File

@ -0,0 +1,66 @@
# setup.py -- by shibboleet
# Allows for the easy setup of Petari and its dependencies
import zipfile
import urllib.request
import os
import sys
import subprocess
def install(what):
subprocess.check_call([sys.executable, '-m', 'pip', 'install', what])
if not os.path.exists("baserom.dol"):
print("baserom.dol does not exist. Place a SMG1 dol named baserom.dol in the root.")
sys.exit(1)
else:
print("Found baserom.dol...")
try:
import capstone
print("Found capstone, continuing...")
except ModuleNotFoundError:
print("Module 'capstone' not installed. Installing...")
install("capstone")
try:
import elftools
print("Found elftools, continuing...")
except ModuleNotFoundError:
print("Module `elftools` not found. Installing...")
install("pyelftools")
try:
import ninja
print("Found ninja, continuing...")
except ModuleNotFoundError:
print("Module 'ninja' not found. Installing...")
install("ninja")
try:
import colorama
print("Found colorama, continuing...")
except ModuleNotFoundError:
print("Module 'colorama' not found. Installing...")
install("colorama")
if not os.path.exists("deps"):
print("Dependency folder not found, downloading...")
with urllib.request.urlopen("http://shibbo.net/smg/deps.zip") as response, open("deps.zip", 'wb') as out:
data = response.read()
out.write(data)
if os.path.exists("deps.zip"):
os.mkdir("deps")
print("Extracting file...")
with zipfile.ZipFile("deps.zip", "r") as zip:
zip.extractall("deps")
os.remove("deps.zip")
else:
print("deps.zip failed to download.")
sys.exit(1)
print("Done.")
sys.exit(1)

View File

@ -1,16 +1,7 @@
#include <JSystem/JMath/JMath.h>
#include "JSystem/JMath/JMath.h"
namespace JMath {
TRandom_fast_::TRandom_fast_(u32 num = 0) {
random = num;
}
u32 TRandom_fast_::get() {
seed = (seed * 0x19660d) + 0x3c6ef35f;
return seed;
}
void TRandom_fast_::setSeed(u32 Seed) {
seed = Seed;
TRandom_fast_::TRandom_fast_(u32 num) {
seed = num;
}
}

View File

@ -0,0 +1,152 @@
#include "JSystem/JSupport/JSUList.h"
JSUPtrLink::JSUPtrLink(void *pData) {
mData = pData;
mPtrList = 0;
mPrev = 0;
mNext = 0;
}
JSUPtrLink::~JSUPtrLink() {
if (mPtrList) {
mPtrList->remove(this);
}
}
JSUPtrList::JSUPtrList(bool doInitialize) {
if (doInitialize) {
initiate();
}
}
JSUPtrList::~JSUPtrList() {
JSUPtrLink* curHead = mHead;
for (int i = 0; i < mNodeCount; i++) {
curHead->mPtrList = 0;
curHead = curHead->mNext;
}
}
void JSUPtrList::initiate() {
mHead = 0;
mTail = 0;
mNodeCount = 0;
}
void JSUPtrList::setFirst(JSUPtrLink *pLink) {
pLink->mPtrList = this;
pLink->mPrev = 0;
pLink->mNext = 0;
mTail = pLink;
mHead = pLink;
mNodeCount = 1;
}
bool JSUPtrList::append(JSUPtrLink *pLink) {
bool validity = (pLink->mPtrList == 0);
if (!validity) {
validity = pLink->mPtrList->remove(pLink);
}
if (validity) {
if (!mNodeCount) {
setFirst(pLink);
}
else {
pLink->mPtrList = this;
pLink->mPrev = mTail;
pLink->mNext = 0;
mTail->mNext = pLink;
mTail = pLink;
mNodeCount = mNodeCount + 1;
}
}
return validity;
}
bool JSUPtrList::prepend(JSUPtrLink *pLink) {
bool validity = (pLink->mPtrList == 0);
if (!validity) {
validity = pLink->mPtrList->remove(pLink);
}
if (validity) {
if (!mNodeCount) {
setFirst(pLink);
}
else {
pLink->mPtrList = this;
pLink->mPrev = 0;
pLink->mNext = mHead;
mHead->mPrev = pLink;
mHead = pLink;
mNodeCount = mNodeCount + 1;
}
}
return validity;
}
bool JSUPtrList::insert(JSUPtrLink *pLink_1, JSUPtrLink *pLink_2) {
if (pLink_1 == mHead) {
return prepend(pLink_2);
}
if (!pLink_1) {
return append(pLink_2);
}
if (pLink_1->mPtrList != this) {
return false;
}
JSUPtrList* link2PtrList = pLink_2->mPtrList;
bool validity = (link2PtrList == 0);
if (!validity) {
validity = link2PtrList->remove(pLink_2);
}
if (validity) {
JSUPtrLink* prev = pLink_1->mPrev;
pLink_2->mPtrList = this;
pLink_2->mPrev = prev;
pLink_2->mNext = pLink_1;
prev->mNext = pLink_2;
pLink_1->mPrev = pLink_2;
mNodeCount++;
}
return validity;
}
bool JSUPtrList::remove(JSUPtrLink *pLink) {
bool isSameList = (pLink->mPtrList == this);
if (isSameList) {
if (mNodeCount == 1) {
mHead = 0;
mTail = 0;
}
else if (pLink == mHead) {
pLink->mNext->mPrev = 0;
mHead = pLink->mNext;
}
else if (pLink == mTail) {
pLink->mPrev->mNext = 0;
mTail = pLink->mPrev;
}
else {
pLink->mPrev->mNext = pLink->mNext;
pLink->mNext->mPrev = pLink->mPrev;
}
pLink->mPtrList = 0;
mNodeCount--;
}
return isSameList;
}

View File

@ -1,71 +0,0 @@
#ifndef KARTCHECKER_H
#define KARTCHECKER_H
#include <types.h>
#include <JSystem/JGeometry.h>
#include "KartInfo.h"
#include "RaceTime.h"
//#include "JugemPoint.h"
//#include "Course.h"
//#include "KartGamePad"
class KartChecker {
public:
KartChecker(int, KartInfo *, int, int);
//void setPlayerKartColor(KartInfo *);
private:
u16 raceFlags;
s16 kartIndex;
s32 sectorCount;
s32 bitfieldCnt;
s32 trackLapCount;
s32 _0x10; // i think this stores the index of the fastest lap
RaceTime* laptimes1;
RaceTime* laptimes2;
s32 playerKartColor;
void* kartGamePad1;
void* kartGamePad2;
bool showLapSplit;
bool raceEnd;
u8 _0x2a; // only seems to get set in the constructor
u8 _0x2b; // probably padding
s32 lapIndex;
f32 sectorProgression;
s32 warpState;
s32 _0x38;
s32 sectorIndex;
Course::Sector * sector1;
Course::Sector * sector2;
f32 lapProgession;
f32 prevlapProgession;
f32 lapProgression2; // might be max Lap Progression
f32 raceProgression;
s32* cpBitfields; // seems to store what checkpoint have been passed
TVec3<f32> curPos;
TVec3<f32> prevPos;
JugemPoint * jugemPoint;
bool _0x78; // true = in race | false = finished
u8 _0x79[3];
s32 curFrame;
s32 goalFrame;
RaceTime Timer;
s32 rank;
s16 battleFlags;
s16 _0x8e;
s16 balloonNumber;
u8 _0x92[2]; // this is probaby padding
RaceTime deathTime;
RaceTime markTime;
u8 _0x9c[010];
s16 bombPoint;
s16 rabbitWinFrame;
s32 demoPoint;
// these only get set in the constructor?
TVec3<f32> _0xb0;
s32 _0xbc;
};
#endif // !KARTCHECKER_H

View File

@ -1,4 +1,4 @@
#include "KartInfo.h"
#include "Kaneshige/KartInfo.h"
void KartInfo::reset() {

View File

@ -1,74 +0,0 @@
#ifndef KARTINFO_H
#define KARTINFO_H
#include <types.h>
enum EKartID {
RED_FIRE = 0,
DK_JUMBO = 1,
TURBO_YOSHI = 2,
KOOPA_DASHER = 3,
HEART_COACH = 4,
GOO_GOO_BUGGY = 5,
WARIO_CAR = 6,
KOOPA_KING = 7,
GREEN_FIRE = 8,
BARREL_TRAIN = 9,
TURBO_BIRDO = 10,
PARA_WING = 11,
BLOOM_COACH = 12,
RATTLE_BUGGY = 13,
WALUIGI_RACER = 14,
BULLET_BLASTER = 15,
TOAD_KART = 16,
TOADETTE_KART = 17,
BOO_PIPES = 18,
PIRANHA_PIPES = 19,
PARADE_KART = 20
};
class KartInfo {
public:
KartInfo();
~KartInfo();
void reset();
struct SCharDB
{
s16 id;
s16 defaultPartnerID;
s16 weight;
s16 defaultKartID;
u8 _8;
u8 _9[3]; // this is padding data most likely
};
struct SKartDB
{
EKartID id;
s32 weight;
s16 _08; // not sure if this is a short or 2 bytes
s8 _09;
s8 _0A; // probably padding
s16 defaultDriverID;
s8 _0E[2]; // padding bytes most likely
};
class KartCharacter {
public:
KartCharacter();
~KartCharacter();
private:
void* kartGamePad; // inherited from JUTGamePad
SCharDB* charDB;
};
private:
SKartDB * kartDB;
KartCharacter kartCharacter[2]; // one for the driver, other for the one doing nothing
s32 kartType; // if this is set to 1 this means the driver is a ghost, 2 is also used for ghost but for the pad that gets recorded, so that means 2 is invisible?
};
#endif // !KARTINFO_H

View File

@ -1,13 +1,15 @@
#include "RaceInfo.h"
#include "Kaneshige/RaceInfo.h"
#include "JSystem/JMath/JMath.h"
void RaceInfo::reset() {
isTinyProcess = false;
isLanMode = false;
isTrueEnding = false;
randomSeed = 0;
gpCup = -1;
raceMode = 0;
raceLevel = -1;
gpCup = INV_CUP;
raceMode = INV_MODE;
raceLevel = LVL_INV;
itemSlotType = 0;
vsLapNum = 0;
lapNumLAN = 0;
@ -17,10 +19,10 @@ void RaceInfo::reset() {
statusNum = 0;
lod = 0;
gpStageNo = 0;
_0x28 = 0;
inWaitDemo = 0;
isMirror = false;
_0x298 = 0;
hideConsole = 0;
HideConsole = 0;
for (s32 i = 0; i < 8; i++) {
kartInfo[i].reset();
@ -67,7 +69,7 @@ void RaceInfo::setRace(ERaceMode RaceMode, s32 kartCount, s32 playerCount, s32 c
}
void RaceInfo::setRaceLevel(ERaceLevel raceLvl) {
raceLevel = raceLvl;
this->raceLevel = raceLvl;
if (raceLvl == LVL_MIRROR)
isMirror = true;
else
@ -96,5 +98,5 @@ void RaceInfo::shuffleStartNo() {
}
void RaceInfo::hideConsole(u32 param_2) {
hideConsole = hideConsole | (u16)(1 << param_2);
HideConsole = HideConsole | (u16)(1 << param_2);
}

View File

@ -1,97 +0,0 @@
#ifndef RACEINFO_H
#define RACEINFO_H
#include <types.h>
#include <JSystem/JMath/JMath.h>
#include "KartInfo.h"
#include "RaceTime.h"
enum ERaceMode {
TIME_ATTACK = 0x1,
GRAND_PRIX = 0x2,
VERSUS_RACE = 0x3,
BALLOON_BATTLE = 0x4,
ROBBERY_BATTLE = 0x5,
BOMB_BATTLE = 0x6,
ESCAPE_BATTLE = 0x7,
AWARD_DEMO = 0x8,
STAFF_ROLL = 0x9,
};
enum ERaceLevel { // unsure of this
LVL_INV = -1,
LVL_50CC = 0,
LVL_100CC = 1,
LVL_150CC = 2,
LVL_MIRROR = 3,
};
enum ERaceGpCup {
MUSHROOM_CUP = 0,
FLOWER_CUP = 1,
STAR_CUP = 2,
SPECIAL_CUP = 3,
REVERSE2_CUP = 4,
};
class RaceInfo {
public:
inline RaceInfo(); // this is not inlined in the debug version
~RaceInfo();
void reset();
void setConsoleTarget(s32 idx, s16 p2, bool p3);
void setRace(ERaceMode RaceMode, s32 kartCount, s32 playerCount, s32 consoleCount, s32 p5);
void setRaceLevel(ERaceLevel);
void shuffleRandomSeed();
void shuffleStartNo();
void hideConsole(u32 param_2);
s16 getKartNumber() {
return kartNum;
}
private:
bool isTinyProcess;
bool isLanMode;
bool isTrueEnding;
u32 randomSeed;
ERaceMode raceMode;
ERaceGpCup gpCup;
ERaceLevel raceLevel;
s32 itemSlotType; // perhaps this is an enum too
s16 vsLapNum;
s16 lapNumLAN;
s16 kartNum;
s16 playerNum;
s16 consoleNum;
s16 statusNum;
u16 lod;
s16 gpStageNo;
s32 inWaitDemo;
bool isMirror;
// padding bytes
KartInfo kartInfo[8];
s16 startPosIndex[8];
s16 pointTable[8];
s16 rivalKarts[2];
s16 _0x114[4];
bool _0x11c[4]; // not sure what these two arrays do, setConsoleTarget sets this so maybe this bool array means isActive and the other the console number
s16 awardKartNo;
// padding bytes
s32 demoNextPhase;
s16 rank[8]; // stores what rank you finished at previous race, basically the same as startPosIndex
RaceTime finishTime[8];
RaceTime lapTimes[80]; // 10 per player so perhaps it's lapTimes[8][10] or lapTimes[10][8](why do i not know how arrays work)
s32 _0x298;
s16 hideConsole;
s8 _0x29e[0x2e0 - 0x29e]; // unknown
};
RaceInfo gRaceInfo;
#endif // !RACEINFO_H

View File

@ -1,70 +0,0 @@
#ifndef RACEMGR_H
#define RACEMGR_H
#include <types.h>
#include <JSystem/JKernel/JKRDisposer.h>
#include <JSystem/JKernel/JKRHeap.h>
#include "RaceInfo.h"
#include "RaceTime.h"
#include "KartChecker.h"
class RaceMgr : JKRDisposer {
public:
RaceMgr(RaceInfo *);
virtual ~RaceMgr();
static RaceMgr * sRaceManager;
static s16 sForceTotalLapNum;
static s16 sDispFrameCounter;
static s16 sMyStartPointID;
class Console {
public:
Console();
void changeTargetNo(s32, bool);
private:
s32 _0x0;
u8 _0x4;
s32 _0x8;
u16 _0xc;
};
private:
RaceDirector * raceDirector;
RaceDrawer * raceDrawer;
u16 areaLight;
u8 _0x22;
u8 _0x23; // probably padding
u32 frame;
JKRHeap * raceHeap;
s16 replayMode;
s16 totalLapNumber;
s32 _0x30;
bool _0x31;
RaceInfo * raceInfo;
RaceBGMPlayer * raceBGMPlayer;
Console * console;
Course * course;
KartChecker * kartChecker[8];
KartLoader * kartLoader[8];
StaffRoll2D * staffRoll2D;
RaceTime bestLapTime;
RaceTime bestTotalTime[5];
s16 events;
// these values store the amount of time/frames it took to execute a certain set of functions
// 0x0 GX Issue
// 0x100 Calc
// 0x200 update
// 0x300 ViewCalc
s16 proctime1;
s16 proctime2;
s16 proctime3;
s16 proctime4;
};
#endif // RACEMGR_H

View File

@ -1,4 +1,4 @@
#include "RaceTime.h"
#include "Kaneshige/RaceTime.h"
#define MAX_TIME 5999999
#define MAX_MS 999
@ -68,7 +68,7 @@ void RaceTime::sub(const RaceTime & split1, const RaceTime & split2) {
}
void RaceTime::sub(int p1) {
time -= p1;
time = time - p1;
}
void RaceTime::zero() {

View File

@ -1,32 +0,0 @@
#ifndef RACETIME_H
#define RACETIME_H
#include <types.h>
class RaceTime
{
public:
inline RaceTime();
//inline RaceTime(RaceTime const &);
//inline void operator=(const RaceTime &);
inline void reset();
inline void zero();
inline void set(int);
inline void set(RaceTime const &);
inline bool isAvailable();
inline bool isLittle(const RaceTime &) const;
inline void sub(const RaceTime &, const RaceTime &);
inline int get() const;
inline int sub(int);
inline void setFrame(int);
inline int getUpwardMSec() const;
void get(int *, int *, int *) const;
private:
int time;
};
#endif

Some files were not shown because too many files have changed in this diff Show More