mirror of
https://github.com/MonsterDruide1/OdysseyDecomp.git
synced 2024-11-26 23:00:25 +00:00
Moving structure to system as zeldaret/botw
Co-authored-by: leoetlino <leo@leolam.fr>
This commit is contained in:
parent
122e4b2f33
commit
72b3d5cdce
34
.gitignore
vendored
34
.gitignore
vendored
@ -1,15 +1,31 @@
|
||||
*.o
|
||||
*.vscode
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.egg-info/
|
||||
*.dist-info/
|
||||
*.so
|
||||
*.dll
|
||||
dist/
|
||||
build/
|
||||
bin/
|
||||
.mypy_cache/
|
||||
.benchmarks/
|
||||
|
||||
# ignore compiled files
|
||||
build
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
# ignore the actual compiler
|
||||
compiler
|
||||
|
||||
# IDA Files
|
||||
*.id0
|
||||
*.id1
|
||||
*.id2
|
||||
*.idb
|
||||
*.i64
|
||||
*.nam
|
||||
*.til
|
||||
*.til
|
||||
|
||||
main.elf
|
||||
|
||||
perf.mData
|
||||
perf.mData.old
|
||||
.gdb_history
|
||||
|
||||
.DS_Store
|
||||
tools/aarch64-none-elf-objdump
|
31
CMakeLists.txt
Normal file
31
CMakeLists.txt
Normal file
@ -0,0 +1,31 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(odyssey CXX)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_NINJA_FORCE_RESPONSE_FILE ON)
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
add_compile_options(-fdiagnostics-color=always)
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
add_compile_options(-fcolor-diagnostics)
|
||||
# Required to silence "unused argument" warnings for -stdlib=libc++ when using distcc
|
||||
add_compile_options(-Wno-unused-command-line-argument)
|
||||
# Required to fix source paths in debug info when using distcc
|
||||
add_compile_options(-fdebug-prefix-map=/tmp=${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
add_executable(odyssey)
|
||||
target_include_directories(odyssey PRIVATE src)
|
||||
target_compile_options(odyssey PRIVATE -fno-rtti -fno-exceptions)
|
||||
target_compile_options(odyssey PRIVATE -Wall -Wextra -Wdeprecated)
|
||||
target_compile_options(odyssey PRIVATE -Wno-unused-parameter -Wno-unused-private-field)
|
||||
target_compile_options(odyssey PRIVATE -fno-strict-aliasing)
|
||||
target_compile_options(odyssey PRIVATE -Wno-invalid-offsetof)
|
||||
|
||||
add_subdirectory(src)
|
||||
include_directories(include)
|
||||
include_directories(include/aarch64)
|
||||
include_directories(include/sead)
|
46
ToolchainNX64.cmake
Normal file
46
ToolchainNX64.cmake
Normal file
@ -0,0 +1,46 @@
|
||||
if (NOT DEFINED ENV{UKING_CLANG})
|
||||
message(FATAL_ERROR "Please define the UKING_CLANG env variable. It should point to a path such that $UKING_CLANG/bin/clang exists")
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ENV{DEVKITA64})
|
||||
message(FATAL_ERROR "Please define the DEVKITA64 env variable.")
|
||||
endif()
|
||||
|
||||
set(UKING_CLANG "$ENV{UKING_CLANG}")
|
||||
set(DEVKITA64 "$ENV{DEVKITA64}")
|
||||
set(NX64_OPT_FLAGS "-O3 -g")
|
||||
set(triple aarch64-none-elf)
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Generic)
|
||||
set(CMAKE_SYSTEM_VERSION 1)
|
||||
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
||||
|
||||
set(CMAKE_SYSROOT ${UKING_CLANG})
|
||||
set(CMAKE_C_COMPILER "${UKING_CLANG}/bin/clang")
|
||||
set(CMAKE_C_COMPILER_TARGET ${triple})
|
||||
set(CMAKE_CXX_COMPILER "${UKING_CLANG}/bin/clang++")
|
||||
set(CMAKE_CXX_COMPILER_TARGET ${triple})
|
||||
|
||||
set(CMAKE_C_FLAGS_RELEASE ${NX64_OPT_FLAGS})
|
||||
set(CMAKE_CXX_FLAGS_RELEASE ${NX64_OPT_FLAGS})
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO ${NX64_OPT_FLAGS})
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO ${NX64_OPT_FLAGS})
|
||||
|
||||
set(ARCH "-mcpu=cortex-a57+fp+simd+crypto+crc")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ARCH} -isystem ${DEVKITA64}/aarch64-none-elf/include")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${UKING_CLANG}/include/c++/v1 -D _LIBCPP_HAS_THREAD_API_PTHREAD ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -x assembler-with-cpp ${ARCH}")
|
||||
|
||||
add_compile_options(-fPIC -stdlib=libc++ -mno-implicit-float)
|
||||
add_link_options(-B ${DEVKITA64}/bin -fPIC -Wl,-Bsymbolic-functions -shared -nodefaultlibs)
|
||||
if(EXISTS "${DEVKITA64}/bin/ld.lld")
|
||||
add_link_options(-fuse-ld=lld -Wl,-z,notext)
|
||||
endif()
|
||||
add_definitions(-D SWITCH -D __DEVKITA64__ -D __ELF__)
|
||||
add_definitions(-D NNSDK)
|
||||
add_definitions(-D MATCHING_HACK_NX_CLANG)
|
||||
add_definitions(-D VER_100)
|
||||
|
||||
# Helps with matching as this causes Clang to emit debug type info even for dynamic classes
|
||||
# with undefined vtables.
|
||||
add_compile_options(-fstandalone-debug)
|
BIN
__pycache__/diff_settings.cpython-38.pyc
Normal file
BIN
__pycache__/diff_settings.cpython-38.pyc
Normal file
Binary file not shown.
0
compile.bat
Normal file → Executable file
0
compile.bat
Normal file → Executable file
12
compile.py
Normal file → Executable file
12
compile.py
Normal file → Executable file
@ -11,21 +11,21 @@ gameVersion = versions[int(sys.argv[1])]
|
||||
# todo -- 1.3.0 uses a different optimization method, find it
|
||||
optimziation = "-O3"
|
||||
|
||||
root = pathlib.Path("compiler")
|
||||
compilerPath = root / "nx/aarch64/bin/clang++.exe"
|
||||
compilerPath = "../clang-4.0.1/bin/clang++"
|
||||
compilerCommand = f"{compilerPath} -x c++ -w -std=gnu++14 -fno-strict-aliasing -fno-exceptions -fno-common -fno-short-enums -ffunction-sections -fdata-sections -fPIC -DNN_NINTENDO_SDK -DNN_SDK_BUILD_RELEASE -D{gameVersion} -DNNSDK {optimziation} -fomit-frame-pointer -mcpu=cortex-a57+fp+simd+crypto+crc -g -I include -I include/sead -I compiler/nx/aarch64/include -c "
|
||||
|
||||
source_folder = pathlib.Path('source/')
|
||||
source_folder = pathlib.Path('src/')
|
||||
cpp_files = list(source_folder.rglob('*.cpp'))
|
||||
|
||||
for cpp_file in cpp_files:
|
||||
compilerCommand += str(cpp_file) + " "
|
||||
|
||||
if subprocess.call(compilerCommand) == 1:
|
||||
|
||||
if subprocess.call(compilerCommand, shell=True) == 1:
|
||||
sys.exit(1)
|
||||
|
||||
# this all assumes that the user doesn't have a single build folder
|
||||
if not os.path.isdir("build/VER_100"):
|
||||
os.mkdir("build")
|
||||
os.mkdir("build/VER_100")
|
||||
os.mkdir("build/VER_110")
|
||||
os.mkdir("build/VER_120")
|
||||
@ -41,4 +41,4 @@ for o_file in o_files:
|
||||
shutil.copy(o_file, buildDir)
|
||||
os.remove(o_file)
|
||||
|
||||
print("Done.")
|
||||
print("Done.")
|
||||
|
499
data/data_symbols.csv
Executable file
499
data/data_symbols.csv
Executable file
@ -0,0 +1,499 @@
|
||||
0x00000071023556B0,_ZTVN4sead14SafeStringBaseIcEE
|
||||
0x0000007102356AF0,_ZTVN4sead22BufferedSafeStringBaseIcEE
|
||||
0x000000710246F9E0,_ZN4ksys3gdt6detail13sCommonFlags0E
|
||||
0x00000071024709E0,_ZN4ksys3gdt6detail13sCommonFlags1E
|
||||
0x00000071024719E0,_ZN4ksys3gdt6detail13sCommonFlags2E
|
||||
0x00000071024729E0,_ZN4ksys3gdt6detail13sCommonFlags3E
|
||||
0x00000071024C0F18,_ZTVN3agl3utl13ParameterBaseE
|
||||
0x00000071024C1060,_ZTVN3agl3utl9ParameterIbEE
|
||||
0x00000071024C1100,_ZTVN3agl3utl9ParameterIfEE
|
||||
0x00000071024C11A0,_ZTVN3agl3utl9ParameterIiEE
|
||||
0x00000071024C1240,_ZTVN3agl3utl9ParameterIjEE
|
||||
0x00000071024C12E0,_ZTVN3agl3utl9ParameterIN4sead7Vector2IfEEEE
|
||||
0x00000071024C1380,_ZTVN3agl3utl9ParameterIN4sead7Vector3IfEEEE
|
||||
0x00000071024C1420,_ZTVN3agl3utl9ParameterIN4sead7Vector4IfEEEE
|
||||
0x00000071024C14C0,_ZTVN3agl3utl9ParameterIN4sead7Color4fEEE
|
||||
0x00000071024C1560,_ZTVN3agl3utl9ParameterIN4sead4QuatIfEEEE
|
||||
0x00000071024C1600,_ZTVN3agl3utl9ParameterIN4sead15FixedSafeStringILi64EEEEE
|
||||
0x00000071024C16A0,_ZTVN3agl3utl9ParameterIN4sead15FixedSafeStringILi256EEEEE
|
||||
0x00000071024C1740,_ZTVN3agl3utl9ParameterIN4sead14SafeStringBaseIcEEEE
|
||||
0x00000071024D8D58,_ZTVN4ksys3act2ai10ActionBaseE
|
||||
0x00000071025129E0,_ZTVN4ksys3act2ai6ActionE
|
||||
0x0000007102513268,_ZTVN4ksys3act2ai2AiE
|
||||
0x00000071025F75B0,pfnc_nvnDeviceBuilderSetDefaults
|
||||
0x00000071025F75B8,pfnc_nvnDeviceBuilderSetFlags
|
||||
0x00000071025F75C0,pfnc_nvnDeviceInitialize
|
||||
0x00000071025F75C8,pfnc_nvnDeviceFinalize
|
||||
0x00000071025F75D0,pfnc_nvnDeviceSetDebugLabel
|
||||
0x00000071025F75D8,pfnc_nvnDeviceGetProcAddress
|
||||
0x00000071025F75E0,pfnc_nvnDeviceGetInteger
|
||||
0x00000071025F75E8,pfnc_nvnDeviceGetCurrentTimestampInNanoseconds
|
||||
0x00000071025F75F0,pfnc_nvnDeviceSetIntermediateShaderCache
|
||||
0x00000071025F75F8,pfnc_nvnDeviceGetTextureHandle
|
||||
0x00000071025F7600,pfnc_nvnDeviceGetTexelFetchHandle
|
||||
0x00000071025F7608,pfnc_nvnDeviceGetImageHandle
|
||||
0x00000071025F7610,pfnc_nvnDeviceInstallDebugCallback
|
||||
0x00000071025F7618,pfnc_nvnDeviceGenerateDebugDomainId
|
||||
0x00000071025F7620,pfnc_nvnDeviceSetWindowOriginMode
|
||||
0x00000071025F7628,pfnc_nvnDeviceSetDepthMode
|
||||
0x00000071025F7630,pfnc_nvnDeviceRegisterFastClearColor
|
||||
0x00000071025F7638,pfnc_nvnDeviceRegisterFastClearColori
|
||||
0x00000071025F7640,pfnc_nvnDeviceRegisterFastClearColorui
|
||||
0x00000071025F7648,pfnc_nvnDeviceRegisterFastClearDepth
|
||||
0x00000071025F7650,pfnc_nvnDeviceGetWindowOriginMode
|
||||
0x00000071025F7658,pfnc_nvnDeviceGetDepthMode
|
||||
0x00000071025F7660,pfnc_nvnDeviceGetTimestampInNanoseconds
|
||||
0x00000071025F7668,pfnc_nvnDeviceApplyDeferredFinalizes
|
||||
0x00000071025F7670,pfnc_nvnDeviceFinalizeCommandHandle
|
||||
0x00000071025F7678,pfnc_nvnDeviceWalkDebugDatabase
|
||||
0x00000071025F7680,pfnc_nvnDeviceGetSeparateTextureHandle
|
||||
0x00000071025F7688,pfnc_nvnDeviceGetSeparateSamplerHandle
|
||||
0x00000071025F7690,pfnc_nvnDeviceIsExternalDebuggerAttached
|
||||
0x00000071025F7698,pfnc_nvnQueueGetError
|
||||
0x00000071025F76A0,pfnc_nvnQueueGetTotalCommandMemoryUsed
|
||||
0x00000071025F76A8,pfnc_nvnQueueGetTotalControlMemoryUsed
|
||||
0x00000071025F76B0,pfnc_nvnQueueGetTotalComputeMemoryUsed
|
||||
0x00000071025F76B8,pfnc_nvnQueueResetMemoryUsageCounts
|
||||
0x00000071025F76C0,pfnc_nvnQueueBuilderSetDevice
|
||||
0x00000071025F76C8,pfnc_nvnQueueBuilderSetDefaults
|
||||
0x00000071025F76D0,pfnc_nvnQueueBuilderSetFlags
|
||||
0x00000071025F76D8,pfnc_nvnQueueBuilderSetCommandMemorySize
|
||||
0x00000071025F76E0,pfnc_nvnQueueBuilderSetComputeMemorySize
|
||||
0x00000071025F76E8,pfnc_nvnQueueBuilderSetControlMemorySize
|
||||
0x00000071025F76F0,pfnc_nvnQueueBuilderGetQueueMemorySize
|
||||
0x00000071025F76F8,pfnc_nvnQueueBuilderSetQueueMemory
|
||||
0x00000071025F7700,pfnc_nvnQueueBuilderSetCommandFlushThreshold
|
||||
0x00000071025F7708,pfnc_nvnQueueInitialize
|
||||
0x00000071025F7710,pfnc_nvnQueueFinalize
|
||||
0x00000071025F7718,pfnc_nvnQueueSetDebugLabel
|
||||
0x00000071025F7720,pfnc_nvnQueueSubmitCommands
|
||||
0x00000071025F7728,pfnc_nvnQueueFlush
|
||||
0x00000071025F7730,pfnc_nvnQueueFinish
|
||||
0x00000071025F7738,pfnc_nvnQueuePresentTexture
|
||||
0x00000071025F7740,pfnc_nvnQueueAcquireTexture
|
||||
0x00000071025F7748,pfnc_nvnWindowBuilderSetDevice
|
||||
0x00000071025F7750,pfnc_nvnWindowBuilderSetDefaults
|
||||
0x00000071025F7758,pfnc_nvnWindowBuilderSetNativeWindow
|
||||
0x00000071025F7760,pfnc_nvnWindowBuilderSetTextures
|
||||
0x00000071025F7768,pfnc_nvnWindowBuilderSetPresentInterval
|
||||
0x00000071025F7770,pfnc_nvnWindowBuilderGetNativeWindow
|
||||
0x00000071025F7778,pfnc_nvnWindowBuilderGetPresentInterval
|
||||
0x00000071025F7780,pfnc_nvnWindowInitialize
|
||||
0x00000071025F7788,pfnc_nvnWindowFinalize
|
||||
0x00000071025F7790,pfnc_nvnWindowSetDebugLabel
|
||||
0x00000071025F7798,pfnc_nvnWindowAcquireTexture
|
||||
0x00000071025F77A0,pfnc_nvnWindowGetNativeWindow
|
||||
0x00000071025F77A8,pfnc_nvnWindowGetPresentInterval
|
||||
0x00000071025F77B0,pfnc_nvnWindowSetPresentInterval
|
||||
0x00000071025F77B8,pfnc_nvnWindowSetCrop
|
||||
0x00000071025F77C0,pfnc_nvnWindowGetCrop
|
||||
0x00000071025F77C8,pfnc_nvnProgramInitialize
|
||||
0x00000071025F77D0,pfnc_nvnProgramFinalize
|
||||
0x00000071025F77D8,pfnc_nvnProgramSetDebugLabel
|
||||
0x00000071025F77E0,pfnc_nvnProgramSetShaders
|
||||
0x00000071025F77E8,pfnc_nvnMemoryPoolBuilderSetDevice
|
||||
0x00000071025F77F0,pfnc_nvnMemoryPoolBuilderSetDefaults
|
||||
0x00000071025F77F8,pfnc_nvnMemoryPoolBuilderSetStorage
|
||||
0x00000071025F7800,pfnc_nvnMemoryPoolBuilderSetFlags
|
||||
0x00000071025F7808,pfnc_nvnMemoryPoolBuilderGetMemory
|
||||
0x00000071025F7810,pfnc_nvnMemoryPoolBuilderGetSize
|
||||
0x00000071025F7818,pfnc_nvnMemoryPoolBuilderGetFlags
|
||||
0x00000071025F7820,pfnc_nvnMemoryPoolInitialize
|
||||
0x00000071025F7828,pfnc_nvnMemoryPoolSetDebugLabel
|
||||
0x00000071025F7830,pfnc_nvnMemoryPoolFinalize
|
||||
0x00000071025F7838,pfnc_nvnMemoryPoolMap
|
||||
0x00000071025F7840,pfnc_nvnMemoryPoolFlushMappedRange
|
||||
0x00000071025F7848,pfnc_nvnMemoryPoolInvalidateMappedRange
|
||||
0x00000071025F7850,pfnc_nvnMemoryPoolGetBufferAddress
|
||||
0x00000071025F7858,pfnc_nvnMemoryPoolMapVirtual
|
||||
0x00000071025F7860,pfnc_nvnMemoryPoolGetSize
|
||||
0x00000071025F7868,pfnc_nvnMemoryPoolGetFlags
|
||||
0x00000071025F7870,pfnc_nvnTexturePoolInitialize
|
||||
0x00000071025F7878,pfnc_nvnTexturePoolSetDebugLabel
|
||||
0x00000071025F7880,pfnc_nvnTexturePoolFinalize
|
||||
0x00000071025F7888,pfnc_nvnTexturePoolRegisterTexture
|
||||
0x00000071025F7890,pfnc_nvnTexturePoolRegisterImage
|
||||
0x00000071025F7898,pfnc_nvnTexturePoolGetMemoryPool
|
||||
0x00000071025F78A0,pfnc_nvnTexturePoolGetMemoryOffset
|
||||
0x00000071025F78A8,pfnc_nvnTexturePoolGetSize
|
||||
0x00000071025F78B0,pfnc_nvnSamplerPoolInitialize
|
||||
0x00000071025F78B8,pfnc_nvnSamplerPoolSetDebugLabel
|
||||
0x00000071025F78C0,pfnc_nvnSamplerPoolFinalize
|
||||
0x00000071025F78C8,pfnc_nvnSamplerPoolRegisterSampler
|
||||
0x00000071025F78D0,pfnc_nvnSamplerPoolRegisterSamplerBuilder
|
||||
0x00000071025F78D8,pfnc_nvnSamplerPoolGetMemoryPool
|
||||
0x00000071025F78E0,pfnc_nvnSamplerPoolGetMemoryOffset
|
||||
0x00000071025F78E8,pfnc_nvnSamplerPoolGetSize
|
||||
0x00000071025F78F0,pfnc_nvnBufferBuilderSetDevice
|
||||
0x00000071025F78F8,pfnc_nvnBufferBuilderSetDefaults
|
||||
0x00000071025F7900,pfnc_nvnBufferBuilderSetStorage
|
||||
0x00000071025F7908,pfnc_nvnBufferBuilderGetMemoryPool
|
||||
0x00000071025F7910,pfnc_nvnBufferBuilderGetMemoryOffset
|
||||
0x00000071025F7918,pfnc_nvnBufferBuilderGetSize
|
||||
0x00000071025F7920,pfnc_nvnBufferInitialize
|
||||
0x00000071025F7928,pfnc_nvnBufferSetDebugLabel
|
||||
0x00000071025F7930,pfnc_nvnBufferFinalize
|
||||
0x00000071025F7938,pfnc_nvnBufferMap
|
||||
0x00000071025F7940,pfnc_nvnBufferGetAddress
|
||||
0x00000071025F7948,pfnc_nvnBufferFlushMappedRange
|
||||
0x00000071025F7950,pfnc_nvnBufferInvalidateMappedRange
|
||||
0x00000071025F7958,pfnc_nvnBufferGetMemoryPool
|
||||
0x00000071025F7960,pfnc_nvnBufferGetMemoryOffset
|
||||
0x00000071025F7968,pfnc_nvnBufferGetSize
|
||||
0x00000071025F7970,pfnc_nvnBufferGetDebugID
|
||||
0x00000071025F7978,pfnc_nvnTextureBuilderSetDevice
|
||||
0x00000071025F7980,pfnc_nvnTextureBuilderSetDefaults
|
||||
0x00000071025F7988,pfnc_nvnTextureBuilderSetFlags
|
||||
0x00000071025F7990,pfnc_nvnTextureBuilderSetTarget
|
||||
0x00000071025F7998,pfnc_nvnTextureBuilderSetWidth
|
||||
0x00000071025F79A0,pfnc_nvnTextureBuilderSetHeight
|
||||
0x00000071025F79A8,pfnc_nvnTextureBuilderSetDepth
|
||||
0x00000071025F79B0,pfnc_nvnTextureBuilderSetSize1D
|
||||
0x00000071025F79B8,pfnc_nvnTextureBuilderSetSize2D
|
||||
0x00000071025F79C0,pfnc_nvnTextureBuilderSetSize3D
|
||||
0x00000071025F79C8,pfnc_nvnTextureBuilderSetLevels
|
||||
0x00000071025F79D0,pfnc_nvnTextureBuilderSetFormat
|
||||
0x00000071025F79D8,pfnc_nvnTextureBuilderSetSamples
|
||||
0x00000071025F79E0,pfnc_nvnTextureBuilderSetSwizzle
|
||||
0x00000071025F79E8,pfnc_nvnTextureBuilderSetDepthStencilMode
|
||||
0x00000071025F79F0,pfnc_nvnTextureBuilderGetStorageSize
|
||||
0x00000071025F79F8,pfnc_nvnTextureBuilderGetStorageAlignment
|
||||
0x00000071025F7A00,pfnc_nvnTextureBuilderSetStorage
|
||||
0x00000071025F7A08,pfnc_nvnTextureBuilderSetPackagedTextureData
|
||||
0x00000071025F7A10,pfnc_nvnTextureBuilderSetPackagedTextureLayout
|
||||
0x00000071025F7A18,pfnc_nvnTextureBuilderSetStride
|
||||
0x00000071025F7A20,pfnc_nvnTextureBuilderSetGLTextureName
|
||||
0x00000071025F7A28,pfnc_nvnTextureBuilderGetStorageClass
|
||||
0x00000071025F7A30,pfnc_nvnTextureBuilderGetFlags
|
||||
0x00000071025F7A38,pfnc_nvnTextureBuilderGetTarget
|
||||
0x00000071025F7A40,pfnc_nvnTextureBuilderGetWidth
|
||||
0x00000071025F7A48,pfnc_nvnTextureBuilderGetHeight
|
||||
0x00000071025F7A50,pfnc_nvnTextureBuilderGetDepth
|
||||
0x00000071025F7A58,pfnc_nvnTextureBuilderGetLevels
|
||||
0x00000071025F7A60,pfnc_nvnTextureBuilderGetFormat
|
||||
0x00000071025F7A68,pfnc_nvnTextureBuilderGetSamples
|
||||
0x00000071025F7A70,pfnc_nvnTextureBuilderGetSwizzle
|
||||
0x00000071025F7A78,pfnc_nvnTextureBuilderGetDepthStencilMode
|
||||
0x00000071025F7A80,pfnc_nvnTextureBuilderGetPackagedTextureData
|
||||
0x00000071025F7A88,pfnc_nvnTextureBuilderGetStride
|
||||
0x00000071025F7A90,pfnc_nvnTextureBuilderGetSparseTileLayout
|
||||
0x00000071025F7A98,pfnc_nvnTextureBuilderGetGLTextureName
|
||||
0x00000071025F7AA0,pfnc_nvnTextureBuilderGetZCullStorageSize
|
||||
0x00000071025F7AA8,pfnc_nvnTextureBuilderGetMemoryPool
|
||||
0x00000071025F7AB0,pfnc_nvnTextureBuilderGetMemoryOffset
|
||||
0x00000071025F7AB8,pfnc_nvnTextureViewSetDefaults
|
||||
0x00000071025F7AC0,pfnc_nvnTextureViewSetLevels
|
||||
0x00000071025F7AC8,pfnc_nvnTextureViewSetLayers
|
||||
0x00000071025F7AD0,pfnc_nvnTextureViewSetFormat
|
||||
0x00000071025F7AD8,pfnc_nvnTextureViewSetSwizzle
|
||||
0x00000071025F7AE0,pfnc_nvnTextureViewSetDepthStencilMode
|
||||
0x00000071025F7AE8,pfnc_nvnTextureViewSetTarget
|
||||
0x00000071025F7AF0,pfnc_nvnTextureViewGetLevels
|
||||
0x00000071025F7AF8,pfnc_nvnTextureViewGetLayers
|
||||
0x00000071025F7B00,pfnc_nvnTextureViewGetFormat
|
||||
0x00000071025F7B08,pfnc_nvnTextureViewGetSwizzle
|
||||
0x00000071025F7B10,pfnc_nvnTextureViewGetDepthStencilMode
|
||||
0x00000071025F7B18,pfnc_nvnTextureViewGetTarget
|
||||
0x00000071025F7B20,pfnc_nvnTextureViewCompare
|
||||
0x00000071025F7B28,pfnc_nvnTextureInitialize
|
||||
0x00000071025F7B30,pfnc_nvnTextureGetZCullStorageSize
|
||||
0x00000071025F7B38,pfnc_nvnTextureFinalize
|
||||
0x00000071025F7B40,pfnc_nvnTextureSetDebugLabel
|
||||
0x00000071025F7B48,pfnc_nvnTextureGetStorageClass
|
||||
0x00000071025F7B50,pfnc_nvnTextureGetViewOffset
|
||||
0x00000071025F7B58,pfnc_nvnTextureGetFlags
|
||||
0x00000071025F7B60,pfnc_nvnTextureGetTarget
|
||||
0x00000071025F7B68,pfnc_nvnTextureGetWidth
|
||||
0x00000071025F7B70,pfnc_nvnTextureGetHeight
|
||||
0x00000071025F7B78,pfnc_nvnTextureGetDepth
|
||||
0x00000071025F7B80,pfnc_nvnTextureGetLevels
|
||||
0x00000071025F7B88,pfnc_nvnTextureGetFormat
|
||||
0x00000071025F7B90,pfnc_nvnTextureGetSamples
|
||||
0x00000071025F7B98,pfnc_nvnTextureGetSwizzle
|
||||
0x00000071025F7BA0,pfnc_nvnTextureGetDepthStencilMode
|
||||
0x00000071025F7BA8,pfnc_nvnTextureGetStride
|
||||
0x00000071025F7BB0,pfnc_nvnTextureGetTextureAddress
|
||||
0x00000071025F7BB8,pfnc_nvnTextureGetSparseTileLayout
|
||||
0x00000071025F7BC0,pfnc_nvnTextureWriteTexels
|
||||
0x00000071025F7BC8,pfnc_nvnTextureWriteTexelsStrided
|
||||
0x00000071025F7BD0,pfnc_nvnTextureReadTexels
|
||||
0x00000071025F7BD8,pfnc_nvnTextureReadTexelsStrided
|
||||
0x00000071025F7BE0,pfnc_nvnTextureFlushTexels
|
||||
0x00000071025F7BE8,pfnc_nvnTextureInvalidateTexels
|
||||
0x00000071025F7BF0,pfnc_nvnTextureGetMemoryPool
|
||||
0x00000071025F7BF8,pfnc_nvnTextureGetMemoryOffset
|
||||
0x00000071025F7C00,pfnc_nvnTextureGetStorageSize
|
||||
0x00000071025F7C08,pfnc_nvnTextureCompare
|
||||
0x00000071025F7C10,pfnc_nvnTextureGetDebugID
|
||||
0x00000071025F7C18,pfnc_nvnSamplerBuilderSetDevice
|
||||
0x00000071025F7C20,pfnc_nvnSamplerBuilderSetDefaults
|
||||
0x00000071025F7C28,pfnc_nvnSamplerBuilderSetMinMagFilter
|
||||
0x00000071025F7C30,pfnc_nvnSamplerBuilderSetWrapMode
|
||||
0x00000071025F7C38,pfnc_nvnSamplerBuilderSetLodClamp
|
||||
0x00000071025F7C40,pfnc_nvnSamplerBuilderSetLodBias
|
||||
0x00000071025F7C48,pfnc_nvnSamplerBuilderSetCompare
|
||||
0x00000071025F7C50,pfnc_nvnSamplerBuilderSetBorderColor
|
||||
0x00000071025F7C58,pfnc_nvnSamplerBuilderSetBorderColori
|
||||
0x00000071025F7C60,pfnc_nvnSamplerBuilderSetBorderColorui
|
||||
0x00000071025F7C68,pfnc_nvnSamplerBuilderSetMaxAnisotropy
|
||||
0x00000071025F7C70,pfnc_nvnSamplerBuilderSetReductionFilter
|
||||
0x00000071025F7C78,pfnc_nvnSamplerBuilderSetLodSnap
|
||||
0x00000071025F7C80,pfnc_nvnSamplerBuilderGetMinMagFilter
|
||||
0x00000071025F7C88,pfnc_nvnSamplerBuilderGetWrapMode
|
||||
0x00000071025F7C90,pfnc_nvnSamplerBuilderGetLodClamp
|
||||
0x00000071025F7C98,pfnc_nvnSamplerBuilderGetLodBias
|
||||
0x00000071025F7CA0,pfnc_nvnSamplerBuilderGetCompare
|
||||
0x00000071025F7CA8,pfnc_nvnSamplerBuilderGetBorderColor
|
||||
0x00000071025F7CB0,pfnc_nvnSamplerBuilderGetBorderColori
|
||||
0x00000071025F7CB8,pfnc_nvnSamplerBuilderGetBorderColorui
|
||||
0x00000071025F7CC0,pfnc_nvnSamplerBuilderGetMaxAnisotropy
|
||||
0x00000071025F7CC8,pfnc_nvnSamplerBuilderGetReductionFilter
|
||||
0x00000071025F7CD0,pfnc_nvnSamplerBuilderGetLodSnap
|
||||
0x00000071025F7CD8,pfnc_nvnSamplerInitialize
|
||||
0x00000071025F7CE0,pfnc_nvnSamplerFinalize
|
||||
0x00000071025F7CE8,pfnc_nvnSamplerSetDebugLabel
|
||||
0x00000071025F7CF0,pfnc_nvnSamplerGetMinMagFilter
|
||||
0x00000071025F7CF8,pfnc_nvnSamplerGetWrapMode
|
||||
0x00000071025F7D00,pfnc_nvnSamplerGetLodClamp
|
||||
0x00000071025F7D08,pfnc_nvnSamplerGetLodBias
|
||||
0x00000071025F7D10,pfnc_nvnSamplerGetCompare
|
||||
0x00000071025F7D18,pfnc_nvnSamplerGetBorderColor
|
||||
0x00000071025F7D20,pfnc_nvnSamplerGetBorderColori
|
||||
0x00000071025F7D28,pfnc_nvnSamplerGetBorderColorui
|
||||
0x00000071025F7D30,pfnc_nvnSamplerGetMaxAnisotropy
|
||||
0x00000071025F7D38,pfnc_nvnSamplerGetReductionFilter
|
||||
0x00000071025F7D40,pfnc_nvnSamplerCompare
|
||||
0x00000071025F7D48,pfnc_nvnSamplerGetDebugID
|
||||
0x00000071025F7D50,pfnc_nvnBlendStateSetDefaults
|
||||
0x00000071025F7D58,pfnc_nvnBlendStateSetBlendTarget
|
||||
0x00000071025F7D60,pfnc_nvnBlendStateSetBlendFunc
|
||||
0x00000071025F7D68,pfnc_nvnBlendStateSetBlendEquation
|
||||
0x00000071025F7D70,pfnc_nvnBlendStateSetAdvancedMode
|
||||
0x00000071025F7D78,pfnc_nvnBlendStateSetAdvancedOverlap
|
||||
0x00000071025F7D80,pfnc_nvnBlendStateSetAdvancedPremultipliedSrc
|
||||
0x00000071025F7D88,pfnc_nvnBlendStateSetAdvancedNormalizedDst
|
||||
0x00000071025F7D90,pfnc_nvnBlendStateGetBlendTarget
|
||||
0x00000071025F7D98,pfnc_nvnBlendStateGetBlendFunc
|
||||
0x00000071025F7DA0,pfnc_nvnBlendStateGetBlendEquation
|
||||
0x00000071025F7DA8,pfnc_nvnBlendStateGetAdvancedMode
|
||||
0x00000071025F7DB0,pfnc_nvnBlendStateGetAdvancedOverlap
|
||||
0x00000071025F7DB8,pfnc_nvnBlendStateGetAdvancedPremultipliedSrc
|
||||
0x00000071025F7DC0,pfnc_nvnBlendStateGetAdvancedNormalizedDst
|
||||
0x00000071025F7DC8,pfnc_nvnColorStateSetDefaults
|
||||
0x00000071025F7DD0,pfnc_nvnColorStateSetBlendEnable
|
||||
0x00000071025F7DD8,pfnc_nvnColorStateSetLogicOp
|
||||
0x00000071025F7DE0,pfnc_nvnColorStateSetAlphaTest
|
||||
0x00000071025F7DE8,pfnc_nvnColorStateGetBlendEnable
|
||||
0x00000071025F7DF0,pfnc_nvnColorStateGetLogicOp
|
||||
0x00000071025F7DF8,pfnc_nvnColorStateGetAlphaTest
|
||||
0x00000071025F7E00,pfnc_nvnChannelMaskStateSetDefaults
|
||||
0x00000071025F7E08,pfnc_nvnChannelMaskStateSetChannelMask
|
||||
0x00000071025F7E10,pfnc_nvnChannelMaskStateGetChannelMask
|
||||
0x00000071025F7E18,pfnc_nvnMultisampleStateSetDefaults
|
||||
0x00000071025F7E20,pfnc_nvnMultisampleStateSetMultisampleEnable
|
||||
0x00000071025F7E28,pfnc_nvnMultisampleStateSetSamples
|
||||
0x00000071025F7E30,pfnc_nvnMultisampleStateSetAlphaToCoverageEnable
|
||||
0x00000071025F7E38,pfnc_nvnMultisampleStateSetAlphaToCoverageDither
|
||||
0x00000071025F7E40,pfnc_nvnMultisampleStateGetMultisampleEnable
|
||||
0x00000071025F7E48,pfnc_nvnMultisampleStateGetSamples
|
||||
0x00000071025F7E50,pfnc_nvnMultisampleStateGetAlphaToCoverageEnable
|
||||
0x00000071025F7E58,pfnc_nvnMultisampleStateGetAlphaToCoverageDither
|
||||
0x00000071025F7E60,pfnc_nvnMultisampleStateSetRasterSamples
|
||||
0x00000071025F7E68,pfnc_nvnMultisampleStateGetRasterSamples
|
||||
0x00000071025F7E70,pfnc_nvnMultisampleStateSetCoverageModulationMode
|
||||
0x00000071025F7E78,pfnc_nvnMultisampleStateGetCoverageModulationMode
|
||||
0x00000071025F7E80,pfnc_nvnMultisampleStateSetCoverageToColorEnable
|
||||
0x00000071025F7E88,pfnc_nvnMultisampleStateGetCoverageToColorEnable
|
||||
0x00000071025F7E90,pfnc_nvnMultisampleStateSetCoverageToColorOutput
|
||||
0x00000071025F7E98,pfnc_nvnMultisampleStateGetCoverageToColorOutput
|
||||
0x00000071025F7EA0,pfnc_nvnMultisampleStateSetSampleLocationsEnable
|
||||
0x00000071025F7EA8,pfnc_nvnMultisampleStateGetSampleLocationsEnable
|
||||
0x00000071025F7EB0,pfnc_nvnMultisampleStateGetSampleLocationsGrid
|
||||
0x00000071025F7EB8,pfnc_nvnMultisampleStateSetSampleLocationsGridEnable
|
||||
0x00000071025F7EC0,pfnc_nvnMultisampleStateGetSampleLocationsGridEnable
|
||||
0x00000071025F7EC8,pfnc_nvnMultisampleStateSetSampleLocations
|
||||
0x00000071025F7ED0,pfnc_nvnPolygonStateSetDefaults
|
||||
0x00000071025F7ED8,pfnc_nvnPolygonStateSetCullFace
|
||||
0x00000071025F7EE0,pfnc_nvnPolygonStateSetFrontFace
|
||||
0x00000071025F7EE8,pfnc_nvnPolygonStateSetPolygonMode
|
||||
0x00000071025F7EF0,pfnc_nvnPolygonStateSetPolygonOffsetEnables
|
||||
0x00000071025F7EF8,pfnc_nvnPolygonStateGetCullFace
|
||||
0x00000071025F7F00,pfnc_nvnPolygonStateGetFrontFace
|
||||
0x00000071025F7F08,pfnc_nvnPolygonStateGetPolygonMode
|
||||
0x00000071025F7F10,pfnc_nvnPolygonStateGetPolygonOffsetEnables
|
||||
0x00000071025F7F18,pfnc_nvnDepthStencilStateSetDefaults
|
||||
0x00000071025F7F20,pfnc_nvnDepthStencilStateSetDepthTestEnable
|
||||
0x00000071025F7F28,pfnc_nvnDepthStencilStateSetDepthWriteEnable
|
||||
0x00000071025F7F30,pfnc_nvnDepthStencilStateSetDepthFunc
|
||||
0x00000071025F7F38,pfnc_nvnDepthStencilStateSetStencilTestEnable
|
||||
0x00000071025F7F40,pfnc_nvnDepthStencilStateSetStencilFunc
|
||||
0x00000071025F7F48,pfnc_nvnDepthStencilStateSetStencilOp
|
||||
0x00000071025F7F50,pfnc_nvnDepthStencilStateGetDepthTestEnable
|
||||
0x00000071025F7F58,pfnc_nvnDepthStencilStateGetDepthWriteEnable
|
||||
0x00000071025F7F60,pfnc_nvnDepthStencilStateGetDepthFunc
|
||||
0x00000071025F7F68,pfnc_nvnDepthStencilStateGetStencilTestEnable
|
||||
0x00000071025F7F70,pfnc_nvnDepthStencilStateGetStencilFunc
|
||||
0x00000071025F7F78,pfnc_nvnDepthStencilStateGetStencilOp
|
||||
0x00000071025F7F80,pfnc_nvnVertexAttribStateSetDefaults
|
||||
0x00000071025F7F88,pfnc_nvnVertexAttribStateSetFormat
|
||||
0x00000071025F7F90,pfnc_nvnVertexAttribStateSetStreamIndex
|
||||
0x00000071025F7F98,pfnc_nvnVertexAttribStateGetFormat
|
||||
0x00000071025F7FA0,pfnc_nvnVertexAttribStateGetStreamIndex
|
||||
0x00000071025F7FA8,pfnc_nvnVertexStreamStateSetDefaults
|
||||
0x00000071025F7FB0,pfnc_nvnVertexStreamStateSetStride
|
||||
0x00000071025F7FB8,pfnc_nvnVertexStreamStateSetDivisor
|
||||
0x00000071025F7FC0,pfnc_nvnVertexStreamStateGetStride
|
||||
0x00000071025F7FC8,pfnc_nvnVertexStreamStateGetDivisor
|
||||
0x00000071025F7FD0,pfnc_nvnCommandBufferInitialize
|
||||
0x00000071025F7FD8,pfnc_nvnCommandBufferFinalize
|
||||
0x00000071025F7FE0,pfnc_nvnCommandBufferSetDebugLabel
|
||||
0x00000071025F7FE8,pfnc_nvnCommandBufferSetMemoryCallback
|
||||
0x00000071025F7FF0,pfnc_nvnCommandBufferSetMemoryCallbackData
|
||||
0x00000071025F7FF8,pfnc_nvnCommandBufferAddCommandMemory
|
||||
0x00000071025F8000,pfnc_nvnCommandBufferAddControlMemory
|
||||
0x00000071025F8008,pfnc_nvnCommandBufferGetCommandMemorySize
|
||||
0x00000071025F8010,pfnc_nvnCommandBufferGetCommandMemoryUsed
|
||||
0x00000071025F8018,pfnc_nvnCommandBufferGetCommandMemoryFree
|
||||
0x00000071025F8020,pfnc_nvnCommandBufferGetControlMemorySize
|
||||
0x00000071025F8028,pfnc_nvnCommandBufferGetControlMemoryUsed
|
||||
0x00000071025F8030,pfnc_nvnCommandBufferGetControlMemoryFree
|
||||
0x00000071025F8038,pfnc_nvnCommandBufferBeginRecording
|
||||
0x00000071025F8040,pfnc_nvnCommandBufferEndRecording
|
||||
0x00000071025F8048,pfnc_nvnCommandBufferCallCommands
|
||||
0x00000071025F8050,pfnc_nvnCommandBufferCopyCommands
|
||||
0x00000071025F8058,pfnc_nvnCommandBufferBindBlendState
|
||||
0x00000071025F8060,pfnc_nvnCommandBufferBindChannelMaskState
|
||||
0x00000071025F8068,pfnc_nvnCommandBufferBindColorState
|
||||
0x00000071025F8070,pfnc_nvnCommandBufferBindMultisampleState
|
||||
0x00000071025F8078,pfnc_nvnCommandBufferBindPolygonState
|
||||
0x00000071025F8080,pfnc_nvnCommandBufferBindDepthStencilState
|
||||
0x00000071025F8088,pfnc_nvnCommandBufferBindVertexAttribState
|
||||
0x00000071025F8090,pfnc_nvnCommandBufferBindVertexStreamState
|
||||
0x00000071025F8098,pfnc_nvnCommandBufferBindProgram
|
||||
0x00000071025F80A0,pfnc_nvnCommandBufferBindVertexBuffer
|
||||
0x00000071025F80A8,pfnc_nvnCommandBufferBindVertexBuffers
|
||||
0x00000071025F80B0,pfnc_nvnCommandBufferBindUniformBuffer
|
||||
0x00000071025F80B8,pfnc_nvnCommandBufferBindUniformBuffers
|
||||
0x00000071025F80C0,pfnc_nvnCommandBufferBindTransformFeedbackBuffer
|
||||
0x00000071025F80C8,pfnc_nvnCommandBufferBindTransformFeedbackBuffers
|
||||
0x00000071025F80D0,pfnc_nvnCommandBufferBindStorageBuffer
|
||||
0x00000071025F80D8,pfnc_nvnCommandBufferBindStorageBuffers
|
||||
0x00000071025F80E0,pfnc_nvnCommandBufferBindTexture
|
||||
0x00000071025F80E8,pfnc_nvnCommandBufferBindTextures
|
||||
0x00000071025F80F0,pfnc_nvnCommandBufferBindImage
|
||||
0x00000071025F80F8,pfnc_nvnCommandBufferBindImages
|
||||
0x00000071025F8100,pfnc_nvnCommandBufferSetPatchSize
|
||||
0x00000071025F8108,pfnc_nvnCommandBufferSetInnerTessellationLevels
|
||||
0x00000071025F8110,pfnc_nvnCommandBufferSetOuterTessellationLevels
|
||||
0x00000071025F8118,pfnc_nvnCommandBufferSetPrimitiveRestart
|
||||
0x00000071025F8120,pfnc_nvnCommandBufferBeginTransformFeedback
|
||||
0x00000071025F8128,pfnc_nvnCommandBufferEndTransformFeedback
|
||||
0x00000071025F8130,pfnc_nvnCommandBufferPauseTransformFeedback
|
||||
0x00000071025F8138,pfnc_nvnCommandBufferResumeTransformFeedback
|
||||
0x00000071025F8140,pfnc_nvnCommandBufferDrawTransformFeedback
|
||||
0x00000071025F8148,pfnc_nvnCommandBufferDrawArrays
|
||||
0x00000071025F8150,pfnc_nvnCommandBufferDrawElements
|
||||
0x00000071025F8158,pfnc_nvnCommandBufferDrawElementsBaseVertex
|
||||
0x00000071025F8160,pfnc_nvnCommandBufferDrawArraysInstanced
|
||||
0x00000071025F8168,pfnc_nvnCommandBufferDrawElementsInstanced
|
||||
0x00000071025F8170,pfnc_nvnCommandBufferDrawArraysIndirect
|
||||
0x00000071025F8178,pfnc_nvnCommandBufferDrawElementsIndirect
|
||||
0x00000071025F8180,pfnc_nvnCommandBufferMultiDrawArraysIndirectCount
|
||||
0x00000071025F8188,pfnc_nvnCommandBufferMultiDrawElementsIndirectCount
|
||||
0x00000071025F8190,pfnc_nvnCommandBufferClearColor
|
||||
0x00000071025F8198,pfnc_nvnCommandBufferClearColori
|
||||
0x00000071025F81A0,pfnc_nvnCommandBufferClearColorui
|
||||
0x00000071025F81A8,pfnc_nvnCommandBufferClearDepthStencil
|
||||
0x00000071025F81B0,pfnc_nvnCommandBufferDispatchCompute
|
||||
0x00000071025F81B8,pfnc_nvnCommandBufferDispatchComputeIndirect
|
||||
0x00000071025F81C0,pfnc_nvnCommandBufferSetViewport
|
||||
0x00000071025F81C8,pfnc_nvnCommandBufferSetViewports
|
||||
0x00000071025F81D0,pfnc_nvnCommandBufferSetViewportSwizzles
|
||||
0x00000071025F81D8,pfnc_nvnCommandBufferSetScissor
|
||||
0x00000071025F81E0,pfnc_nvnCommandBufferSetScissors
|
||||
0x00000071025F81E8,pfnc_nvnCommandBufferSetDepthRange
|
||||
0x00000071025F81F0,pfnc_nvnCommandBufferSetDepthBounds
|
||||
0x00000071025F81F8,pfnc_nvnCommandBufferSetDepthRanges
|
||||
0x00000071025F8200,pfnc_nvnCommandBufferSetTiledCacheAction
|
||||
0x00000071025F8208,pfnc_nvnCommandBufferSetTiledCacheTileSize
|
||||
0x00000071025F8210,pfnc_nvnCommandBufferBindSeparateTexture
|
||||
0x00000071025F8218,pfnc_nvnCommandBufferBindSeparateSampler
|
||||
0x00000071025F8220,pfnc_nvnCommandBufferBindSeparateTextures
|
||||
0x00000071025F8228,pfnc_nvnCommandBufferBindSeparateSamplers
|
||||
0x00000071025F8230,pfnc_nvnCommandBufferSetStencilValueMask
|
||||
0x00000071025F8238,pfnc_nvnCommandBufferSetStencilMask
|
||||
0x00000071025F8240,pfnc_nvnCommandBufferSetStencilRef
|
||||
0x00000071025F8248,pfnc_nvnCommandBufferSetBlendColor
|
||||
0x00000071025F8250,pfnc_nvnCommandBufferSetPointSize
|
||||
0x00000071025F8258,pfnc_nvnCommandBufferSetLineWidth
|
||||
0x00000071025F8260,pfnc_nvnCommandBufferSetPolygonOffsetClamp
|
||||
0x00000071025F8268,pfnc_nvnCommandBufferSetAlphaRef
|
||||
0x00000071025F8270,pfnc_nvnCommandBufferSetSampleMask
|
||||
0x00000071025F8278,pfnc_nvnCommandBufferSetRasterizerDiscard
|
||||
0x00000071025F8280,pfnc_nvnCommandBufferSetDepthClamp
|
||||
0x00000071025F8288,pfnc_nvnCommandBufferSetConservativeRasterEnable
|
||||
0x00000071025F8290,pfnc_nvnCommandBufferSetConservativeRasterDilate
|
||||
0x00000071025F8298,pfnc_nvnCommandBufferSetSubpixelPrecisionBias
|
||||
0x00000071025F82A0,pfnc_nvnCommandBufferCopyBufferToTexture
|
||||
0x00000071025F82A8,pfnc_nvnCommandBufferCopyTextureToBuffer
|
||||
0x00000071025F82B0,pfnc_nvnCommandBufferCopyTextureToTexture
|
||||
0x00000071025F82B8,pfnc_nvnCommandBufferCopyBufferToBuffer
|
||||
0x00000071025F82C0,pfnc_nvnCommandBufferClearBuffer
|
||||
0x00000071025F82C8,pfnc_nvnCommandBufferClearTexture
|
||||
0x00000071025F82D0,pfnc_nvnCommandBufferClearTexturei
|
||||
0x00000071025F82D8,pfnc_nvnCommandBufferClearTextureui
|
||||
0x00000071025F82E0,pfnc_nvnCommandBufferUpdateUniformBuffer
|
||||
0x00000071025F82E8,pfnc_nvnCommandBufferReportCounter
|
||||
0x00000071025F82F0,pfnc_nvnCommandBufferResetCounter
|
||||
0x00000071025F82F8,pfnc_nvnCommandBufferReportValue
|
||||
0x00000071025F8300,pfnc_nvnCommandBufferSetRenderEnable
|
||||
0x00000071025F8308,pfnc_nvnCommandBufferSetRenderEnableConditional
|
||||
0x00000071025F8310,pfnc_nvnCommandBufferSetRenderTargets
|
||||
0x00000071025F8318,pfnc_nvnCommandBufferDiscardColor
|
||||
0x00000071025F8320,pfnc_nvnCommandBufferDiscardDepthStencil
|
||||
0x00000071025F8328,pfnc_nvnCommandBufferDownsample
|
||||
0x00000071025F8330,pfnc_nvnCommandBufferTiledDownsample
|
||||
0x00000071025F8338,pfnc_nvnCommandBufferDownsampleTextureView
|
||||
0x00000071025F8340,pfnc_nvnCommandBufferTiledDownsampleTextureView
|
||||
0x00000071025F8348,pfnc_nvnCommandBufferBarrier
|
||||
0x00000071025F8350,pfnc_nvnCommandBufferWaitSync
|
||||
0x00000071025F8358,pfnc_nvnCommandBufferFenceSync
|
||||
0x00000071025F8360,pfnc_nvnCommandBufferSetTexturePool
|
||||
0x00000071025F8368,pfnc_nvnCommandBufferSetSamplerPool
|
||||
0x00000071025F8370,pfnc_nvnCommandBufferSetShaderScratchMemory
|
||||
0x00000071025F8378,pfnc_nvnCommandBufferSaveZCullData
|
||||
0x00000071025F8380,pfnc_nvnCommandBufferRestoreZCullData
|
||||
0x00000071025F8388,pfnc_nvnCommandBufferSetCopyRowStride
|
||||
0x00000071025F8390,pfnc_nvnCommandBufferSetCopyImageStride
|
||||
0x00000071025F8398,pfnc_nvnCommandBufferGetCopyRowStride
|
||||
0x00000071025F83A0,pfnc_nvnCommandBufferGetCopyImageStride
|
||||
0x00000071025F83A8,pfnc_nvnCommandBufferDrawTexture
|
||||
0x00000071025F83B0,pfnc_nvnProgramSetSubroutineLinkage
|
||||
0x00000071025F83B8,pfnc_nvnCommandBufferSetProgramSubroutines
|
||||
0x00000071025F83C0,pfnc_nvnCommandBufferBindCoverageModulationTable
|
||||
0x00000071025F83C8,pfnc_nvnCommandBufferResolveDepthBuffer
|
||||
0x00000071025F83D0,pfnc_nvnCommandBufferPushDebugGroupStatic
|
||||
0x00000071025F83D8,pfnc_nvnCommandBufferPushDebugGroupDynamic
|
||||
0x00000071025F83E0,pfnc_nvnCommandBufferPushDebugGroup
|
||||
0x00000071025F83E8,pfnc_nvnCommandBufferPopDebugGroup
|
||||
0x00000071025F83F0,pfnc_nvnCommandBufferPopDebugGroupId
|
||||
0x00000071025F83F8,pfnc_nvnCommandBufferInsertDebugMarkerStatic
|
||||
0x00000071025F8400,pfnc_nvnCommandBufferInsertDebugMarkerDynamic
|
||||
0x00000071025F8408,pfnc_nvnCommandBufferInsertDebugMarker
|
||||
0x00000071025F8410,pfnc_nvnCommandBufferGetMemoryCallback
|
||||
0x00000071025F8418,pfnc_nvnCommandBufferGetMemoryCallbackData
|
||||
0x00000071025F8420,pfnc_nvnCommandBufferIsRecording
|
||||
0x00000071025F8428,pfnc_nvnSyncInitialize
|
||||
0x00000071025F8430,pfnc_nvnSyncFinalize
|
||||
0x00000071025F8438,pfnc_nvnSyncSetDebugLabel
|
||||
0x00000071025F8440,pfnc_nvnQueueFenceSync
|
||||
0x00000071025F8448,pfnc_nvnSyncWait
|
||||
0x00000071025F8450,pfnc_nvnQueueWaitSync
|
||||
0x00000071025F8458,pfnc_nvnEventBuilderSetDefaults
|
||||
0x00000071025F8460,pfnc_nvnEventBuilderSetStorage
|
||||
0x00000071025F8468,pfnc_nvnEventInitialize
|
||||
0x00000071025F8470,pfnc_nvnEventFinalize
|
||||
0x00000071025F8478,pfnc_nvnEventGetValue
|
||||
0x00000071025F8480,pfnc_nvnEventSignal
|
||||
0x00000071025F8488,pfnc_nvnCommandBufferWaitEvent
|
||||
0x00000071025F8490,pfnc_nvnCommandBufferSignalEvent
|
|
74783
data/odyssey_functions.csv
Normal file
74783
data/odyssey_functions.csv
Normal file
File diff suppressed because it is too large
Load Diff
112757
data/uking_functions.csv
Executable file
112757
data/uking_functions.csv
Executable file
File diff suppressed because it is too large
Load Diff
23
diff_settings.py
Executable file
23
diff_settings.py
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def apply(config, args):
|
||||
config['arch'] = 'aarch64'
|
||||
config['baseimg'] = 'data/main.elf'
|
||||
config['myimg'] = 'build/odyssey'
|
||||
config['source_directories'] = ['src', 'lib']
|
||||
config['objdump_executable'] = 'tools/aarch64-none-elf-objdump'
|
||||
|
||||
for dir in ('build', 'build/nx64-release'):
|
||||
if (Path(dir) / 'build.ninja').is_file():
|
||||
config['make_command'] = ['ninja', '-C', dir]
|
||||
|
||||
|
||||
def map_build_target(make_target: str):
|
||||
if make_target == "build/odyssey":
|
||||
return "odyssey"
|
||||
|
||||
# TODO: When support for directly diffing object files is added, this needs to strip
|
||||
# the build/ prefix from the object file targets.
|
||||
return make_target
|
26
include/aarch64/byteswap.h
Normal file
26
include/aarch64/byteswap.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef _BYTESWAP_H
|
||||
#define _BYTESWAP_H
|
||||
|
||||
#include <features.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static __inline uint16_t __bswap_16(uint16_t __x)
|
||||
{
|
||||
return __x<<8 | __x>>8;
|
||||
}
|
||||
|
||||
static __inline uint32_t __bswap_32(uint32_t __x)
|
||||
{
|
||||
return __x>>24 | __x>>8&0xff00 | __x<<8&0xff0000 | __x<<24;
|
||||
}
|
||||
|
||||
static __inline uint64_t __bswap_64(uint64_t __x)
|
||||
{
|
||||
return __bswap_32(__x)+0ULL<<32 | __bswap_32(__x>>32);
|
||||
}
|
||||
|
||||
#define bswap_16(x) __bswap_16(x)
|
||||
#define bswap_32(x) __bswap_32(x)
|
||||
#define bswap_64(x) __bswap_64(x)
|
||||
|
||||
#endif
|
22
include/aarch64/features.h
Normal file
22
include/aarch64/features.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef _NN_FEATURES_H
|
||||
#define _NN_FEATURES_H
|
||||
/* libc++ (and or libc++abi) checks for GLIBC
|
||||
*
|
||||
* for now pretend MUSL is GLIBC 2.17
|
||||
* Perhaps someday MUSL will have version information
|
||||
* and libc++ will check for it
|
||||
*
|
||||
* rename original MUSL header to features_musl.h
|
||||
* and include it here
|
||||
*/
|
||||
#include <features_musl.h>
|
||||
#ifndef __GLIBC_PREREQ
|
||||
#define __MUSL_GLIBC__ 2
|
||||
#define __MUSL_GLIBC_MINOR__ 17
|
||||
#define __GLIBC_PREREQ(maj, min) ((__MUSL_GLIBC__ << 16) + __MUSL_GLIBC_MINOR__ >= ((maj) << 16) + (min))
|
||||
#endif
|
||||
#define __MUSL__ 0x10110
|
||||
#define __NNMUSL__ 1
|
||||
#endif
|
||||
|
||||
|
38
include/aarch64/features_musl.h
Normal file
38
include/aarch64/features_musl.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef _FEATURES_H
|
||||
#define _FEATURES_H
|
||||
|
||||
#if defined(_ALL_SOURCE) && !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#if defined(_DEFAULT_SOURCE) && !defined(_BSD_SOURCE)
|
||||
#define _BSD_SOURCE 1
|
||||
#endif
|
||||
|
||||
#if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) \
|
||||
&& !defined(_XOPEN_SOURCE) && !defined(_GNU_SOURCE) \
|
||||
&& !defined(_BSD_SOURCE) && !defined(__STRICT_ANSI__)
|
||||
#define _BSD_SOURCE 1
|
||||
#define _XOPEN_SOURCE 700
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 199901L
|
||||
#define __restrict restrict
|
||||
#elif !defined(__GNUC__)
|
||||
#define __restrict
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 199901L || defined(__cplusplus)
|
||||
#define __inline inline
|
||||
#elif !defined(__GNUC__)
|
||||
#define __inline
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
#elif defined(__GNUC__)
|
||||
#define _Noreturn __attribute__((__noreturn__))
|
||||
#else
|
||||
#define _Noreturn
|
||||
#endif
|
||||
|
||||
#endif
|
0
include/agl/g3d.h
Normal file → Executable file
0
include/agl/g3d.h
Normal file → Executable file
0
include/agl/g3d/g3d_ResFile.h
Normal file → Executable file
0
include/agl/g3d/g3d_ResFile.h
Normal file → Executable file
0
include/nn/g3d.h
Normal file → Executable file
0
include/nn/g3d.h
Normal file → Executable file
0
include/nn/g3d/g3d_ResFile.h
Normal file → Executable file
0
include/nn/g3d/g3d_ResFile.h
Normal file → Executable file
0
include/nn/util/util_AccessorBase.h
Normal file → Executable file
0
include/nn/util/util_AccessorBase.h
Normal file → Executable file
0
include/sead/seadBitFlag.h
Normal file → Executable file
0
include/sead/seadBitFlag.h
Normal file → Executable file
0
include/sead/seadDisposer.h
Normal file → Executable file
0
include/sead/seadDisposer.h
Normal file → Executable file
0
include/sead/seadFileDevice.h
Normal file → Executable file
0
include/sead/seadFileDevice.h
Normal file → Executable file
0
include/sead/seadHeap.h
Normal file → Executable file
0
include/sead/seadHeap.h
Normal file → Executable file
0
include/sead/seadHostIO.h
Normal file → Executable file
0
include/sead/seadHostIO.h
Normal file → Executable file
0
include/sead/seadListImpl.h
Normal file → Executable file
0
include/sead/seadListImpl.h
Normal file → Executable file
0
include/sead/seadMatrix.h
Normal file → Executable file
0
include/sead/seadMatrix.h
Normal file → Executable file
0
include/sead/seadNamable.h
Normal file → Executable file
0
include/sead/seadNamable.h
Normal file → Executable file
0
include/sead/seadQuat.h
Normal file → Executable file
0
include/sead/seadQuat.h
Normal file → Executable file
0
include/sead/seadResource.h
Normal file → Executable file
0
include/sead/seadResource.h
Normal file → Executable file
0
include/sead/seadRuntimeTypeInfo.h
Normal file → Executable file
0
include/sead/seadRuntimeTypeInfo.h
Normal file → Executable file
0
include/sead/seadSafeString.h
Normal file → Executable file
0
include/sead/seadSafeString.h
Normal file → Executable file
0
include/sead/seadSafeString.hpp
Normal file → Executable file
0
include/sead/seadSafeString.hpp
Normal file → Executable file
0
include/sead/seadVector.h
Normal file → Executable file
0
include/sead/seadVector.h
Normal file → Executable file
1
src/CMakeLists.txt
Normal file
1
src/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(al)
|
9
src/al/CMakeLists.txt
Normal file
9
src/al/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
add_subdirectory(actor)
|
||||
add_subdirectory(byaml)
|
||||
add_subdirectory(LiveActor)
|
||||
add_subdirectory(nerve)
|
||||
add_subdirectory(pose)
|
||||
add_subdirectory(resource)
|
||||
add_subdirectory(sead)
|
||||
add_subdirectory(sensor)
|
||||
add_subdirectory(util)
|
4
src/al/LiveActor/CMakeLists.txt
Normal file
4
src/al/LiveActor/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
target_sources(odyssey PRIVATE
|
||||
LiveActor.cpp
|
||||
LiveActorGroup.cpp
|
||||
)
|
0
source/al/LiveActor/LiveActor.cpp → src/al/LiveActor/LiveActor.cpp
Normal file → Executable file
0
source/al/LiveActor/LiveActor.cpp → src/al/LiveActor/LiveActor.cpp
Normal file → Executable file
0
source/al/LiveActor/LiveActorGroup.cpp → src/al/LiveActor/LiveActorGroup.cpp
Normal file → Executable file
0
source/al/LiveActor/LiveActorGroup.cpp → src/al/LiveActor/LiveActorGroup.cpp
Normal file → Executable file
4
src/al/actor/CMakeLists.txt
Normal file
4
src/al/actor/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
target_sources(odyssey PRIVATE
|
||||
Factory.cpp
|
||||
Placement.cpp
|
||||
)
|
0
source/al/actor/Factory.cpp → src/al/actor/Factory.cpp
Normal file → Executable file
0
source/al/actor/Factory.cpp → src/al/actor/Factory.cpp
Normal file → Executable file
0
source/al/actor/Placement.cpp → src/al/actor/Placement.cpp
Normal file → Executable file
0
source/al/actor/Placement.cpp → src/al/actor/Placement.cpp
Normal file → Executable file
0
source/al/byaml/ByamlContainerHeader.cpp → src/al/byaml/ByamlContainerHeader.cpp
Normal file → Executable file
0
source/al/byaml/ByamlContainerHeader.cpp → src/al/byaml/ByamlContainerHeader.cpp
Normal file → Executable file
0
source/al/byaml/ByamlData.cpp → src/al/byaml/ByamlData.cpp
Normal file → Executable file
0
source/al/byaml/ByamlData.cpp → src/al/byaml/ByamlData.cpp
Normal file → Executable file
0
source/al/byaml/ByamlHashPair.cpp → src/al/byaml/ByamlHashPair.cpp
Normal file → Executable file
0
source/al/byaml/ByamlHashPair.cpp → src/al/byaml/ByamlHashPair.cpp
Normal file → Executable file
0
source/al/byaml/ByamlHeader.cpp → src/al/byaml/ByamlHeader.cpp
Normal file → Executable file
0
source/al/byaml/ByamlHeader.cpp → src/al/byaml/ByamlHeader.cpp
Normal file → Executable file
0
source/al/byaml/ByamlStringTableIter.cpp → src/al/byaml/ByamlStringTableIter.cpp
Normal file → Executable file
0
source/al/byaml/ByamlStringTableIter.cpp → src/al/byaml/ByamlStringTableIter.cpp
Normal file → Executable file
7
src/al/byaml/CMakeLists.txt
Normal file
7
src/al/byaml/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
target_sources(odyssey PRIVATE
|
||||
ByamlContainerHeader.cpp
|
||||
ByamlData.cpp
|
||||
ByamlHashPair.cpp
|
||||
ByamlHeader.cpp
|
||||
ByamlStringTableIter.cpp
|
||||
)
|
7
src/al/nerve/CMakeLists.txt
Normal file
7
src/al/nerve/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
target_sources(odyssey PRIVATE
|
||||
NerveAction.cpp
|
||||
NerveExecutor.cpp
|
||||
NerveKeeper.cpp
|
||||
NerveStateBase.cpp
|
||||
NerveStateCtrl.cpp
|
||||
)
|
0
source/al/nerve/NerveAction.cpp → src/al/nerve/NerveAction.cpp
Normal file → Executable file
0
source/al/nerve/NerveAction.cpp → src/al/nerve/NerveAction.cpp
Normal file → Executable file
0
source/al/nerve/NerveExecutor.cpp → src/al/nerve/NerveExecutor.cpp
Normal file → Executable file
0
source/al/nerve/NerveExecutor.cpp → src/al/nerve/NerveExecutor.cpp
Normal file → Executable file
0
source/al/nerve/NerveKeeper.cpp → src/al/nerve/NerveKeeper.cpp
Normal file → Executable file
0
source/al/nerve/NerveKeeper.cpp → src/al/nerve/NerveKeeper.cpp
Normal file → Executable file
0
source/al/nerve/NerveStateBase.cpp → src/al/nerve/NerveStateBase.cpp
Normal file → Executable file
0
source/al/nerve/NerveStateBase.cpp → src/al/nerve/NerveStateBase.cpp
Normal file → Executable file
0
source/al/nerve/NerveStateCtrl.cpp → src/al/nerve/NerveStateCtrl.cpp
Normal file → Executable file
0
source/al/nerve/NerveStateCtrl.cpp → src/al/nerve/NerveStateCtrl.cpp
Normal file → Executable file
0
source/al/pose/ActorPoseKeeper.cpp → src/al/pose/ActorPoseKeeper.cpp
Normal file → Executable file
0
source/al/pose/ActorPoseKeeper.cpp → src/al/pose/ActorPoseKeeper.cpp
Normal file → Executable file
3
src/al/pose/CMakeLists.txt
Normal file
3
src/al/pose/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
target_sources(odyssey PRIVATE
|
||||
ActorPoseKeeper.cpp
|
||||
)
|
3
src/al/resource/CMakeLists.txt
Normal file
3
src/al/resource/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
target_sources(odyssey PRIVATE
|
||||
Resource.cpp
|
||||
)
|
0
source/al/resource/Resource.cpp → src/al/resource/Resource.cpp
Normal file → Executable file
0
source/al/resource/Resource.cpp → src/al/resource/Resource.cpp
Normal file → Executable file
3
src/al/sead/CMakeLists.txt
Normal file
3
src/al/sead/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
target_sources(odyssey PRIVATE
|
||||
seadSafeString.cpp
|
||||
)
|
0
source/al/sead/seadSafeString.cpp → src/al/sead/seadSafeString.cpp
Normal file → Executable file
0
source/al/sead/seadSafeString.cpp → src/al/sead/seadSafeString.cpp
Normal file → Executable file
4
src/al/sensor/CMakeLists.txt
Normal file
4
src/al/sensor/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
target_sources(odyssey PRIVATE
|
||||
HitSensor.cpp
|
||||
SensorHitGroup.cpp
|
||||
)
|
0
source/al/sensor/HitSensor.cpp → src/al/sensor/HitSensor.cpp
Normal file → Executable file
0
source/al/sensor/HitSensor.cpp → src/al/sensor/HitSensor.cpp
Normal file → Executable file
0
source/al/sensor/SensorHitGroup.cpp → src/al/sensor/SensorHitGroup.cpp
Normal file → Executable file
0
source/al/sensor/SensorHitGroup.cpp → src/al/sensor/SensorHitGroup.cpp
Normal file → Executable file
0
source/al/util/ByamlUtil.cpp → src/al/util/ByamlUtil.cpp
Normal file → Executable file
0
source/al/util/ByamlUtil.cpp → src/al/util/ByamlUtil.cpp
Normal file → Executable file
7
src/al/util/CMakeLists.txt
Normal file
7
src/al/util/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
target_sources(odyssey PRIVATE
|
||||
ByamlUtil.cpp
|
||||
MathUtil.cpp
|
||||
NerveUtil.cpp
|
||||
PlacementUtil.cpp
|
||||
StringUtil.cpp
|
||||
)
|
0
source/al/util/MathUtil.cpp → src/al/util/MathUtil.cpp
Normal file → Executable file
0
source/al/util/MathUtil.cpp → src/al/util/MathUtil.cpp
Normal file → Executable file
0
source/al/util/NerveUtil.cpp → src/al/util/NerveUtil.cpp
Normal file → Executable file
0
source/al/util/NerveUtil.cpp → src/al/util/NerveUtil.cpp
Normal file → Executable file
0
source/al/util/PlacementUtil.cpp → src/al/util/PlacementUtil.cpp
Normal file → Executable file
0
source/al/util/PlacementUtil.cpp → src/al/util/PlacementUtil.cpp
Normal file → Executable file
0
source/al/util/StringUtil.cpp → src/al/util/StringUtil.cpp
Normal file → Executable file
0
source/al/util/StringUtil.cpp → src/al/util/StringUtil.cpp
Normal file → Executable file
BIN
tools/__pycache__/check.cpython-38.pyc
Executable file
BIN
tools/__pycache__/check.cpython-38.pyc
Executable file
Binary file not shown.
BIN
tools/__pycache__/diff_settings.cpython-38.pyc
Normal file
BIN
tools/__pycache__/diff_settings.cpython-38.pyc
Normal file
Binary file not shown.
BIN
tools/aarch64-none-elf-objdump
Executable file
BIN
tools/aarch64-none-elf-objdump
Executable file
Binary file not shown.
37
tools/add_missing_functions.py
Executable file
37
tools/add_missing_functions.py
Executable file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Set, List
|
||||
|
||||
from util import utils
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("csv_path", help="Path to function CSV to merge")
|
||||
args = parser.parse_args()
|
||||
|
||||
csv_path = Path(args.csv_path)
|
||||
|
||||
known_fn_addrs: Set[int] = {func.addr for func in utils.get_functions()}
|
||||
new_fns: List[utils.FunctionInfo] = []
|
||||
for func in utils.get_functions(csv_path):
|
||||
if func.addr not in known_fn_addrs:
|
||||
new_fns.append(func)
|
||||
|
||||
new_fn_list: List[utils.FunctionInfo] = []
|
||||
new_fn_list.extend(utils.get_functions())
|
||||
new_fn_list.extend(new_fns)
|
||||
new_fn_list.sort(key=lambda func: func.addr)
|
||||
|
||||
# Output the modified function CSV.
|
||||
writer = csv.writer(sys.stdout, lineterminator="\n")
|
||||
for func in new_fn_list:
|
||||
writer.writerow(func.raw_row)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
271
tools/ai_generate_actions.py
Executable file
271
tools/ai_generate_actions.py
Executable file
@ -0,0 +1,271 @@
|
||||
#!/usr/bin/env python3
|
||||
import enum
|
||||
|
||||
import cxxfilt
|
||||
import zlib
|
||||
from typing import List, Dict, Iterable, Optional, Set
|
||||
|
||||
from pathlib import Path
|
||||
import textwrap
|
||||
from util import ai_common, elf
|
||||
|
||||
|
||||
def get_member_name(entry) -> str:
|
||||
type_ = entry["type"]
|
||||
if type_ == "dynamic_param":
|
||||
return f'm{entry["param_name"]}_d'
|
||||
elif type_ == "dynamic2_param":
|
||||
return f'm{entry["param_name"]}_d'
|
||||
elif type_ == "static_param":
|
||||
return f'm{entry["param_name"]}_s'
|
||||
elif type_ == "map_unit_param":
|
||||
return f'm{entry["param_name"]}_m'
|
||||
elif type_ == "aitree_variable":
|
||||
return f'm{entry["param_name"]}_a'
|
||||
else:
|
||||
assert False
|
||||
|
||||
|
||||
def generate_action_loadparam_body(info: list) -> str:
|
||||
out = []
|
||||
for entry in info:
|
||||
type_ = entry["type"]
|
||||
if type_ == "dynamic_param":
|
||||
if entry["param_name"]:
|
||||
out.append(f'getDynamicParam(&{get_member_name(entry)}, "{entry["param_name"]}");')
|
||||
elif type_ == "dynamic2_param":
|
||||
if entry["param_name"]:
|
||||
out.append(f'getDynamicParam2(&{get_member_name(entry)}, "{entry["param_name"]}");')
|
||||
elif type_ == "static_param":
|
||||
if entry["param_name"]:
|
||||
out.append(f'getStaticParam(&{get_member_name(entry)}, "{entry["param_name"]}");')
|
||||
elif type_ == "map_unit_param":
|
||||
if entry["param_name"]:
|
||||
out.append(f'getMapUnitParam(&{get_member_name(entry)}, "{entry["param_name"]}");')
|
||||
elif type_ == "aitree_variable":
|
||||
if entry["param_name"]:
|
||||
out.append(f'getAITreeVariable(&{get_member_name(entry)}, "{entry["param_name"]}");')
|
||||
elif type_ == "call":
|
||||
fn_name: str = entry["fn"]
|
||||
if fn_name.startswith("_ZN") and fn_name.endswith("11loadParams_Ev"):
|
||||
parent_class_name = cxxfilt.demangle(fn_name).split("::")[-2]
|
||||
out.append(f"{parent_class_name}::loadParams_();")
|
||||
else:
|
||||
out.append(f"// FIXME: CALL {fn_name} @ {entry['addr']:#x}")
|
||||
else:
|
||||
raise AssertionError(f"unknown type: {type_}")
|
||||
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
def generate_action_param_member_vars(parent: str, info: list) -> str:
|
||||
out = []
|
||||
|
||||
# Ignore duplicate calls to getXXXXXParam
|
||||
params_dict = dict()
|
||||
for entry in info:
|
||||
offset: Optional[int] = entry.get("param_offset")
|
||||
if offset is not None:
|
||||
params_dict[offset] = entry
|
||||
params = list(params_dict.values())
|
||||
params.sort(key=lambda entry: entry["param_offset"])
|
||||
|
||||
if not parent and params:
|
||||
first_offset: int = params[0]["param_offset"]
|
||||
sizeof_action = 0x20
|
||||
diff = first_offset - sizeof_action
|
||||
assert diff >= 0
|
||||
if diff > 0:
|
||||
out.append(f"// FIXME: remove this")
|
||||
out.append(f"u8 pad_0x20[{diff:#x}];")
|
||||
|
||||
for entry in params:
|
||||
if not entry["param_name"]:
|
||||
continue
|
||||
out.append(f"// {entry['type']} at offset {entry['param_offset']:#x}")
|
||||
out.append(f"{entry['param_type']} {get_member_name(entry)}{{}};")
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
@enum.unique
|
||||
class CommonVIndex(enum.IntEnum):
|
||||
Dtor = 2
|
||||
OneShot = 10
|
||||
Init = 11
|
||||
Enter = 12
|
||||
Leave = 14
|
||||
LoadParams = 15
|
||||
Calc = 31
|
||||
|
||||
|
||||
def generate_action(class_dir: Path, name: str, info: list, parent: str, seen_virtual_functions: Set[int],
|
||||
vtable: int) -> None:
|
||||
name = name[0].upper() + name[1:]
|
||||
if parent:
|
||||
parent = parent[0].upper() + parent[1:]
|
||||
|
||||
cpp_class_name = f"{name}"
|
||||
header_file_name = f"action{name}.h"
|
||||
|
||||
parent_class_name = parent if parent else 'ksys::act::ai::Action'
|
||||
|
||||
own_virtual_functions: Set[int] = set()
|
||||
for i, fn in enumerate(elf.get_vtable_fns_from_base_elf(vtable, 32)):
|
||||
if i not in CommonVIndex.__members__.values() or fn in seen_virtual_functions:
|
||||
continue
|
||||
own_virtual_functions.add(i)
|
||||
seen_virtual_functions.add(fn)
|
||||
|
||||
# Header
|
||||
out = []
|
||||
out.append("#pragma once")
|
||||
out.append("")
|
||||
if parent:
|
||||
out.append(f'#include "Game/AI/Action/action{parent}.h"')
|
||||
out.append('#include "KingSystem/ActorSystem/actAiAction.h"')
|
||||
out.append("")
|
||||
out.append("namespace uking::action {")
|
||||
out.append("")
|
||||
out.append(f"class {cpp_class_name} : public {parent_class_name} {{")
|
||||
out.append(f" SEAD_RTTI_OVERRIDE({cpp_class_name}, {parent_class_name})")
|
||||
out.append("public:")
|
||||
out.append(f" explicit {cpp_class_name}(const InitArg& arg);")
|
||||
if CommonVIndex.Dtor in own_virtual_functions:
|
||||
out.append(f" ~{cpp_class_name}() override;")
|
||||
out.append("")
|
||||
if CommonVIndex.Init in own_virtual_functions:
|
||||
out.append(" bool init_(sead::Heap* heap) override;")
|
||||
if CommonVIndex.Enter in own_virtual_functions:
|
||||
out.append(" void enter_(ksys::act::ai::InlineParamPack* params) override;")
|
||||
if CommonVIndex.Leave in own_virtual_functions:
|
||||
out.append(" void leave_() override;")
|
||||
if CommonVIndex.LoadParams in own_virtual_functions:
|
||||
out.append(" void loadParams_() override;")
|
||||
out.append("")
|
||||
out.append("protected:")
|
||||
if CommonVIndex.Calc in own_virtual_functions:
|
||||
out.append(" void calc_() override;")
|
||||
out.append("")
|
||||
out.append(textwrap.indent(generate_action_param_member_vars(parent, info), " " * 4))
|
||||
out.append("};") # =================================== end of class
|
||||
out.append("")
|
||||
out.append("} // namespace uking::action")
|
||||
out.append("")
|
||||
(class_dir / header_file_name).write_text("\n".join(out))
|
||||
|
||||
# .cpp
|
||||
out = []
|
||||
out.append(f'#include "Game/AI/Action/{header_file_name}"')
|
||||
out.append("")
|
||||
out.append("namespace uking::action {")
|
||||
out.append("")
|
||||
out.append(f"{cpp_class_name}::{cpp_class_name}(const InitArg& arg) : {parent_class_name}(arg) {{}}")
|
||||
out.append("")
|
||||
if CommonVIndex.Dtor in own_virtual_functions:
|
||||
out.append(f"{cpp_class_name}::~{cpp_class_name}() = default;")
|
||||
out.append("")
|
||||
if CommonVIndex.Init in own_virtual_functions:
|
||||
out.append(f"bool {cpp_class_name}::init_(sead::Heap* heap) {{")
|
||||
out.append(f" return {parent_class_name}::init_(heap);")
|
||||
out.append(f"}}")
|
||||
out.append("")
|
||||
if CommonVIndex.Enter in own_virtual_functions:
|
||||
out.append(f"void {cpp_class_name}::enter_(ksys::act::ai::InlineParamPack* params) {{")
|
||||
out.append(f" {parent_class_name}::enter_(params);")
|
||||
out.append(f"}}")
|
||||
out.append("")
|
||||
if CommonVIndex.Leave in own_virtual_functions:
|
||||
out.append(f"void {cpp_class_name}::leave_() {{")
|
||||
out.append(f" {parent_class_name}::leave_();")
|
||||
out.append(f"}}")
|
||||
out.append("")
|
||||
if CommonVIndex.LoadParams in own_virtual_functions:
|
||||
out.append(f"void {cpp_class_name}::loadParams_() {{")
|
||||
out.append(textwrap.indent(generate_action_loadparam_body(info), " " * 4))
|
||||
out.append(f"}}")
|
||||
out.append("")
|
||||
if CommonVIndex.Calc in own_virtual_functions:
|
||||
out.append(f"void {cpp_class_name}::calc_() {{")
|
||||
out.append(f" {parent_class_name}::calc_();")
|
||||
out.append(f"}}")
|
||||
out.append("")
|
||||
out.append("} // namespace uking::action")
|
||||
out.append("")
|
||||
(class_dir / f"action{name}.cpp").write_text("\n".join(out))
|
||||
|
||||
|
||||
def generate_action_factories(class_dir: Path, actions: Iterable[str]) -> None:
|
||||
out = []
|
||||
out.append("""\
|
||||
// DO NOT MAKE MAJOR EDITS. This file is automatically generated.
|
||||
// For major edits, please edit the generator script (ai_generate_queries.py) instead.
|
||||
// If edits are made to this file, make sure they are not lost when the generator is re-run.
|
||||
""")
|
||||
out.append('#include "Game/AI/aiActionFactories.h"')
|
||||
out.append('#include <array>')
|
||||
for name in actions:
|
||||
name = name[0].upper() + name[1:]
|
||||
out.append(f'#include "Game/AI/Action/action{name}.h"')
|
||||
out.append('#include "KingSystem/ActorSystem/actAiAction.h"')
|
||||
out.append('')
|
||||
out.append('namespace uking {')
|
||||
out.append('')
|
||||
out.append('using Factory = ksys::act::ai::ActionFactory;')
|
||||
out.append('')
|
||||
out.append('static Factory sActionFactories[] = {')
|
||||
for name in sorted(actions, key=lambda name: zlib.crc32(name.encode())):
|
||||
class_name = "action::" + name[0].upper() + name[1:]
|
||||
out.append(f' {{0x{zlib.crc32(name.encode()):08x}, Factory::make<{class_name}>}},')
|
||||
out.append('};')
|
||||
out.append('')
|
||||
out.append('void initActionFactories() {')
|
||||
out.append(' ksys::act::ai::Actions::setFactories(std::size(sActionFactories), sActionFactories);')
|
||||
out.append('}')
|
||||
out.append('')
|
||||
out.append('} // namespace uking')
|
||||
(class_dir.parent / f"aiActionFactories.cpp").write_text("\n".join(out))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
src_root = Path(__file__).parent.parent
|
||||
class_dir = src_root / "src" / "Game" / "AI" / "Action"
|
||||
class_dir.mkdir(exist_ok=True)
|
||||
|
||||
action_vtables: Dict[str, List[int]] = ai_common.get_vtables()["Action"]
|
||||
action_params = ai_common.get_action_params()
|
||||
vtable_names = ai_common.get_action_vtable_names()
|
||||
|
||||
seen_virtual_functions = set()
|
||||
seen_virtual_functions.update(elf.get_vtable_fns_from_base_elf(0x24d8d68, 31))
|
||||
seen_virtual_functions.update(elf.get_vtable_fns_from_base_elf(0x25129f0, 32))
|
||||
|
||||
generated = set()
|
||||
for vtables in action_vtables.values():
|
||||
vtables = list(dict.fromkeys(vtables))
|
||||
for i in range(len(vtables)):
|
||||
# This skips the first base class.
|
||||
if i == 0:
|
||||
continue
|
||||
|
||||
vtable_parent = vtables[i - 1]
|
||||
vtable = vtables[i]
|
||||
|
||||
# This skips any other base class.
|
||||
if vtable in ai_common.BaseClasses:
|
||||
continue
|
||||
|
||||
action_name = vtable_names[vtable]
|
||||
parent_name = vtable_names[vtable_parent]
|
||||
if vtable_parent in ai_common.BaseClasses:
|
||||
parent_name = ""
|
||||
|
||||
if vtable not in generated:
|
||||
generated.add(vtable)
|
||||
generate_action(class_dir, action_name, action_params[action_name], parent_name, seen_virtual_functions,
|
||||
vtable)
|
||||
|
||||
generate_action_factories(class_dir, action_vtables.keys())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
272
tools/ai_generate_ais.py
Executable file
272
tools/ai_generate_ais.py
Executable file
@ -0,0 +1,272 @@
|
||||
#!/usr/bin/env python3
|
||||
import enum
|
||||
|
||||
import cxxfilt
|
||||
import zlib
|
||||
from typing import List, Dict, Iterable, Optional, Set
|
||||
|
||||
from pathlib import Path
|
||||
import textwrap
|
||||
from util import ai_common, elf
|
||||
|
||||
|
||||
def get_member_name(entry) -> str:
|
||||
type_ = entry["type"]
|
||||
if type_ == "dynamic_param":
|
||||
return f'm{entry["param_name"]}_d'
|
||||
elif type_ == "dynamic2_param":
|
||||
return f'm{entry["param_name"]}_d'
|
||||
elif type_ == "static_param":
|
||||
return f'm{entry["param_name"]}_s'
|
||||
elif type_ == "map_unit_param":
|
||||
return f'm{entry["param_name"]}_m'
|
||||
elif type_ == "aitree_variable":
|
||||
return f'm{entry["param_name"]}_a'
|
||||
else:
|
||||
assert False
|
||||
|
||||
|
||||
def generate_ai_loadparam_body(info: list) -> str:
|
||||
out = []
|
||||
for entry in info:
|
||||
type_ = entry["type"]
|
||||
if type_ == "dynamic_param":
|
||||
if entry["param_name"]:
|
||||
out.append(f'getDynamicParam(&{get_member_name(entry)}, "{entry["param_name"]}");')
|
||||
elif type_ == "dynamic2_param":
|
||||
if entry["param_name"]:
|
||||
out.append(f'getDynamicParam2(&{get_member_name(entry)}, "{entry["param_name"]}");')
|
||||
elif type_ == "static_param":
|
||||
if entry["param_name"]:
|
||||
out.append(f'getStaticParam(&{get_member_name(entry)}, "{entry["param_name"]}");')
|
||||
elif type_ == "map_unit_param":
|
||||
if entry["param_name"]:
|
||||
out.append(f'getMapUnitParam(&{get_member_name(entry)}, "{entry["param_name"]}");')
|
||||
elif type_ == "aitree_variable":
|
||||
if entry["param_name"]:
|
||||
out.append(f'getAITreeVariable(&{get_member_name(entry)}, "{entry["param_name"]}");')
|
||||
elif type_ == "call":
|
||||
fn_name: str = entry["fn"]
|
||||
if fn_name.startswith("_ZN") and fn_name.endswith("11loadParams_Ev"):
|
||||
parent_class_name = cxxfilt.demangle(fn_name).split("::")[-2]
|
||||
out.append(f"{parent_class_name}::loadParams_();")
|
||||
else:
|
||||
out.append(f"// FIXME: CALL {fn_name} @ {entry['addr']:#x}")
|
||||
else:
|
||||
raise AssertionError(f"unknown type: {type_}")
|
||||
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
def generate_ai_param_member_vars(parent: str, info: list) -> str:
|
||||
out = []
|
||||
|
||||
# Ignore duplicate calls to getXXXXXParam
|
||||
params_dict = dict()
|
||||
for entry in info:
|
||||
offset: Optional[int] = entry.get("param_offset")
|
||||
if offset is not None:
|
||||
params_dict[offset] = entry
|
||||
params = list(params_dict.values())
|
||||
params.sort(key=lambda entry: entry["param_offset"])
|
||||
|
||||
if not parent and params:
|
||||
first_offset: int = params[0]["param_offset"]
|
||||
sizeof_ai = 0x38
|
||||
diff = first_offset - sizeof_ai
|
||||
assert diff >= 0
|
||||
if diff > 0:
|
||||
out.append(f"// FIXME: remove this")
|
||||
out.append(f"u8 pad_0x38[{diff:#x}];")
|
||||
|
||||
for entry in params:
|
||||
if not entry["param_name"]:
|
||||
continue
|
||||
out.append(f"// {entry['type']} at offset {entry['param_offset']:#x}")
|
||||
out.append(f"{entry['param_type']} {get_member_name(entry)}{{}};")
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
@enum.unique
|
||||
class CommonVIndex(enum.IntEnum):
|
||||
Dtor = 2
|
||||
OneShot = 10
|
||||
Init = 11
|
||||
Enter = 12
|
||||
Leave = 14
|
||||
LoadParams = 15
|
||||
Calc = 32
|
||||
|
||||
|
||||
def generate_ai(class_dir: Path, name: str, info: list, parent: str, seen_virtual_functions: Set[int],
|
||||
vtable: int) -> None:
|
||||
name = name[0].upper() + name[1:]
|
||||
if parent:
|
||||
parent = parent[0].upper() + parent[1:]
|
||||
|
||||
cpp_class_name = f"{name}"
|
||||
header_file_name = f"ai{name}.h"
|
||||
|
||||
parent_class_name = parent if parent else 'ksys::act::ai::Ai'
|
||||
|
||||
own_virtual_functions: Set[int] = set()
|
||||
for i, fn in enumerate(elf.get_vtable_fns_from_base_elf(vtable, 32)):
|
||||
if i not in CommonVIndex.__members__.values() or fn in seen_virtual_functions:
|
||||
continue
|
||||
own_virtual_functions.add(i)
|
||||
seen_virtual_functions.add(fn)
|
||||
|
||||
# Header
|
||||
out = []
|
||||
out.append("#pragma once")
|
||||
out.append("")
|
||||
if parent:
|
||||
out.append(f'#include "Game/AI/AI/ai{parent}.h"')
|
||||
out.append('#include "KingSystem/ActorSystem/actAiAi.h"')
|
||||
out.append("")
|
||||
out.append("namespace uking::ai {")
|
||||
out.append("")
|
||||
out.append(f"class {cpp_class_name} : public {parent_class_name} {{")
|
||||
out.append(f" SEAD_RTTI_OVERRIDE({cpp_class_name}, {parent_class_name})")
|
||||
out.append("public:")
|
||||
out.append(f" explicit {cpp_class_name}(const InitArg& arg);")
|
||||
if CommonVIndex.Dtor in own_virtual_functions:
|
||||
out.append(f" ~{cpp_class_name}() override;")
|
||||
out.append("")
|
||||
if CommonVIndex.Init in own_virtual_functions:
|
||||
out.append(" bool init_(sead::Heap* heap) override;")
|
||||
if CommonVIndex.Enter in own_virtual_functions:
|
||||
out.append(" void enter_(ksys::act::ai::InlineParamPack* params) override;")
|
||||
if CommonVIndex.Leave in own_virtual_functions:
|
||||
out.append(" void leave_() override;")
|
||||
if CommonVIndex.LoadParams in own_virtual_functions:
|
||||
out.append(" void loadParams_() override;")
|
||||
out.append("")
|
||||
out.append("protected:")
|
||||
if CommonVIndex.Calc in own_virtual_functions:
|
||||
out.append(" void calc_() override;")
|
||||
out.append("")
|
||||
out.append(textwrap.indent(generate_ai_param_member_vars(parent, info), " " * 4))
|
||||
out.append("};") # =================================== end of class
|
||||
out.append("")
|
||||
out.append("} // namespace uking::ai")
|
||||
out.append("")
|
||||
(class_dir / header_file_name).write_text("\n".join(out))
|
||||
|
||||
# .cpp
|
||||
out = []
|
||||
out.append(f'#include "Game/AI/AI/{header_file_name}"')
|
||||
out.append("")
|
||||
out.append("namespace uking::ai {")
|
||||
out.append("")
|
||||
out.append(f"{cpp_class_name}::{cpp_class_name}(const InitArg& arg) : {parent_class_name}(arg) {{}}")
|
||||
out.append("")
|
||||
if CommonVIndex.Dtor in own_virtual_functions:
|
||||
out.append(f"{cpp_class_name}::~{cpp_class_name}() = default;")
|
||||
out.append("")
|
||||
if CommonVIndex.Init in own_virtual_functions:
|
||||
out.append(f"bool {cpp_class_name}::init_(sead::Heap* heap) {{")
|
||||
out.append(f" return {parent_class_name}::init_(heap);")
|
||||
out.append(f"}}")
|
||||
out.append("")
|
||||
if CommonVIndex.Enter in own_virtual_functions:
|
||||
out.append(f"void {cpp_class_name}::enter_(ksys::act::ai::InlineParamPack* params) {{")
|
||||
out.append(f" {parent_class_name}::enter_(params);")
|
||||
out.append(f"}}")
|
||||
out.append("")
|
||||
if CommonVIndex.Leave in own_virtual_functions:
|
||||
out.append(f"void {cpp_class_name}::leave_() {{")
|
||||
out.append(f" {parent_class_name}::leave_();")
|
||||
out.append(f"}}")
|
||||
out.append("")
|
||||
if CommonVIndex.LoadParams in own_virtual_functions:
|
||||
out.append(f"void {cpp_class_name}::loadParams_() {{")
|
||||
out.append(textwrap.indent(generate_ai_loadparam_body(info), " " * 4))
|
||||
out.append(f"}}")
|
||||
out.append("")
|
||||
if CommonVIndex.Calc in own_virtual_functions:
|
||||
out.append(f"void {cpp_class_name}::calc_() {{")
|
||||
out.append(f" {parent_class_name}::calc_();")
|
||||
out.append(f"}}")
|
||||
out.append("")
|
||||
out.append("} // namespace uking::ai")
|
||||
out.append("")
|
||||
(class_dir / f"ai{name}.cpp").write_text("\n".join(out))
|
||||
|
||||
|
||||
def generate_ai_factories(class_dir: Path, ais: Iterable[str]) -> None:
|
||||
out = []
|
||||
out.append("""\
|
||||
// DO NOT MAKE MAJOR EDITS. This file is automatically generated.
|
||||
// For major edits, please edit the generator script (ai_generate_ais.py) instead.
|
||||
// If edits are made to this file, make sure they are not lost when the generator is re-run.
|
||||
""")
|
||||
out.append('#include "Game/AI/aiAiFactories.h"')
|
||||
out.append('#include <array>')
|
||||
for name in ais:
|
||||
name = name[0].upper() + name[1:]
|
||||
out.append(f'#include "Game/AI/AI/ai{name}.h"')
|
||||
out.append('#include "KingSystem/ActorSystem/actAiAi.h"')
|
||||
out.append('')
|
||||
out.append('namespace uking {')
|
||||
out.append('')
|
||||
out.append('using Factory = ksys::act::ai::AiFactory;')
|
||||
out.append('')
|
||||
out.append('static Factory sAiFactories[] = {')
|
||||
for name in sorted(ais, key=lambda name: zlib.crc32(name.encode())):
|
||||
class_name = "ai::" + name[0].upper() + name[1:]
|
||||
out.append(f' {{0x{zlib.crc32(name.encode()):08x}, Factory::make<{class_name}>}},')
|
||||
out.append('};')
|
||||
out.append('')
|
||||
out.append('void initAiFactories() {')
|
||||
out.append(' ksys::act::ai::Ais::setFactories(std::size(sAiFactories), sAiFactories);')
|
||||
out.append('}')
|
||||
out.append('')
|
||||
out.append('} // namespace uking')
|
||||
(class_dir.parent / f"aiAiFactories.cpp").write_text("\n".join(out))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
src_root = Path(__file__).parent.parent
|
||||
class_dir = src_root / "src" / "Game" / "AI" / "AI"
|
||||
class_dir.mkdir(exist_ok=True)
|
||||
|
||||
ai_vtables: Dict[str, List[int]] = ai_common.get_vtables()["AI"]
|
||||
ai_params = ai_common.get_ai_params()
|
||||
vtable_names = ai_common.get_ai_vtable_names()
|
||||
|
||||
seen_virtual_functions = set()
|
||||
# ai::ActionBase
|
||||
seen_virtual_functions.update(elf.get_vtable_fns_from_base_elf(0x24d8d68, 31))
|
||||
# ai::Ai
|
||||
seen_virtual_functions.update(elf.get_vtable_fns_from_base_elf(0x2513278, 34))
|
||||
|
||||
generated = set()
|
||||
for vtables in ai_vtables.values():
|
||||
vtables = list(dict.fromkeys(vtables))
|
||||
for i in range(len(vtables)):
|
||||
# This skips the first base class.
|
||||
if i == 0:
|
||||
continue
|
||||
|
||||
vtable_parent = vtables[i - 1]
|
||||
vtable = vtables[i]
|
||||
|
||||
# This skips any other base class.
|
||||
if vtable in ai_common.BaseClasses:
|
||||
continue
|
||||
|
||||
ai_name = vtable_names[vtable]
|
||||
parent_name = vtable_names[vtable_parent]
|
||||
if vtable_parent in ai_common.BaseClasses:
|
||||
parent_name = ""
|
||||
|
||||
if vtable not in generated:
|
||||
generated.add(vtable)
|
||||
generate_ai(class_dir, ai_name, ai_params[ai_name], parent_name, seen_virtual_functions, vtable)
|
||||
|
||||
generate_ai_factories(class_dir, ai_vtables.keys())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
213
tools/ai_generate_queries.py
Executable file
213
tools/ai_generate_queries.py
Executable file
@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import zlib
|
||||
from typing import List
|
||||
|
||||
import oead
|
||||
from pathlib import Path
|
||||
import textwrap
|
||||
|
||||
|
||||
def sort_params(params: list) -> list:
|
||||
def sort_by_type(param):
|
||||
t = param["Type"]
|
||||
if t == "String":
|
||||
return 1
|
||||
return 0
|
||||
|
||||
return sorted(params, key=sort_by_type)
|
||||
|
||||
|
||||
def generate_query_loadparam_body(query: dict, is_evfl: bool) -> str:
|
||||
if not query:
|
||||
return ""
|
||||
|
||||
out = []
|
||||
|
||||
if is_evfl:
|
||||
for param in sort_params(query.get("DynamicInstParams", [])):
|
||||
out.append(f"load{param['Type']}(arg.param_accessor, \"{param['Name']}\");")
|
||||
else:
|
||||
for param in sort_params(query.get("StaticInstParams", [])):
|
||||
out.append(f"getStaticParam(&m{param['Name']}, \"{param['Name']}\");")
|
||||
|
||||
for param in sort_params(query.get("DynamicInstParams", [])):
|
||||
out.append(f"getDynamicParam(&m{param['Name']}, \"{param['Name']}\");")
|
||||
|
||||
for param in sort_params(query.get("AITreeVariables", [])):
|
||||
out.append(f"getAITreeVariable(&m{param['Name']}, \"{param['Name']}\");")
|
||||
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
_types_static = {
|
||||
"Bool": "const bool*",
|
||||
"Int": "const int*",
|
||||
"Float": "const float*",
|
||||
"String": "sead::SafeString",
|
||||
}
|
||||
|
||||
_types_dynamic = {
|
||||
"Bool": "bool*",
|
||||
"Int": "int*",
|
||||
"Float": "float*",
|
||||
"String": "sead::SafeString",
|
||||
}
|
||||
|
||||
_types_ai_tree_var = {
|
||||
"String": "sead::SafeString*",
|
||||
"AITreeVariablePointer": "void*",
|
||||
}
|
||||
|
||||
|
||||
def generate_query_param_member_vars(query: dict) -> str:
|
||||
out = []
|
||||
|
||||
for param in sort_params(query.get("StaticInstParams", [])):
|
||||
out.append(f"{_types_static[param['Type']]} m{param['Name']}{{}};")
|
||||
|
||||
for param in sort_params(query.get("DynamicInstParams", [])):
|
||||
out.append(f"{_types_dynamic[param['Type']]} m{param['Name']}{{}};")
|
||||
|
||||
for param in sort_params(query.get("AITreeVariables", [])):
|
||||
out.append(f"{_types_ai_tree_var[param['Type']]} m{param['Name']}{{}};")
|
||||
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
def generate_query(class_dir: Path, name: str, query) -> None:
|
||||
has_params = False
|
||||
if query != "":
|
||||
assert isinstance(query, oead.byml.Hash)
|
||||
query = dict(query)
|
||||
has_params = "DynamicInstParams" in query or "StaticInstParams" in query or "AITreeVariables" in query
|
||||
|
||||
cpp_class_name = f"{name}"
|
||||
header_file_name = f"query{name}.h"
|
||||
|
||||
# Header
|
||||
out = []
|
||||
out.append("#pragma once")
|
||||
out.append("")
|
||||
out.append('#include "KingSystem/ActorSystem/actAiQuery.h"')
|
||||
out.append("")
|
||||
out.append("namespace uking::query {")
|
||||
out.append("")
|
||||
out.append(f"class {cpp_class_name} : public ksys::act::ai::Query {{")
|
||||
out.append(f" SEAD_RTTI_OVERRIDE({cpp_class_name}, Query)")
|
||||
out.append("public:")
|
||||
out.append(f" explicit {cpp_class_name}(const InitArg& arg);")
|
||||
out.append(f" ~{cpp_class_name}() override;")
|
||||
out.append(f" int doQuery() override;")
|
||||
out.append("")
|
||||
out.append(" void loadParams() override;")
|
||||
out.append(" void loadParams(const evfl::QueryArg& arg) override;")
|
||||
if has_params:
|
||||
out.append("")
|
||||
out.append("protected:")
|
||||
out.append(textwrap.indent(generate_query_param_member_vars(query), " " * 4))
|
||||
out.append("};") # =================================== end of class
|
||||
out.append("")
|
||||
out.append("} // namespace uking::query")
|
||||
out.append("")
|
||||
(class_dir / header_file_name).write_text("\n".join(out))
|
||||
|
||||
# .cpp
|
||||
out = []
|
||||
out.append(f'#include "Game/AI/Query/{header_file_name}"')
|
||||
out.append(f'#include <evfl/query.h>')
|
||||
out.append("")
|
||||
out.append("namespace uking::query {")
|
||||
out.append("")
|
||||
out.append(f"{cpp_class_name}::{cpp_class_name}(const InitArg& arg) : ksys::act::ai::Query(arg) {{}}")
|
||||
out.append("")
|
||||
out.append(f"{cpp_class_name}::~{cpp_class_name}() = default;")
|
||||
out.append("")
|
||||
out.append("// FIXME: implement")
|
||||
out.append(f"int {cpp_class_name}::doQuery() {{ return -1; }}")
|
||||
out.append("")
|
||||
out.append(f"void {cpp_class_name}::loadParams(const evfl::QueryArg& arg) {{")
|
||||
out.append(textwrap.indent(generate_query_loadparam_body(query, is_evfl=True), " " * 4))
|
||||
out.append(f"}}")
|
||||
out.append("")
|
||||
out.append(f"void {cpp_class_name}::loadParams() {{")
|
||||
out.append(textwrap.indent(generate_query_loadparam_body(query, is_evfl=False), " " * 4))
|
||||
out.append(f"}}")
|
||||
out.append("")
|
||||
out.append("} // namespace uking::query")
|
||||
out.append("")
|
||||
(class_dir / f"query{name}.cpp").write_text("\n".join(out))
|
||||
|
||||
|
||||
def generate_query_factories(class_dir: Path, aidef) -> None:
|
||||
queries: List[str] = []
|
||||
for query_name, data in aidef["Querys"].items():
|
||||
if isinstance(data, oead.byml.Hash) and dict(data).get("SystemQuery", False):
|
||||
continue
|
||||
queries.append(query_name)
|
||||
|
||||
out = []
|
||||
out.append("""\
|
||||
// DO NOT MAKE MAJOR EDITS. This file is automatically generated.
|
||||
// For major edits, please edit the generator script (ai_generate_queries.py) instead.
|
||||
// If edits are made to this file, make sure they are not lost when the generator is re-run.
|
||||
""")
|
||||
out.append('#include "Game/AI/aiQueryFactories.h"')
|
||||
out.append('#include <array>')
|
||||
for query_name in queries:
|
||||
query_name = query_name[0].upper() + query_name[1:]
|
||||
out.append(f'#include "Game/AI/Query/query{query_name}.h"')
|
||||
out.append('#include "KingSystem/ActorSystem/actAiQueries.h"')
|
||||
out.append('#include "KingSystem/ActorSystem/actAiQuery.h"')
|
||||
out.append('')
|
||||
out.append('namespace uking {')
|
||||
out.append('')
|
||||
out.append('using Factory = ksys::act::ai::QueryFactory;')
|
||||
out.append('')
|
||||
out.append('static ksys::act::ai::QueryFactory sQueryFactories[] = {')
|
||||
for query_name in sorted(queries, key=lambda query: zlib.crc32(query.encode())):
|
||||
class_name = "query::" + query_name[0].upper() + query_name[1:]
|
||||
out.append(f' {{0x{zlib.crc32(query_name.encode()):08x}, Factory::make<{class_name}>}},')
|
||||
out.append('};')
|
||||
out.append('')
|
||||
out.append('void initQueryFactories() {')
|
||||
out.append(' ksys::act::ai::Queries::setFactories(std::size(sQueryFactories), sQueryFactories);')
|
||||
out.append('}')
|
||||
out.append('')
|
||||
out.append('} // namespace uking')
|
||||
(class_dir.parent / f"aiQueryFactories.cpp").write_text("\n".join(out))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
src_root = Path(__file__).parent.parent
|
||||
class_dir = src_root / "src" / "Game" / "AI" / "Query"
|
||||
class_dir.mkdir(exist_ok=True)
|
||||
|
||||
parser = argparse.ArgumentParser(description="Generates stubs for AI queries.")
|
||||
parser.add_argument("aidef")
|
||||
args = parser.parse_args()
|
||||
|
||||
aidef = oead.byml.from_text(Path(args.aidef).read_text(encoding="utf-8"))
|
||||
|
||||
count = 0
|
||||
keys = set()
|
||||
for query_name, data in aidef["Querys"].items():
|
||||
if isinstance(data, oead.byml.Hash) and dict(data).get("SystemQuery", False):
|
||||
continue
|
||||
|
||||
if isinstance(data, oead.byml.Hash):
|
||||
keys |= set(data.keys())
|
||||
|
||||
query_name = query_name[0].upper() + query_name[1:]
|
||||
generate_query(class_dir, query_name, data)
|
||||
print(query_name)
|
||||
count += 1
|
||||
|
||||
generate_query_factories(class_dir, aidef)
|
||||
|
||||
print()
|
||||
print(f"{count} queries")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
132
tools/ai_identify_matching_stubs.py
Executable file
132
tools/ai_identify_matching_stubs.py
Executable file
@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
|
||||
import oead
|
||||
from colorama import Fore
|
||||
import cxxfilt
|
||||
from pathlib import Path
|
||||
from typing import Dict, Iterable
|
||||
|
||||
import util.checker
|
||||
import util.elf
|
||||
from util import utils, ai_common
|
||||
|
||||
|
||||
def identify(functions: Dict[str, utils.FunctionInfo], checker: util.checker.FunctionChecker,
|
||||
new_matches: Dict[int, str], class_names: Iterable[str], get_pairs) -> None:
|
||||
for name in class_names:
|
||||
orig_name = name
|
||||
name = name[0].upper() + name[1:]
|
||||
|
||||
pairs = get_pairs(orig_name, name)
|
||||
for orig_fn_name, fn_name in pairs:
|
||||
orig_fn_info = functions.get(orig_fn_name, None)
|
||||
if orig_fn_info is None:
|
||||
continue
|
||||
if orig_fn_info.status != utils.FunctionStatus.NotDecompiled:
|
||||
continue
|
||||
|
||||
orig_fn = util.elf.get_fn_from_base_elf(orig_fn_info.addr, orig_fn_info.size)
|
||||
try:
|
||||
decomp_fn = util.elf.get_fn_from_my_elf(fn_name)
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
if checker.check(orig_fn, decomp_fn):
|
||||
new_matches[orig_fn_info.addr] = fn_name
|
||||
utils.print_note(f"new match: {Fore.BLUE}{cxxfilt.demangle(fn_name)}{Fore.RESET}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Identifies matching AI class functions.")
|
||||
parser.add_argument("aidef")
|
||||
parser.add_argument("--type", choices=["Action", "AI", "Behavior", "Query"], required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
type_: str = args.type
|
||||
|
||||
new_matches: Dict[int, str] = dict()
|
||||
checker = util.checker.FunctionChecker()
|
||||
functions: Dict[str, utils.FunctionInfo] = {fn.name: fn for fn in utils.get_functions()}
|
||||
|
||||
aidef = oead.byml.from_text(Path(args.aidef).read_text(encoding="utf-8"))
|
||||
|
||||
def get_query_pairs(orig_name, name):
|
||||
prefix = f"AI_Query_{orig_name}::"
|
||||
return [
|
||||
(f"{prefix}ctor", f"_ZN5uking5query{len(name)}{name}C1ERKN4ksys3act2ai5Query7InitArgE"),
|
||||
(f"{prefix}dtor", f"_ZN5uking5query{len(name)}{name}D1Ev"),
|
||||
(f"{prefix}dtorDelete", f"_ZN5uking5query{len(name)}{name}D0Ev"),
|
||||
(f"{prefix}m10", f"_ZN5uking5query{len(name)}{name}10loadParamsERKN4evfl8QueryArgE"),
|
||||
(f"{prefix}loadParams", f"_ZN5uking5query{len(name)}{name}10loadParamsEv"),
|
||||
(f"{prefix}rtti1",
|
||||
f"_ZNK5uking5query{len(name)}{name}27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE"),
|
||||
(f"{prefix}rtti2", f"_ZNK5uking5query{len(name)}{name}18getRuntimeTypeInfoEv"),
|
||||
(f"AI_F_Query_{orig_name}",
|
||||
f"_ZN4ksys3act2ai12QueryFactory4makeIN5uking5query{len(name)}{name}EEEPNS1_5QueryERKNS7_7InitArgEPN4sead4HeapE"),
|
||||
]
|
||||
|
||||
def get_action_pairs(orig_name, name):
|
||||
pairs = []
|
||||
|
||||
def add_pair(x):
|
||||
pairs.append((x, x))
|
||||
|
||||
pairs.append(
|
||||
(f"AI_Action_{orig_name}::ctor",
|
||||
f"_ZN5uking6action{len(name)}{name}C1ERKN4ksys3act2ai10ActionBase7InitArgE"))
|
||||
pairs.append(
|
||||
(f"AI_Action{orig_name}::ctor",
|
||||
f"_ZN5uking6action{len(name)}{name}C1ERKN4ksys3act2ai10ActionBase7InitArgE"))
|
||||
pairs.append((f"AI_F_Action_{orig_name}",
|
||||
f"_ZN4ksys3act2ai13ActionFactory4makeIN5uking6action{len(name)}{name}EEEPNS1_6ActionERKNS1_10ActionBase7InitArgEPN4sead4HeapE"))
|
||||
add_pair(f"_ZN5uking6action{len(name)}{name}D1Ev")
|
||||
add_pair(f"_ZN5uking6action{len(name)}{name}D0Ev")
|
||||
add_pair(f"_ZN5uking6action{len(name)}{name}11loadParams_Ev")
|
||||
add_pair(f"_ZN5uking6action{len(name)}{name}5init_EPN4sead4HeapE")
|
||||
add_pair(f"_ZN5uking6action{len(name)}{name}6enter_EPN4ksys3act2ai15InlineParamPackE")
|
||||
add_pair(f"_ZN5uking6action{len(name)}{name}6leave_Ev")
|
||||
add_pair(f"_ZN5uking6action{len(name)}{name}5calc_Ev")
|
||||
add_pair(
|
||||
f"_ZNK5uking6action{len(name)}{name}27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE")
|
||||
add_pair(f"_ZNK5uking6action{len(name)}{name}18getRuntimeTypeInfoEv")
|
||||
return pairs
|
||||
|
||||
def get_ai_pairs(orig_name, name):
|
||||
pairs = []
|
||||
|
||||
def add_pair(x):
|
||||
pairs.append((x, x))
|
||||
|
||||
pairs.append(
|
||||
(f"AI_AI_{orig_name}::ctor", f"_ZN5uking2ai{len(name)}{name}C1ERKN4ksys3act2ai10ActionBase7InitArgE"))
|
||||
pairs.append(
|
||||
(f"AI_AI{orig_name}::ctor", f"_ZN5uking2ai{len(name)}{name}C1ERKN4ksys3act2ai10ActionBase7InitArgE"))
|
||||
pairs.append((f"AI_F_AI_{orig_name}",
|
||||
f"_ZN4ksys3act2ai9AiFactory4makeIN5uking2ai{len(name)}{name}EEEPNS1_2AiERKNS1_10ActionBase7InitArgEPN4sead4HeapE"))
|
||||
add_pair(f"_ZN5uking2ai{len(name)}{name}D1Ev")
|
||||
add_pair(f"_ZN5uking2ai{len(name)}{name}D0Ev")
|
||||
add_pair(f"_ZN5uking2ai{len(name)}{name}11loadParams_Ev")
|
||||
add_pair(f"_ZN5uking2ai{len(name)}{name}5init_EPN4sead4HeapE")
|
||||
add_pair(f"_ZN5uking2ai{len(name)}{name}6enter_EPN4ksys3act2ai15InlineParamPackE")
|
||||
add_pair(f"_ZN5uking2ai{len(name)}{name}6leave_Ev")
|
||||
add_pair(f"_ZN5uking2ai{len(name)}{name}5calc_Ev")
|
||||
add_pair(f"_ZNK5uking2ai{len(name)}{name}27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE")
|
||||
add_pair(f"_ZNK5uking2ai{len(name)}{name}18getRuntimeTypeInfoEv")
|
||||
return pairs
|
||||
|
||||
if type_ == "Action":
|
||||
action_vtable_names = ai_common.get_action_vtable_names()
|
||||
identify(functions, checker, new_matches, action_vtable_names.values(), get_action_pairs)
|
||||
if type_ == "AI":
|
||||
ai_vtable_names = ai_common.get_ai_vtable_names()
|
||||
identify(functions, checker, new_matches, ai_vtable_names.values(), get_ai_pairs)
|
||||
elif type_ == "Query":
|
||||
identify(functions, checker, new_matches, aidef["Querys"].keys(), get_query_pairs)
|
||||
|
||||
utils.add_decompiled_functions(new_matches)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
43
tools/ai_progress.py
Executable file
43
tools/ai_progress.py
Executable file
@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
from typing import Dict, Optional
|
||||
|
||||
import yaml
|
||||
from colorama import Fore
|
||||
|
||||
from util import utils
|
||||
|
||||
# TODO: add behaviors after they have been generated
|
||||
_TYPES = ("action", "ai", "query")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser("Print AI class decompilation progress.")
|
||||
parser.add_argument("-t", "--type", help="AI class type", choices=_TYPES)
|
||||
args = parser.parse_args()
|
||||
|
||||
filter_type: Optional[str] = args.type
|
||||
|
||||
data_path = utils.get_repo_root() / "data"
|
||||
for class_type in _TYPES:
|
||||
if filter_type is not None and class_type != filter_type:
|
||||
continue
|
||||
|
||||
with (data_path / f"status_{class_type}.yml").open() as f:
|
||||
fns: Dict[str, dict] = yaml.load(f, Loader=yaml.CSafeLoader)
|
||||
|
||||
for name, info in fns.items():
|
||||
status = info["status"]
|
||||
if status == "done":
|
||||
color = Fore.GREEN
|
||||
elif status == "wip":
|
||||
color = Fore.YELLOW
|
||||
elif status == "pending":
|
||||
color = ""
|
||||
else:
|
||||
assert False, f"unexpected status {status}"
|
||||
print(f"{color}{name:<50} {color}{info['status']}{Fore.RESET}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
114
tools/ai_show_nontrivial_hierarchies.py
Executable file
114
tools/ai_show_nontrivial_hierarchies.py
Executable file
@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import Union
|
||||
|
||||
import yaml
|
||||
|
||||
from util import ai_common
|
||||
from util.ai_common import BaseClasses
|
||||
from util.graph import Graph
|
||||
|
||||
_known_vtables = {
|
||||
0x71024d8d68: "ActionBase",
|
||||
0x71025129f0: "Action",
|
||||
0x7102513278: "Ai",
|
||||
0x71024d8ef0: "Behavior",
|
||||
0x710243c9b8: "Query",
|
||||
}
|
||||
|
||||
|
||||
def get_name_for_vtable(vtable: Union[str, int]):
|
||||
if isinstance(vtable, str):
|
||||
return vtable
|
||||
|
||||
known_name = _known_vtables.get(vtable, None)
|
||||
if known_name is not None:
|
||||
return f"[V] {known_name}"
|
||||
|
||||
return f"[V] {vtable:#x}"
|
||||
|
||||
|
||||
def guess_vtable_names(reverse_graph: Graph):
|
||||
for u in reverse_graph.nodes:
|
||||
targets = list(reverse_graph.nodes[u])
|
||||
known_targets = list(filter(lambda x: isinstance(x, str), targets))
|
||||
if len(known_targets) == 1:
|
||||
# Leaves can be named pretty easily.
|
||||
_known_vtables[u] = known_targets[0]
|
||||
|
||||
|
||||
def build_graph(all_vtables: dict, type_: str, graph: Graph, reverse_graph: Graph):
|
||||
for name, vtables in all_vtables[type_].items():
|
||||
classes = [name] + list(reversed(vtables))
|
||||
# Each class has at least one parent, so the -1 is fine.
|
||||
for i in range(len(classes) - 1):
|
||||
from_ = classes[i]
|
||||
to_ = classes[i + 1]
|
||||
# Skip base classes to reduce noise.
|
||||
if to_ in BaseClasses:
|
||||
break
|
||||
reverse_graph.add_edge(to_, from_)
|
||||
|
||||
guess_vtable_names(reverse_graph)
|
||||
|
||||
for name, vtables in all_vtables[type_].items():
|
||||
classes = [name] + list(reversed(vtables))
|
||||
for i in range(len(classes) - 1):
|
||||
if classes[i + 1] in BaseClasses:
|
||||
break
|
||||
from_ = get_name_for_vtable(classes[i])
|
||||
to_ = get_name_for_vtable(classes[i + 1])
|
||||
graph.add_edge(from_, to_)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Shows AI classes with non-trivial class hierarchies.")
|
||||
parser.add_argument("--type", help="AI class type to visualise", choices=["Action", "AI", "Behavior", "Query"],
|
||||
required=True)
|
||||
parser.add_argument("--out-names", help="Path to which a vtable -> name map will be written", required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
all_vtables = ai_common.get_vtables()
|
||||
|
||||
graph = Graph()
|
||||
reverse_graph = Graph()
|
||||
build_graph(all_vtables, args.type, graph, reverse_graph)
|
||||
|
||||
interesting_nodes = set()
|
||||
node_colors = dict()
|
||||
|
||||
colors = ["#c7dcff", "#ffc7c7", "#ceffc7", "#dcc7ff", "#fffdc9", "#c9fff3", "#ffe0cc", "#ffcffe", "#96a8ff"]
|
||||
components = graph.find_connected_components()
|
||||
num_nontrivial_cc = 0
|
||||
for i, comp in enumerate(components):
|
||||
if len(comp) == 2:
|
||||
continue
|
||||
for node in comp:
|
||||
node_colors[node] = colors[i % len(colors)]
|
||||
num_nontrivial_cc += 1
|
||||
interesting_nodes |= set(comp)
|
||||
|
||||
print("digraph {")
|
||||
print("node [shape=rectangle]")
|
||||
for u in graph.nodes:
|
||||
if u not in interesting_nodes:
|
||||
continue
|
||||
for v in graph.nodes[u]:
|
||||
shape_u = "shape=component," if "[V]" not in u else ""
|
||||
shape_v = "shape=component," if "[V]" not in v else ""
|
||||
print(f'"{u}" [{shape_u}style=filled, fillcolor="{node_colors[u]}"]')
|
||||
print(f'"{v}" [{shape_v}style=filled, fillcolor="{node_colors[v]}"]')
|
||||
print(f'"{u}" -> "{v}"')
|
||||
print("}")
|
||||
print(f"# {len(components)} connected components")
|
||||
print(f"# {num_nontrivial_cc} non-trivial connected components")
|
||||
|
||||
yaml.add_representer(int, lambda dumper, data: yaml.ScalarNode('tag:yaml.org,2002:int', f"{data:#x}"),
|
||||
Dumper=yaml.CSafeDumper)
|
||||
with Path(args.out_names).open("w") as f:
|
||||
yaml.dump(_known_vtables, f, Dumper=yaml.CSafeDumper)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
2
tools/asm-differ/.gitignore
vendored
Executable file
2
tools/asm-differ/.gitignore
vendored
Executable file
@ -0,0 +1,2 @@
|
||||
.mypy_cache/
|
||||
__pycache__/
|
40
tools/asm-differ/README.md
Executable file
40
tools/asm-differ/README.md
Executable file
@ -0,0 +1,40 @@
|
||||
# asm-differ
|
||||
|
||||
Nice differ for assembly code (MIPS and AArch64; should be easy to hack to support other instruction sets).
|
||||
|
||||
![](screenshot.png)
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Python >= 3.6
|
||||
- `python3 -m pip install --user colorama ansiwrap watchdog python-Levenshtein`
|
||||
|
||||
## Usage
|
||||
|
||||
Create a file `diff-settings.sh` in some directory (see the one in this repo for an example). Then from that directory, run
|
||||
|
||||
```
|
||||
/path/to/diff.sh [flags] (function|rom addr)
|
||||
```
|
||||
|
||||
Recommended flags are `-mwo` (automatically run `make` on source file changes, and include symbols in diff). See `--help` for more details.
|
||||
|
||||
### Tab completion
|
||||
|
||||
[argcomplete](https://kislyuk.github.io/argcomplete/) can be optionally installed (with `python3 -m pip install argcomplete`) to enable tab completion in a bash shell, completing options and symbol names using the linker map. It also requires a bit more setup:
|
||||
|
||||
If invoking the script **exactly** as `./diff.py`, the following should be added to the `.bashrc` according to argcomplete's instructions:
|
||||
|
||||
```sh
|
||||
eval "$(register-python-argcomplete ./diff.py)"
|
||||
```
|
||||
|
||||
If that doesn't work, run `register-python-argcomplete ./diff.py` in your terminal and copy the output to `.bashrc`.
|
||||
|
||||
If setup correctly (don't forget to restart the shell), `complete | grep ./diff.py` should output:
|
||||
|
||||
```
|
||||
complete -o bashdefault -o default -o nospace -F _python_argcomplete ./diff.py
|
||||
```
|
||||
|
||||
Note for developers or for general troubleshooting: run `export _ARC_DEBUG=` to enable debug output during tab-completion, it may show otherwise silenced errors. Use `unset _ARC_DEBUG` or restart the terminal to disable.
|
1607
tools/asm-differ/diff.py
Executable file
1607
tools/asm-differ/diff.py
Executable file
File diff suppressed because it is too large
Load Diff
10
tools/asm-differ/diff_settings.py
Executable file
10
tools/asm-differ/diff_settings.py
Executable file
@ -0,0 +1,10 @@
|
||||
def apply(config, args):
|
||||
config["baseimg"] = "target.bin"
|
||||
config["myimg"] = "source.bin"
|
||||
config["mapfile"] = "build.map"
|
||||
config["source_directories"] = ["."]
|
||||
#config["arch"] = "mips"
|
||||
#config["map_format"] = "gnu" # gnu or mw
|
||||
#config["mw_build_dir"] = "build/" # only needed for mw map format
|
||||
#config["makeflags"] = []
|
||||
#config["objdump_executable"] = ""
|
16
tools/asm-differ/mypy.ini
Executable file
16
tools/asm-differ/mypy.ini
Executable file
@ -0,0 +1,16 @@
|
||||
[mypy]
|
||||
check_untyped_defs = True
|
||||
disallow_any_generics = True
|
||||
disallow_incomplete_defs = True
|
||||
disallow_subclassing_any = True
|
||||
disallow_untyped_calls = True
|
||||
disallow_untyped_decorators = True
|
||||
disallow_untyped_defs = True
|
||||
no_implicit_optional = True
|
||||
warn_redundant_casts = True
|
||||
warn_return_any = True
|
||||
warn_unused_ignores = True
|
||||
python_version = 3.6
|
||||
|
||||
[mypy-diff_settings]
|
||||
ignore_errors = True
|
BIN
tools/asm-differ/screenshot.png
Executable file
BIN
tools/asm-differ/screenshot.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
68
tools/check.py
Executable file
68
tools/check.py
Executable file
@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
from colorama import Fore
|
||||
|
||||
import util.elf
|
||||
import util.checker
|
||||
from util import utils
|
||||
|
||||
|
||||
def check_function(checker: util.checker.FunctionChecker, addr: int, size: int, name: str,
|
||||
base_fn: Optional[util.elf.Function] = None) -> bool:
|
||||
if base_fn is None:
|
||||
try:
|
||||
base_fn = util.elf.get_fn_from_base_elf(addr, size)
|
||||
except KeyError:
|
||||
utils.print_error(f"couldn't find base function 0x{addr:016x} for {utils.format_symbol_name_for_msg(name)}")
|
||||
return False
|
||||
|
||||
my_fn = util.elf.get_fn_from_my_elf(name)
|
||||
return checker.check(base_fn, my_fn)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
failed = False
|
||||
|
||||
nonmatching_fns_with_dump = {p.stem: util.elf.Function(p.read_bytes(), 0) for p in
|
||||
(utils.get_repo_root() / "expected").glob("*.bin")}
|
||||
|
||||
checker = util.checker.FunctionChecker(log_mismatch_cause=True)
|
||||
|
||||
for func in utils.get_functions():
|
||||
if not func.decomp_name:
|
||||
continue
|
||||
|
||||
try:
|
||||
util.elf.get_fn_from_my_elf(func.decomp_name)
|
||||
except KeyError:
|
||||
utils.warn(f"couldn't find {utils.format_symbol_name_for_msg(func.decomp_name)}")
|
||||
continue
|
||||
|
||||
if func.status == utils.FunctionStatus.Matching:
|
||||
if not check_function(checker, func.addr, func.size, func.decomp_name):
|
||||
utils.print_error(
|
||||
f"function {utils.format_symbol_name_for_msg(func.decomp_name)} is marked as matching but does not match")
|
||||
a1, a2, reason = checker.get_mismatch()
|
||||
if a1 != -1:
|
||||
sys.stderr.write(f" at {a1 | 0x7100000000:#x} : {Fore.CYAN}{reason}{Fore.RESET}\n")
|
||||
failed = True
|
||||
elif func.status == utils.FunctionStatus.Equivalent or func.status == utils.FunctionStatus.NonMatching:
|
||||
if check_function(checker, func.addr, func.size, func.decomp_name):
|
||||
utils.print_note(
|
||||
f"function {utils.format_symbol_name_for_msg(func.decomp_name)} is marked as non-matching but matches")
|
||||
|
||||
fn_dump = nonmatching_fns_with_dump.get(func.decomp_name, None)
|
||||
if fn_dump is not None and not check_function(checker, func.addr, len(fn_dump), func.decomp_name, fn_dump):
|
||||
utils.print_error(
|
||||
f"function {utils.format_symbol_name_for_msg(func.decomp_name)} does not match expected output")
|
||||
failed = True
|
||||
|
||||
if failed:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
8
tools/createFunctionCSV.py
Normal file
8
tools/createFunctionCSV.py
Normal file
@ -0,0 +1,8 @@
|
||||
import idaapi
|
||||
import idautils
|
||||
|
||||
with open("/tmp/funclist.csv", "w") as f:
|
||||
for ea in idautils.Functions():
|
||||
size = idaapi.get_func(ea).size()
|
||||
name = idaapi.get_func_name(ea)
|
||||
f.write(",".join(("0x%016lx" % ea, name, str(size), "")) + "\n")
|
61
tools/diff.py
Executable file
61
tools/diff.py
Executable file
@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import subprocess
|
||||
|
||||
import cxxfilt
|
||||
from colorama import Fore, Style
|
||||
|
||||
from util import utils
|
||||
import util.checker
|
||||
import check
|
||||
|
||||
parser = argparse.ArgumentParser(description="Diff assembly")
|
||||
parser.add_argument(
|
||||
"function", help="Name of the function to diff. Pass | to get a WIP function", nargs="?", default="|")
|
||||
args, unknown = parser.parse_known_args()
|
||||
|
||||
find_wip = args.function == "|"
|
||||
|
||||
|
||||
def find_function_info(name: str):
|
||||
for info in utils.get_functions():
|
||||
if info.decomp_name == name or (find_wip and info.status == utils.FunctionStatus.Wip):
|
||||
return info
|
||||
|
||||
for info in utils.get_functions():
|
||||
if name in cxxfilt.demangle(info.decomp_name):
|
||||
return info
|
||||
|
||||
return None
|
||||
|
||||
def check_func(info):
|
||||
checker = util.checker.FunctionChecker(log_mismatch_cause=True)
|
||||
return check.check_function(checker, info.addr, info.size, info.decomp_name)
|
||||
|
||||
info = find_function_info(args.function)
|
||||
if info is not None:
|
||||
if not info.decomp_name:
|
||||
utils.fail(f"{args.function} has not been decompiled")
|
||||
|
||||
print("comparing functions...")
|
||||
if(check_func(info)):
|
||||
print("matching function!")
|
||||
else:
|
||||
print(
|
||||
f"diffing: {Style.BRIGHT}{Fore.BLUE}{cxxfilt.demangle(info.decomp_name)}{Style.RESET_ALL} {Style.DIM}({info.decomp_name}){Style.RESET_ALL}")
|
||||
addr_end = info.addr + info.size
|
||||
subprocess.call(["tools/asm-differ/diff.py", "-I", "-e", info.decomp_name, "0x%016x" %
|
||||
info.addr, "0x%016x" % addr_end] + unknown)
|
||||
|
||||
if info.status == utils.FunctionStatus.NonMatching:
|
||||
utils.warn(
|
||||
f"{info.decomp_name} is marked as non-matching and possibly NOT functionally equivalent")
|
||||
elif info.status == utils.FunctionStatus.Equivalent:
|
||||
utils.warn(f"{info.decomp_name} is marked as functionally equivalent but non-matching")
|
||||
|
||||
else:
|
||||
if find_wip:
|
||||
utils.fail("no WIP function")
|
||||
|
||||
utils.fail(
|
||||
f"unknown function '{args.function}'\nfor constructors and destructors, list the complete object constructor (C1) or destructor (D1)")
|
23
tools/diff_settings.py
Executable file
23
tools/diff_settings.py
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def apply(config, args):
|
||||
config['arch'] = 'aarch64'
|
||||
config['baseimg'] = 'data/main.elf'
|
||||
config['myimg'] = 'build/odyssey'
|
||||
config['source_directories'] = ['src', 'lib']
|
||||
config['objdump_executable'] = 'tools/aarch64-none-elf-objdump'
|
||||
|
||||
for dir in ('build', 'build/nx64-release'):
|
||||
if (Path(dir) / 'build.ninja').is_file():
|
||||
config['make_command'] = ['ninja', '-C', dir]
|
||||
|
||||
|
||||
def map_build_target(make_target: str):
|
||||
if make_target == "build/odyssey":
|
||||
return "odyssey"
|
||||
|
||||
# TODO: When support for directly diffing object files is added, this needs to strip
|
||||
# the build/ prefix from the object file targets.
|
||||
return make_target
|
29
tools/dump_function.py
Executable file
29
tools/dump_function.py
Executable file
@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
|
||||
import util.elf
|
||||
from util import utils
|
||||
|
||||
|
||||
def dump_fn(name: str) -> None:
|
||||
expected_dir = utils.get_repo_root() / "expected"
|
||||
try:
|
||||
fn = util.elf.get_fn_from_my_elf(name)
|
||||
path = expected_dir / f"{name}.bin"
|
||||
path.parent.mkdir(exist_ok=True)
|
||||
path.write_bytes(fn.data)
|
||||
except KeyError:
|
||||
utils.fail("could not find function")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("function_name", help="Name of the function to dump")
|
||||
args = parser.parse_args()
|
||||
|
||||
dump_fn(args.function_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
131
tools/generate_bgparamlist_struct.py
Executable file
131
tools/generate_bgparamlist_struct.py
Executable file
@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
import oead
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _parse_parameter_archive(path: Path) -> oead.aamp.ParameterIO:
|
||||
data = path.read_bytes()
|
||||
try:
|
||||
return oead.aamp.ParameterIO.from_binary(data)
|
||||
except:
|
||||
return oead.aamp.ParameterIO.from_text(data)
|
||||
|
||||
|
||||
_AampTypeToAglUtlParameterType = {
|
||||
oead.aamp.Parameter.Type.Bool: "agl::utl::Parameter<bool>",
|
||||
oead.aamp.Parameter.Type.F32: "agl::utl::Parameter<f32>",
|
||||
oead.aamp.Parameter.Type.Int: "agl::utl::Parameter<s32>",
|
||||
oead.aamp.Parameter.Type.Vec2: "agl::utl::Parameter<sead::Vector2f>",
|
||||
oead.aamp.Parameter.Type.Vec3: "agl::utl::Parameter<sead::Vector3f>",
|
||||
oead.aamp.Parameter.Type.Vec4: "agl::utl::Parameter<sead::Vector4f>",
|
||||
oead.aamp.Parameter.Type.Color: "agl::utl::Parameter<sead::Color4f>",
|
||||
oead.aamp.Parameter.Type.String32: "agl::utl::Parameter<sead::SafeString>",
|
||||
oead.aamp.Parameter.Type.String64: "agl::utl::Parameter<sead::SafeString>",
|
||||
oead.aamp.Parameter.Type.Curve1: "agl::utl::ParameterCurve<1>",
|
||||
oead.aamp.Parameter.Type.Curve2: "agl::utl::ParameterCurve<2>",
|
||||
oead.aamp.Parameter.Type.Curve3: "agl::utl::ParameterCurve<3>",
|
||||
oead.aamp.Parameter.Type.Curve4: "agl::utl::ParameterCurve<4>",
|
||||
oead.aamp.Parameter.Type.BufferInt: "agl::utl::ParameterBuffer<s32>",
|
||||
oead.aamp.Parameter.Type.BufferF32: "agl::utl::ParameterBuffer<f32>",
|
||||
oead.aamp.Parameter.Type.String256: "agl::utl::Parameter<sead::SafeString>",
|
||||
oead.aamp.Parameter.Type.Quat: "agl::utl::Parameter<sead::Quatf>",
|
||||
oead.aamp.Parameter.Type.U32: "agl::utl::Parameter<u32>",
|
||||
oead.aamp.Parameter.Type.BufferU32: "agl::utl::ParameterBuffer<u32>",
|
||||
oead.aamp.Parameter.Type.BufferBinary: "agl::utl::ParameterBuffer<u8>",
|
||||
oead.aamp.Parameter.Type.StringRef: "agl::utl::Parameter<sead::SafeString>",
|
||||
}
|
||||
|
||||
|
||||
def _aamp_type_to_agl_utl_parameter_type(type_: oead.aamp.Parameter.Type) -> str:
|
||||
return _AampTypeToAglUtlParameterType[type_]
|
||||
|
||||
|
||||
def _represent_float(value: float) -> str:
|
||||
s = f'{value:g}'
|
||||
if 'e' not in s and '.' not in s:
|
||||
s += '.0'
|
||||
return s
|
||||
|
||||
|
||||
def _get_value_repr(value) -> str:
|
||||
v = value.v
|
||||
|
||||
if isinstance(v, bool):
|
||||
return "true" if v else "false"
|
||||
|
||||
if isinstance(v, oead.FixedSafeString32) or isinstance(v, oead.FixedSafeString64) or isinstance(v, oead.FixedSafeString256) or isinstance(v, str):
|
||||
return json.dumps(str(v))
|
||||
|
||||
if isinstance(v, oead.Vector2f):
|
||||
return f"{{{_represent_float(v.x)}, {_represent_float(v.y)}}}"
|
||||
|
||||
if isinstance(v, oead.Vector3f):
|
||||
return f"{{{_represent_float(v.x)}, {_represent_float(v.y)}, {_represent_float(v.z)}}}"
|
||||
|
||||
if isinstance(v, oead.Vector4f):
|
||||
return f"{{{_represent_float(v.x)}, {_represent_float(v.y)}, {_represent_float(v.z)}, {_represent_float(v.t)}}}"
|
||||
|
||||
if isinstance(v, float):
|
||||
return _represent_float(v)
|
||||
|
||||
return repr(v)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("bgparamlist_path", type=Path,
|
||||
help="Path to Dummy.bgparamlist (text or binary)")
|
||||
parser.add_argument("--object", required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
name_table = oead.aamp.get_default_name_table()
|
||||
|
||||
pio = _parse_parameter_archive(args.bgparamlist_path)
|
||||
pobj = pio.objects[args.object]
|
||||
|
||||
class_name = f"GParamListObject{args.object}"
|
||||
|
||||
# Includes
|
||||
print("""\
|
||||
#pragma once
|
||||
|
||||
#include <agl/Utils/aglParameter.h>
|
||||
#include "KingSystem/Resource/GeneralParamList/resGParamListObject.h"
|
||||
#include "KingSystem/Utils/Types.h"
|
||||
|
||||
namespace ksys::res {
|
||||
""")
|
||||
|
||||
# Generate the class definition.
|
||||
print(f"class {class_name} : public GParamListObject {{")
|
||||
print(f"public:")
|
||||
print(f" {class_name}();")
|
||||
print(f' const char* getName() const override {{ return "{args.object}"; }}')
|
||||
print()
|
||||
for key, value in pobj.params.items():
|
||||
name = name_table.get_name(key.hash, 0, 0)
|
||||
assert name
|
||||
type_str = _aamp_type_to_agl_utl_parameter_type(value.type())
|
||||
print(f" {type_str} m{name};")
|
||||
print("};")
|
||||
print()
|
||||
|
||||
# Generate the constructor now.
|
||||
print(f"inline {class_name}::{class_name}() {{")
|
||||
print(" auto* const obj = &mObj;")
|
||||
print()
|
||||
for key, value in pobj.params.items():
|
||||
name = name_table.get_name(key.hash, 0, 0)
|
||||
assert name
|
||||
default_value_repr = _get_value_repr(value)
|
||||
print(f' m{name}.init({default_value_repr}, "{name}", "", obj);')
|
||||
print("}")
|
||||
|
||||
print()
|
||||
print("} // namespace ksys::res")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
346
tools/generate_gdt_common_flags.py
Executable file
346
tools/generate_gdt_common_flags.py
Executable file
@ -0,0 +1,346 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import typing as tp
|
||||
|
||||
import oead
|
||||
|
||||
|
||||
class FlagTypeInfo(tp.NamedTuple):
|
||||
def get_getter_fn_name(self) -> str:
|
||||
return self.getter_fn_name
|
||||
|
||||
def get_handle_getter_fn_name(self) -> str:
|
||||
s = self.getter_fn_name
|
||||
if self.is_value_array():
|
||||
s += "Array"
|
||||
s += "Handle"
|
||||
return s
|
||||
|
||||
def get_setter_fn_name(self) -> str:
|
||||
return "s" + self.getter_fn_name[1:]
|
||||
|
||||
def is_value_inline(self) -> bool:
|
||||
return self.arg_type in ("bool", "s32", "f32")
|
||||
|
||||
def is_value_array(self) -> bool:
|
||||
return self.is_array
|
||||
|
||||
def get_setter_arg_type(self) -> str:
|
||||
return self.setter_arg_type if self.setter_arg_type else self.arg_type
|
||||
|
||||
getter_fn_name: str
|
||||
arg_type: str
|
||||
setter_arg_type: str = ""
|
||||
is_array: bool = False
|
||||
|
||||
|
||||
flag_type_info = {
|
||||
"bool_data": FlagTypeInfo("getBool", "bool"),
|
||||
"s32_data": FlagTypeInfo("getS32", "s32"),
|
||||
"f32_data": FlagTypeInfo("getF32", "f32"),
|
||||
"string_data": FlagTypeInfo("getStr", "char const*", "const sead::SafeString&"),
|
||||
"string64_data": FlagTypeInfo("getStr64", "char const*", "const sead::SafeString&"),
|
||||
"string256_data": FlagTypeInfo("getStr256", "char const*", "const sead::SafeString&"),
|
||||
"vector2f_data": FlagTypeInfo("getVec2f", "sead::Vector2f", "const sead::Vector2f&"),
|
||||
"vector3f_data": FlagTypeInfo("getVec3f", "sead::Vector3f", "const sead::Vector3f&"),
|
||||
"vector4f_data": FlagTypeInfo("getVec4f", "sead::Vector4f", "const sead::Vector4f&"),
|
||||
|
||||
"bool_array_data": FlagTypeInfo("getBool", "bool", is_array=True),
|
||||
"s32_array_data": FlagTypeInfo("getS32", "s32", is_array=True),
|
||||
"f32_array_data": FlagTypeInfo("getF32", "f32", is_array=True),
|
||||
"string_array_data": FlagTypeInfo("getStr", "char const*", "const sead::SafeString&", is_array=True),
|
||||
"string64_array_data": FlagTypeInfo("getStr64", "char const*", "const sead::SafeString&", is_array=True),
|
||||
"string256_array_data": FlagTypeInfo("getStr256", "char const*", "const sead::SafeString&", is_array=True),
|
||||
"vector2f_array_data": FlagTypeInfo("getVec2f", "sead::Vector2f", "const sead::Vector2f&", is_array=True),
|
||||
"vector3f_array_data": FlagTypeInfo("getVec3f", "sead::Vector3f", "const sead::Vector3f&", is_array=True),
|
||||
"vector4f_array_data": FlagTypeInfo("getVec4f", "sead::Vector4f", "const sead::Vector4f&", is_array=True),
|
||||
}
|
||||
|
||||
|
||||
def add_development_remnant_flags(flags: tp.Dict[str, str]):
|
||||
_flags = {
|
||||
"AoC_DragonFireChallengeRing_Advent": "bool_data",
|
||||
"AoC_RandomSpawnTreasure_Contents": "string64_array_data",
|
||||
"AoC_RandomSpawnTreasure_IsRandomized": "bool_data",
|
||||
"AoC_TestProg_Imoto_Flag_00": "bool_data",
|
||||
"AoC_TestProg_Imoto_TagCount_00": "s32_data",
|
||||
"AocTestEx_Omosako_IsPastWorld": "bool_data",
|
||||
"AocTestEx_Omosako_ReturnToMainField_Position": "vector3f_data",
|
||||
"AocTestEx_Omosako_ReturnToMainField_Rotation": "f32_data",
|
||||
"AocTestEx_Omosako_SandOfTime_Num": "s32_data",
|
||||
"AocTestEx_Omosako_SandOfTime_Rate": "f32_data",
|
||||
"Location_DarkDungeon01": "s32_data",
|
||||
"Location_DarkDungeon02": "s32_data",
|
||||
"Location_DarkDungeon03": "s32_data",
|
||||
"Location_DarkDungeon04": "s32_data",
|
||||
"SpurGear_revolve_01": "bool_data",
|
||||
"SpurGear_revolve_02": "bool_data",
|
||||
}
|
||||
flags.update(_flags)
|
||||
|
||||
|
||||
def load_flag_types(root: Path) -> tp.Dict[str, str]:
|
||||
flag_types: tp.Dict[str, str] = dict()
|
||||
add_development_remnant_flags(flag_types)
|
||||
|
||||
gdt_dir = root / "GameData"
|
||||
for path in gdt_dir.glob("Flag/*.yml"):
|
||||
flag_list = oead.byml.from_text(path.read_text(encoding="utf-8"))
|
||||
keys = list(flag_list.keys())
|
||||
assert len(keys) == 1
|
||||
flag_type = keys[0]
|
||||
for flag in flag_list[flag_type]:
|
||||
flag_types[flag["DataName"]] = flag_type
|
||||
|
||||
return flag_types
|
||||
|
||||
|
||||
def write_struct_chunk(f: tp.TextIO, flags: tp.Collection[str], i: int) -> None:
|
||||
f.write(f"""\
|
||||
struct CommonFlags{i} {{
|
||||
""")
|
||||
for name in flags:
|
||||
f.write(f" FlagHandle flag_{name} = InvalidHandle;\n")
|
||||
f.write(f"""\
|
||||
u32 _pad = 0;
|
||||
}};
|
||||
|
||||
[[gnu::visibility("hidden")]] extern CommonFlags{i} sCommonFlags{i};
|
||||
""")
|
||||
|
||||
|
||||
FLAGS_PER_CHUNK = 1023
|
||||
|
||||
|
||||
def chunk_flag_iterator(flags: tp.Iterator[str]):
|
||||
while True:
|
||||
chunk = []
|
||||
for i in range(FLAGS_PER_CHUNK):
|
||||
try:
|
||||
chunk.append(next(flags))
|
||||
except StopIteration:
|
||||
break
|
||||
|
||||
if not chunk:
|
||||
return
|
||||
|
||||
yield chunk
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("root", help="Path to the root of the GameROM source")
|
||||
parser.add_argument("exe_flag_list", help="Path to a file containing a list of flags")
|
||||
args = parser.parse_args()
|
||||
|
||||
src_root = Path(__file__).parent.parent
|
||||
src_gdt = src_root / "src" / "KingSystem" / "GameData"
|
||||
root = Path(args.root)
|
||||
exe_flag_list = Path(args.exe_flag_list).read_text().splitlines()
|
||||
flag_types = load_flag_types(root)
|
||||
|
||||
with (src_gdt / "gdtCommonFlags.h").open("w") as f:
|
||||
f.write("""\
|
||||
#pragma once
|
||||
|
||||
// DO NOT EDIT. This file is automatically generated.
|
||||
|
||||
#include "KingSystem/GameData/gdtManager.h"
|
||||
|
||||
namespace ksys::gdt {
|
||||
|
||||
// clang-format off
|
||||
|
||||
namespace detail {
|
||||
|
||||
""")
|
||||
for i, chunk in enumerate(chunk_flag_iterator(iter(exe_flag_list))):
|
||||
write_struct_chunk(f, chunk, i)
|
||||
f.write("\n")
|
||||
f.write("""\
|
||||
} // namespace detail
|
||||
|
||||
void initCommonFlags();
|
||||
|
||||
""")
|
||||
|
||||
for i, name in enumerate(exe_flag_list):
|
||||
chunk_idx: int = i // FLAGS_PER_CHUNK
|
||||
f.write(f"inline FlagHandle& flag_{name}() {{ return detail::sCommonFlags{chunk_idx}.flag_{name}; }}\n")
|
||||
|
||||
f.write("""\
|
||||
|
||||
// clang-format on
|
||||
|
||||
} // namespace ksys::gdt
|
||||
""")
|
||||
|
||||
# Generate the implementation.
|
||||
with (src_gdt / "gdtCommonFlags.cpp").open("w") as f:
|
||||
f.write("""\
|
||||
// DO NOT EDIT. This file is automatically generated.
|
||||
|
||||
#include "KingSystem/GameData/gdtCommonFlags.h"
|
||||
|
||||
namespace ksys::gdt {
|
||||
|
||||
namespace detail {
|
||||
|
||||
""")
|
||||
for i in range(len(exe_flag_list) // FLAGS_PER_CHUNK + 1):
|
||||
f.write(f"CommonFlags{i} sCommonFlags{i};\n")
|
||||
f.write("""
|
||||
} // namespace detail
|
||||
|
||||
void initCommonFlags_();
|
||||
|
||||
void initCommonFlags() {
|
||||
initCommonFlags_();
|
||||
}
|
||||
|
||||
void initCommonFlags_() {
|
||||
auto* mgr = Manager::instance();
|
||||
if (!mgr)
|
||||
return;
|
||||
|
||||
// clang-format off
|
||||
|
||||
""")
|
||||
for flag_name in exe_flag_list:
|
||||
info = flag_type_info[flag_types[flag_name]]
|
||||
f.write(f" flag_{flag_name}() = mgr->{info.get_handle_getter_fn_name()}(\"{flag_name}\");\n")
|
||||
|
||||
f.write("""\
|
||||
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
} // namespace ksys::gdt
|
||||
""")
|
||||
|
||||
# Generate gdtCommonFlagsUtils.h
|
||||
with (src_gdt / "gdtCommonFlagsUtils.h").open("w") as f:
|
||||
f.write("""\
|
||||
#pragma once
|
||||
|
||||
// DO NOT EDIT. This file is automatically generated.
|
||||
|
||||
#include "KingSystem/GameData/gdtCommonFlags.h"
|
||||
#include "KingSystem/GameData/gdtFlagUtils.h"
|
||||
|
||||
namespace ksys::gdt {
|
||||
|
||||
// clang-format off
|
||||
|
||||
bool getFlagGenericBool(FlagHandle handle, bool debug = false);
|
||||
s32 getFlagGenericS32(FlagHandle handle, bool debug = false);
|
||||
|
||||
""")
|
||||
for i, name in enumerate(exe_flag_list):
|
||||
info = flag_type_info[flag_types[name]]
|
||||
if info.is_value_array():
|
||||
# Getter
|
||||
if info.is_value_inline():
|
||||
f.write(
|
||||
f"{info.arg_type} getFlag_{name}(s32 idx, bool debug = false);\n")
|
||||
else:
|
||||
f.write(
|
||||
f"void getFlag_{name}({info.arg_type}* value, s32 idx, bool debug = false);\n")
|
||||
# Increase function
|
||||
if info.arg_type == "s32":
|
||||
f.write(f"void increaseFlag_{name}(s32 value, s32 idx, bool debug = false);\n")
|
||||
# Setter
|
||||
f.write(f"void setFlag_{name}({info.get_setter_arg_type()} value, s32 idx, bool debug = false);\n")
|
||||
# Resetter
|
||||
f.write(f"void resetFlag_{name}(s32 idx, bool debug = false);\n")
|
||||
else:
|
||||
# Getter
|
||||
if info.is_value_inline():
|
||||
f.write(
|
||||
f"{info.arg_type} getFlag_{name}(bool debug = false);\n")
|
||||
else:
|
||||
f.write(
|
||||
f"void getFlag_{name}({info.arg_type}* value, bool debug = false);\n")
|
||||
# Increase function
|
||||
if info.arg_type == "s32":
|
||||
f.write(f"void increaseFlag_{name}(s32 value, bool debug = false);\n")
|
||||
# Setter
|
||||
f.write(f"void setFlag_{name}({info.get_setter_arg_type()} value, bool debug = false);\n")
|
||||
# Resetter
|
||||
f.write(f"void resetFlag_{name}(bool debug = false);\n")
|
||||
|
||||
f.write("""\
|
||||
|
||||
// clang-format on
|
||||
|
||||
} // namespace ksys::gdt
|
||||
""")
|
||||
|
||||
# Generate gdtCommonFlagsUtils.cpp
|
||||
with (src_gdt / "gdtCommonFlagsUtils.cpp").open("w") as f:
|
||||
f.write("""\
|
||||
// DO NOT EDIT. This file is automatically generated.
|
||||
|
||||
#include "KingSystem/GameData/gdtCommonFlagsUtils.h"
|
||||
|
||||
namespace ksys::gdt {
|
||||
|
||||
// clang-format off
|
||||
|
||||
bool getFlagGenericBool(FlagHandle handle, bool debug) { return getBool(handle, debug); }
|
||||
s32 getFlagGenericS32(FlagHandle handle, bool debug) { return getS32(handle, debug); }
|
||||
|
||||
""")
|
||||
for i, name in enumerate(exe_flag_list):
|
||||
info = flag_type_info[flag_types[name]]
|
||||
if info.is_value_array():
|
||||
# Getter
|
||||
if info.is_value_inline():
|
||||
f.write(
|
||||
f"{info.arg_type} getFlag_{name}(s32 idx, bool debug) {{ return {info.get_getter_fn_name()}(flag_{name}(), idx, debug); }}\n")
|
||||
else:
|
||||
f.write(
|
||||
f"void getFlag_{name}({info.arg_type}* value, s32 idx, bool debug) {{ {info.get_getter_fn_name()}(flag_{name}(), value, idx, debug); }}\n")
|
||||
# Increase function
|
||||
if info.arg_type == "s32":
|
||||
f.write(f"void increaseFlag_{name}(s32 value, s32 idx, bool debug) {{ "
|
||||
f"increaseS32CommonFlag(value, \"{name}\", idx, debug); }}\n")
|
||||
# Setter
|
||||
f.write(
|
||||
f"void setFlag_{name}({info.get_setter_arg_type()} value, s32 idx, bool debug) {{ "
|
||||
f"{info.get_setter_fn_name()}(value, flag_{name}(), idx, debug); }}\n")
|
||||
# Resetter
|
||||
f.write(
|
||||
f"void resetFlag_{name}(s32 idx, bool debug) {{ "
|
||||
f"re{info.get_setter_fn_name()}(flag_{name}(), idx, debug); }}\n")
|
||||
else:
|
||||
# Getter
|
||||
if info.is_value_inline():
|
||||
f.write(
|
||||
f"{info.arg_type} getFlag_{name}(bool debug) {{ return {info.get_getter_fn_name()}(flag_{name}(), debug); }}\n")
|
||||
else:
|
||||
f.write(
|
||||
f"void getFlag_{name}({info.arg_type}* value, bool debug) {{ {info.get_getter_fn_name()}(flag_{name}(), value, debug); }}\n")
|
||||
# Increase function
|
||||
if info.arg_type == "s32":
|
||||
f.write(f"void increaseFlag_{name}(s32 value, bool debug) {{ "
|
||||
f"increaseS32CommonFlag(value, \"{name}\", -1, debug); }}\n")
|
||||
# Setter
|
||||
f.write(
|
||||
f"void setFlag_{name}({info.get_setter_arg_type()} value, bool debug) {{ "
|
||||
f"{info.get_setter_fn_name()}(value, flag_{name}(), debug); }}\n")
|
||||
# Resetter
|
||||
f.write(
|
||||
f"void resetFlag_{name}(bool debug) {{ re{info.get_setter_fn_name()}(flag_{name}(), debug); }}\n")
|
||||
|
||||
f.write("""\
|
||||
|
||||
// clang-format on
|
||||
|
||||
} // namespace ksys::gdt
|
||||
""")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
94
tools/ida_ai_rename_action_vfns.py
Executable file
94
tools/ida_ai_rename_action_vfns.py
Executable file
@ -0,0 +1,94 @@
|
||||
import struct
|
||||
from typing import Dict
|
||||
|
||||
from util import utils, ai_common
|
||||
import idaapi
|
||||
|
||||
from util.ai_common import BaseClasses
|
||||
|
||||
_vtable_fn_names = [
|
||||
"_ZNK5uking6action{}27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE",
|
||||
"_ZNK5uking6action{}18getRuntimeTypeInfoEv",
|
||||
"_ZN5uking6action{}D2Ev",
|
||||
"_ZN5uking6action{}D0Ev",
|
||||
"_ZNK5uking6action{}8isFailedEv",
|
||||
"_ZNK5uking6action{}10isFinishedEv",
|
||||
"_ZNK5uking6action{}10isFlag4SetEv",
|
||||
"_ZN5uking6action{}14hasPreDeleteCbEv",
|
||||
"_ZN5uking6action{}23hasUpdateForPreDeleteCbEv",
|
||||
"_ZN5uking6action{}2m9Ev",
|
||||
"_ZN5uking6action{}8oneShot_Ev",
|
||||
"_ZN5uking6action{}5init_EPN4sead4HeapE",
|
||||
"_ZN5uking6action{}6enter_EPN4ksys3act2ai15InlineParamPackE",
|
||||
"_ZN5uking6action{}8reenter_EPS2_b",
|
||||
"_ZN5uking6action{}6leave_Ev",
|
||||
"_ZN5uking6action{}11loadParams_Ev",
|
||||
"_ZN5uking6action{}14handleMessage_EPN4ksys3mes7MessageE",
|
||||
"_ZN5uking6action{}15handleMessage2_EPN4ksys3mes7MessageE",
|
||||
"_ZN5uking6action{}18updateForPreDeleteEv",
|
||||
"_ZN5uking6action{}11onPreDeleteEv",
|
||||
"_ZN5uking6action{}4calcEv",
|
||||
"_ZNK5uking6action{}14getCurrentNameEPN4sead22BufferedSafeStringBaseIcEEPS2_",
|
||||
"_ZN5uking6action{}11changeChildERKN4sead14SafeStringBaseIcEE",
|
||||
"_ZNK5uking6action{}9getParamsEPN4ksys3act2ai18ParamNameTypePairsEb",
|
||||
"_ZNK5uking6action{}14getNumChildrenEv",
|
||||
"_ZN5uking6action{}12initChildrenERKN4ksys8AIDefSetEPN4sead4HeapE",
|
||||
"_ZNK5uking6action{}15getCurrentChildEv",
|
||||
"_ZNK5uking6action{}7getTypeEv",
|
||||
"_ZN5uking6action{}7reenterEPS2_RKN4sead14SafeStringBaseIcEE",
|
||||
"_ZN5uking6action{}9postLeaveEv",
|
||||
"_ZNK5uking6action{}8getChildEi",
|
||||
"_ZN5uking6action{}5calc_Ev",
|
||||
]
|
||||
|
||||
|
||||
def format_fn_name(name: str, class_name: str):
|
||||
return name.format(f"{len(class_name)}{class_name}")
|
||||
|
||||
|
||||
def iterate_vtable(vtable_addr):
|
||||
ea = vtable_addr
|
||||
while True:
|
||||
fn_ea = struct.unpack('<Q', idaapi.get_bytes(ea, 8))[0]
|
||||
if idaapi.get_name(fn_ea) != "__cxa_pure_virtual" and not idaapi.is_func(idaapi.get_flags(fn_ea)):
|
||||
return
|
||||
yield fn_ea
|
||||
ea += 8
|
||||
|
||||
|
||||
_ida_base = 0x7100000000
|
||||
|
||||
|
||||
def main() -> None:
|
||||
all_vtables = ai_common.get_vtables()
|
||||
names = ai_common.get_action_vtable_names()
|
||||
not_decompiled = {func.addr for func in utils.get_functions() if func.status == utils.FunctionStatus.NotDecompiled}
|
||||
|
||||
new_names: Dict[int, str] = dict()
|
||||
|
||||
order = ai_common.topologically_sort_vtables(all_vtables, "Action")
|
||||
for vtable_addr in order:
|
||||
if vtable_addr in BaseClasses:
|
||||
continue
|
||||
|
||||
class_name = names.get(vtable_addr)
|
||||
for i, fn_ea in enumerate(iterate_vtable(vtable_addr)):
|
||||
if idaapi.get_name(fn_ea) == "__cxa_pure_virtual":
|
||||
continue
|
||||
|
||||
real_fn_ea = fn_ea & ~_ida_base
|
||||
if real_fn_ea not in new_names:
|
||||
if i < len(_vtable_fn_names):
|
||||
new_names[real_fn_ea] = format_fn_name(_vtable_fn_names[i], class_name)
|
||||
else:
|
||||
# Unknown member function.
|
||||
new_names[real_fn_ea] = f"uking::action::{class_name}::m{i}"
|
||||
|
||||
if real_fn_ea in not_decompiled:
|
||||
idaapi.set_name(fn_ea, new_names[real_fn_ea])
|
||||
|
||||
utils.add_decompiled_functions(dict(), new_names)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
96
tools/ida_ai_rename_ai_vfns.py
Executable file
96
tools/ida_ai_rename_ai_vfns.py
Executable file
@ -0,0 +1,96 @@
|
||||
import struct
|
||||
from typing import Dict
|
||||
|
||||
from util import utils, ai_common
|
||||
import idaapi
|
||||
|
||||
from util.ai_common import BaseClasses
|
||||
|
||||
_vtable_fn_names = [
|
||||
"_ZNK5uking2ai{}27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE",
|
||||
"_ZNK5uking2ai{}18getRuntimeTypeInfoEv",
|
||||
"_ZN5uking2ai{}D2Ev",
|
||||
"_ZN5uking2ai{}D0Ev",
|
||||
"_ZNK5uking2ai{}8isFailedEv",
|
||||
"_ZNK5uking2ai{}10isFinishedEv",
|
||||
"_ZNK5uking2ai{}10isFlag4SetEv",
|
||||
"_ZN5uking2ai{}14hasPreDeleteCbEv",
|
||||
"_ZN5uking2ai{}23hasUpdateForPreDeleteCbEv",
|
||||
"_ZN5uking2ai{}2m9Ev",
|
||||
"_ZN5uking2ai{}8oneShot_Ev",
|
||||
"_ZN5uking2ai{}5init_EPN4sead4HeapE",
|
||||
"_ZN5uking2ai{}6enter_EPN4ksys3act2ai15InlineParamPackE",
|
||||
"_ZN5uking2ai{}8reenter_EPS2_b",
|
||||
"_ZN5uking2ai{}6leave_Ev",
|
||||
"_ZN5uking2ai{}11loadParams_Ev",
|
||||
"_ZN5uking2ai{}14handleMessage_EPN4ksys3mes7MessageE",
|
||||
"_ZN5uking2ai{}15handleMessage2_EPN4ksys3mes7MessageE",
|
||||
"_ZN5uking2ai{}18updateForPreDeleteEv",
|
||||
"_ZN5uking2ai{}11onPreDeleteEv",
|
||||
"_ZN5uking2ai{}4calcEv",
|
||||
"_ZNK5uking2ai{}14getCurrentNameEPN4sead22BufferedSafeStringBaseIcEEPS2_",
|
||||
"_ZN5uking2ai{}11changeChildERKN4sead14SafeStringBaseIcEE",
|
||||
"_ZNK5uking2ai{}9getParamsEPN4ksys3act2ai18ParamNameTypePairsEb",
|
||||
"_ZNK5uking2ai{}14getNumChildrenEv",
|
||||
"_ZN5uking2ai{}12initChildrenERKN4ksys8AIDefSetEPN4sead4HeapE",
|
||||
"_ZNK5uking2ai{}15getCurrentChildEv",
|
||||
"_ZNK5uking2ai{}7getTypeEv",
|
||||
"_ZN5uking2ai{}7reenterEPS2_RKN4sead14SafeStringBaseIcEE",
|
||||
"_ZN5uking2ai{}9postLeaveEv",
|
||||
"_ZNK5uking2ai{}8getChildEi",
|
||||
"_ZNK5uking2ai{}8getNamesEPN4sead22BufferedSafeStringBaseIcEE",
|
||||
"_ZN5uking2ai{}5calc_Ev",
|
||||
"_ZN5uking2ai{}25handlePendingChildChange_Ev",
|
||||
]
|
||||
|
||||
|
||||
def format_fn_name(name: str, class_name: str):
|
||||
return name.format(f"{len(class_name)}{class_name}")
|
||||
|
||||
|
||||
def iterate_vtable(vtable_addr):
|
||||
ea = vtable_addr
|
||||
while True:
|
||||
fn_ea = struct.unpack('<Q', idaapi.get_bytes(ea, 8))[0]
|
||||
if idaapi.get_name(fn_ea) != "__cxa_pure_virtual" and not idaapi.is_func(idaapi.get_flags(fn_ea)):
|
||||
return
|
||||
yield fn_ea
|
||||
ea += 8
|
||||
|
||||
|
||||
_ida_base = 0x7100000000
|
||||
|
||||
|
||||
def main() -> None:
|
||||
all_vtables = ai_common.get_vtables()
|
||||
names = ai_common.get_ai_vtable_names()
|
||||
not_decompiled = {func.addr for func in utils.get_functions() if func.status == utils.FunctionStatus.NotDecompiled}
|
||||
|
||||
new_names: Dict[int, str] = dict()
|
||||
|
||||
order = ai_common.topologically_sort_vtables(all_vtables, "AI")
|
||||
for vtable_addr in order:
|
||||
if vtable_addr in BaseClasses:
|
||||
continue
|
||||
|
||||
class_name = names.get(vtable_addr)
|
||||
for i, fn_ea in enumerate(iterate_vtable(vtable_addr)):
|
||||
if idaapi.get_name(fn_ea) == "__cxa_pure_virtual":
|
||||
continue
|
||||
|
||||
real_fn_ea = fn_ea & ~_ida_base
|
||||
if real_fn_ea not in new_names:
|
||||
if i < len(_vtable_fn_names):
|
||||
new_names[real_fn_ea] = format_fn_name(_vtable_fn_names[i], class_name)
|
||||
else:
|
||||
# Unknown member function.
|
||||
new_names[real_fn_ea] = f"uking::ai::{class_name}::m{i}"
|
||||
|
||||
if real_fn_ea in not_decompiled:
|
||||
idaapi.set_name(fn_ea, new_names[real_fn_ea])
|
||||
|
||||
utils.add_decompiled_functions(dict(), new_names)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
31
tools/ida_generate_gdt_common_flags_list.py
Executable file
31
tools/ida_generate_gdt_common_flags_list.py
Executable file
@ -0,0 +1,31 @@
|
||||
# This script needs to be compatible with Python 2.7 as it is executed in IDA.
|
||||
|
||||
import idaapi
|
||||
import idautils
|
||||
import idc
|
||||
import os
|
||||
|
||||
# only valid in 1.5.0
|
||||
LOAD_SAVEDATA_FUNCTION_START = 0x71008BF8A0
|
||||
LOAD_SAVEDATA_FUNCTION_END = 0x71008E3DB8
|
||||
CRC32_FUNCTION_EA = 0x7100B2170C
|
||||
SAVEDATA_STRUCT = 0x710246F9E0
|
||||
|
||||
with open(os.path.dirname(os.path.realpath(__file__)) + "/../build/gdt_common_flags.txt", "w") as file:
|
||||
struct_offset = 0
|
||||
for ref in idautils.CodeRefsTo(idc.GetFunctionAttr(CRC32_FUNCTION_EA, idc.FUNCATTR_START), 1):
|
||||
if not (LOAD_SAVEDATA_FUNCTION_START < ref < LOAD_SAVEDATA_FUNCTION_END):
|
||||
continue
|
||||
|
||||
string_xref = idaapi.get_arg_addrs(ref)[0]
|
||||
iterator = idautils.XrefsFrom(string_xref, 0)
|
||||
next(iterator)
|
||||
string_addr = next(iterator).to
|
||||
string = idc.GetString(string_addr)
|
||||
|
||||
# For some reason the struct includes dummy members that should be skipped.
|
||||
if idaapi.get_dword(SAVEDATA_STRUCT + struct_offset) == 0:
|
||||
struct_offset += 4
|
||||
|
||||
file.write("%s\n" % string)
|
||||
struct_offset += 4
|
12
tools/ida_remove_function_tails.py
Executable file
12
tools/ida_remove_function_tails.py
Executable file
@ -0,0 +1,12 @@
|
||||
import idaapi
|
||||
|
||||
for i in range(idaapi.get_fchunk_qty()):
|
||||
chunk = idaapi.getn_fchunk(i)
|
||||
if not idaapi.is_func_tail(chunk):
|
||||
continue
|
||||
|
||||
ea = chunk.start_ea
|
||||
print("removing tail 0x%016x" % ea)
|
||||
parent = idaapi.get_func(ea)
|
||||
idaapi.remove_func_tail(parent, ea)
|
||||
idaapi.add_func(ea)
|
80
tools/identify_matching_functions.py
Executable file
80
tools/identify_matching_functions.py
Executable file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
from colorama import Fore
|
||||
import csv
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict
|
||||
|
||||
import util.checker
|
||||
import util.elf
|
||||
from util import utils
|
||||
|
||||
|
||||
def read_candidates(path: Path) -> Dict[str, util.elf.Function]:
|
||||
candidates: Dict[str, util.elf.Function] = dict()
|
||||
|
||||
for candidate in path.read_text().splitlines():
|
||||
columns = candidate.split()
|
||||
if len(columns) == 3:
|
||||
candidate = columns[2]
|
||||
|
||||
candidates[candidate] = util.elf.get_fn_from_my_elf(candidate)
|
||||
|
||||
return candidates
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("csv_path",
|
||||
help="Path to a list of functions to identify (in the same format as the main function CSV)")
|
||||
parser.add_argument("candidates_path",
|
||||
help="Path to a list of candidates (names only)")
|
||||
args = parser.parse_args()
|
||||
|
||||
csv_path = Path(args.csv_path)
|
||||
candidates_path = Path(args.candidates_path)
|
||||
|
||||
candidates = read_candidates(candidates_path)
|
||||
|
||||
new_matches: Dict[int, str] = dict()
|
||||
checker = util.checker.FunctionChecker()
|
||||
|
||||
# Given a list L of functions to identify and a small list of candidates C, this tool will attempt to
|
||||
# automatically identify matches by checking each function in L against each function in C.
|
||||
#
|
||||
# This matching algorithm is quite naive (quadratic time complexity if both lists have about the same size)
|
||||
# but this should work well enough for short lists of candidates...
|
||||
for func in utils.get_functions(csv_path):
|
||||
if func.status != utils.FunctionStatus.NotDecompiled:
|
||||
continue
|
||||
|
||||
match_name = ""
|
||||
|
||||
for candidate_name, candidate in candidates.items():
|
||||
if len(candidate.data) != func.size:
|
||||
continue
|
||||
if checker.check(util.elf.get_fn_from_base_elf(func.addr, func.size), candidate):
|
||||
match_name = candidate_name
|
||||
break
|
||||
|
||||
if match_name:
|
||||
new_matches[func.addr] = match_name
|
||||
utils.print_note(
|
||||
f"found new match: {Fore.BLUE}{match_name}{Fore.RESET} ({func.addr | 0x71_00000000:#018x})")
|
||||
# This is no longer a candidate.
|
||||
del candidates[match_name]
|
||||
else:
|
||||
utils.warn(f"no match found for {Fore.BLUE}{func.name}{Fore.RESET} ({func.addr | 0x71_00000000:#018x})")
|
||||
|
||||
# Output the modified function CSV.
|
||||
writer = csv.writer(sys.stdout, lineterminator="\n")
|
||||
for func in utils.get_functions():
|
||||
if func.status == utils.FunctionStatus.NotDecompiled and func.addr in new_matches:
|
||||
func.raw_row[3] = new_matches[func.addr]
|
||||
writer.writerow(func.raw_row)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
92
tools/identify_matching_functions_by_call.py
Executable file
92
tools/identify_matching_functions_by_call.py
Executable file
@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Dict, List
|
||||
import argparse
|
||||
|
||||
import cxxfilt
|
||||
from colorama import Fore
|
||||
|
||||
from util import utils, checker, elf
|
||||
|
||||
|
||||
class Checker(checker.FunctionChecker):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.checking = ""
|
||||
self.invalid_call_descriptions: List[str] = []
|
||||
self.addr_to_symbol = elf.build_addr_to_symbol_table(elf.my_symtab)
|
||||
self._possible_calls: Dict[int, int] = dict()
|
||||
|
||||
def reset(self) -> None:
|
||||
self._possible_calls.clear()
|
||||
|
||||
def get_possible_calls(self) -> Dict[int, int]:
|
||||
return self._possible_calls
|
||||
|
||||
def on_unknown_fn_call(self, orig_addr: int, decomp_addr: int):
|
||||
existing_addr = self._possible_calls.get(orig_addr)
|
||||
if existing_addr is not None and existing_addr != decomp_addr:
|
||||
self.invalid_call_descriptions.append(
|
||||
f"{orig_addr | 0x7100000000:#x} was mapped to {self.addr_to_symbol[existing_addr]} "
|
||||
f"({existing_addr:#x}) "
|
||||
f"but now maps to {self.addr_to_symbol[decomp_addr]} ({decomp_addr:#x})"
|
||||
f" (while checking {self.checking})")
|
||||
return
|
||||
self._possible_calls[orig_addr] = decomp_addr
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser("Identifies matching functions by looking at function calls in matching functions")
|
||||
parser.add_argument("-f", "--fn", help="Functions to analyze", nargs="*")
|
||||
args = parser.parse_args()
|
||||
|
||||
functions_to_analyze = set(args.fn) if args.fn else set()
|
||||
|
||||
functions_by_addr: Dict[int, utils.FunctionInfo] = {fn.addr: fn for fn in utils.get_functions()}
|
||||
fn_checker = Checker()
|
||||
for fn in functions_by_addr.values():
|
||||
if functions_to_analyze and fn.decomp_name not in functions_to_analyze:
|
||||
continue
|
||||
|
||||
if fn.status != utils.FunctionStatus.Matching:
|
||||
continue
|
||||
|
||||
base_fn = elf.get_fn_from_base_elf(fn.addr, fn.size)
|
||||
try:
|
||||
my_fn = elf.get_fn_from_my_elf(fn.decomp_name)
|
||||
except KeyError:
|
||||
utils.warn(f"could not find function {fn.decomp_name}")
|
||||
continue
|
||||
|
||||
fn_checker.checking = fn.decomp_name
|
||||
fn_checker.check(base_fn, my_fn)
|
||||
|
||||
if fn_checker.invalid_call_descriptions:
|
||||
for x in fn_checker.invalid_call_descriptions:
|
||||
utils.print_note(x)
|
||||
utils.fail("invalid calls detected")
|
||||
|
||||
new_matches: Dict[int, str] = dict()
|
||||
calls = fn_checker.get_possible_calls().copy()
|
||||
for base_target, my_target in calls.items():
|
||||
target_info = functions_by_addr.get(base_target)
|
||||
if target_info is None:
|
||||
continue
|
||||
if target_info.status != utils.FunctionStatus.NotDecompiled:
|
||||
continue
|
||||
|
||||
base_fn = elf.get_fn_from_base_elf(target_info.addr, target_info.size)
|
||||
try:
|
||||
name = fn_checker.addr_to_symbol[my_target]
|
||||
my_fn = elf.get_fn_from_my_elf(name)
|
||||
except KeyError:
|
||||
continue
|
||||
|
||||
if fn_checker.check(base_fn, my_fn):
|
||||
new_matches[base_target] = name
|
||||
utils.print_note(f"new match: {Fore.BLUE}{cxxfilt.demangle(name)}{Fore.RESET}")
|
||||
|
||||
utils.add_decompiled_functions(new_matches)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
84
tools/identify_matching_rtti_functions.py
Executable file
84
tools/identify_matching_rtti_functions.py
Executable file
@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
import struct
|
||||
from typing import Dict, Set
|
||||
|
||||
import capstone as cs
|
||||
import cxxfilt
|
||||
from colorama import Fore
|
||||
|
||||
from util import utils, elf
|
||||
|
||||
|
||||
def main() -> None:
|
||||
new_matches: Dict[int, str] = dict()
|
||||
functions_by_addr: Dict[int, utils.FunctionInfo] = {fn.addr: fn for fn in utils.get_functions()}
|
||||
|
||||
md = cs.Cs(cs.CS_ARCH_ARM64, cs.CS_MODE_ARM)
|
||||
md.detail = True
|
||||
decomp_addr_to_symbol = elf.build_addr_to_symbol_table(elf.my_symtab)
|
||||
decomp_glob_data_table = elf.build_glob_data_table(elf.my_elf)
|
||||
|
||||
processed: Set[int] = set()
|
||||
for fn in functions_by_addr.values():
|
||||
if fn.status != utils.FunctionStatus.Matching:
|
||||
continue
|
||||
|
||||
if fn.size != 0x5C or (not fn.decomp_name.endswith("8getRuntimeTypeInfoEv") and not fn.name.endswith("rtti2")):
|
||||
continue
|
||||
|
||||
base_fn = elf.get_fn_from_base_elf(fn.addr, fn.size)
|
||||
try:
|
||||
my_fn = elf.get_fn_from_my_elf(fn.decomp_name)
|
||||
except KeyError:
|
||||
utils.warn(f"could not find function {fn.decomp_name}")
|
||||
continue
|
||||
|
||||
assert len(base_fn.data) == len(my_fn.data)
|
||||
|
||||
vtable_ptr1 = 0
|
||||
vtable_ptr2 = 0
|
||||
for j, (i1, i2) in enumerate(zip(md.disasm(base_fn.data, base_fn.addr), md.disasm(my_fn.data, my_fn.addr))):
|
||||
assert i1.mnemonic == i2.mnemonic
|
||||
if j == 10:
|
||||
assert i1.mnemonic == "adrp"
|
||||
assert i1.operands[0].reg == i2.operands[0].reg
|
||||
vtable_ptr1 = i1.operands[1].imm
|
||||
vtable_ptr2 = i2.operands[1].imm
|
||||
elif j == 11:
|
||||
assert i1.mnemonic == "ldr"
|
||||
assert i1.operands[0].reg == i2.operands[0].reg
|
||||
assert i1.operands[1].value.mem.base == i2.operands[1].value.mem.base
|
||||
vtable_ptr1 += i1.operands[1].value.mem.disp
|
||||
vtable_ptr2 += i2.operands[1].value.mem.disp
|
||||
break
|
||||
|
||||
assert vtable_ptr1 != 0 and vtable_ptr2 != 0
|
||||
if vtable_ptr1 in processed:
|
||||
continue
|
||||
processed.add(vtable_ptr1)
|
||||
ptr1, = struct.unpack("<Q", elf.read_from_elf(elf.base_elf, vtable_ptr1, 8))
|
||||
ptr2 = decomp_glob_data_table[vtable_ptr2]
|
||||
|
||||
vtable1 = elf.get_vtable_fns_from_base_elf(ptr1 + 0x10, num_entries=1)
|
||||
vtable2 = elf.unpack_vtable_fns(elf.read_from_elf(elf.my_elf, addr=ptr2 + 0x10, size=8), num_entries=1)
|
||||
|
||||
if functions_by_addr[vtable1[0]].status == utils.FunctionStatus.Matching:
|
||||
continue
|
||||
|
||||
decomp_derive_fn_addr = vtable2[0]
|
||||
if decomp_derive_fn_addr == 0:
|
||||
decomp_derive_fn_addr = decomp_glob_data_table.get(ptr2 + 0x10, 0)
|
||||
if decomp_derive_fn_addr == 0:
|
||||
raise RuntimeError(f"Derive virtual function pointer is null "
|
||||
f"(fn: {fn.decomp_name}, decomp vtable at {ptr2:#x})")
|
||||
|
||||
name = decomp_addr_to_symbol[decomp_derive_fn_addr]
|
||||
new_matches[vtable1[0]] = name
|
||||
utils.print_note(f"new match: {Fore.BLUE}{cxxfilt.demangle(name)}{Fore.RESET} (from {fn.decomp_name})")
|
||||
|
||||
# overwrite the original names because they are likely to be incorrect
|
||||
utils.add_decompiled_functions(new_matches, new_orig_names=new_matches)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
58
tools/print_decomp_symbols.py
Executable file
58
tools/print_decomp_symbols.py
Executable file
@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
from colorama import Fore, Style
|
||||
import diff_settings
|
||||
import subprocess
|
||||
from util import utils
|
||||
|
||||
parser = argparse.ArgumentParser(description="Prints build/odyssey.elf symbols")
|
||||
parser.add_argument("--print-undefined", "-u",
|
||||
help="Print symbols that are undefined", action="store_true")
|
||||
parser.add_argument("--print-c2-d2", "-c",
|
||||
help="Print C2/D2 (base object constructor/destructor) symbols", action="store_true")
|
||||
parser.add_argument("--hide-unknown", "-H",
|
||||
help="Hide symbols that are not present in the original game", action="store_true")
|
||||
parser.add_argument("--all", "-a", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
listed_decomp_symbols = {info.decomp_name for info in utils.get_functions()}
|
||||
original_symbols = {info.name for info in utils.get_functions()}
|
||||
|
||||
config: dict = dict()
|
||||
diff_settings.apply(config, {})
|
||||
myimg: str = config["myimg"]
|
||||
|
||||
entries = [x.strip().split() for x in subprocess.check_output(["nm", "-n", myimg], universal_newlines=True).split("\n")]
|
||||
|
||||
for entry in entries:
|
||||
if len(entry) == 3:
|
||||
addr = int(entry[0], 16)
|
||||
symbol_type: str = entry[1]
|
||||
name = entry[2]
|
||||
|
||||
if (symbol_type == "t" or symbol_type == "T" or symbol_type == "W") and (
|
||||
args.all or name not in listed_decomp_symbols):
|
||||
c1_name = name.replace("C2", "C1")
|
||||
is_c2_ctor = "C2" in name and c1_name in listed_decomp_symbols and utils.are_demangled_names_equal(
|
||||
c1_name, name)
|
||||
|
||||
d1_name = name.replace("D2", "D1")
|
||||
is_d2_dtor = "D2" in name and d1_name in listed_decomp_symbols and utils.are_demangled_names_equal(
|
||||
d1_name, name)
|
||||
|
||||
if args.print_c2_d2 or not (is_c2_ctor or is_d2_dtor):
|
||||
color = Fore.YELLOW
|
||||
if name in original_symbols:
|
||||
color = Fore.RED
|
||||
elif args.hide_unknown:
|
||||
continue
|
||||
if is_c2_ctor or is_d2_dtor:
|
||||
color += Style.DIM
|
||||
print(f"{color}UNLISTED {Fore.RESET} {utils.format_symbol_name(name)}")
|
||||
|
||||
elif len(entry) == 2:
|
||||
symbol_type = entry[0]
|
||||
name = entry[1]
|
||||
|
||||
if symbol_type.upper() == "U" and args.print_undefined:
|
||||
print(f"{Fore.CYAN}UNDEFINED{Style.RESET_ALL} {utils.format_symbol_name(name)}")
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user