mirror of
https://github.com/open-goal/jak-project.git
synced 2026-11-07 17:28:57 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e307c8a9e | ||
|
|
3a67f40098 | ||
|
|
cbfa65c78a | ||
|
|
681c419f17 | ||
|
|
a4e108cca6 | ||
|
|
f1ee25c640 | ||
|
|
af6de539b5 | ||
|
|
c72a086e49 | ||
|
|
a66d832b2f | ||
|
|
d29ab77892 | ||
|
|
e975eab15a | ||
|
|
441952186c | ||
|
|
d819d6da05 | ||
|
|
ce978638fe | ||
|
|
9d0009715e | ||
|
|
3856ae505a | ||
|
|
92c4390f0a | ||
|
|
a7c9151c6c | ||
|
|
82a23c747e | ||
|
|
f0b46ff2e5 | ||
|
|
9d80ada016 | ||
|
|
e81431bd21 | ||
|
|
57772c59a0 | ||
|
|
edae60d58d | ||
|
|
365fae4913 | ||
|
|
3d04ac958c | ||
|
|
849ba391d4 | ||
|
|
c8fbe26c7d | ||
|
|
fbab87b0fe | ||
|
|
1c170b741c | ||
|
|
b8f1ee5289 | ||
|
|
bdded9ad8c | ||
|
|
08a23793c8 | ||
|
|
291c89a851 | ||
|
|
b4113dda67 | ||
|
|
a485c236d6 | ||
|
|
73ff53f01d | ||
|
|
495a8bc26f | ||
|
|
90c11bde8f | ||
|
|
86979e3d06 | ||
|
|
29849a4fbb | ||
|
|
b0b9fc4311 | ||
|
|
c162c66118 | ||
|
|
37762c5fb7 | ||
|
|
a18d9dd4d0 | ||
|
|
a9bdb0136e | ||
|
|
eb703ee96e | ||
|
|
39786482a1 | ||
|
|
f586cb9af2 | ||
|
|
ea1271cfd0 | ||
|
|
cefb371681 | ||
|
|
70ea2a1f67 | ||
|
|
c64eea6337 | ||
|
|
f1de2c9bc5 | ||
|
|
f6688659f2 | ||
|
|
12ce274226 | ||
|
|
bd2db7b15a | ||
|
|
c2cccc48cd | ||
|
|
c5effb2395 | ||
|
|
5f3671b8a3 | ||
|
|
645e649a9c | ||
|
|
26bfac8555 | ||
|
|
dd765b41cb | ||
|
|
0db7be55e6 | ||
|
|
62ef9fe49d | ||
|
|
271007e552 | ||
|
|
a61f24a168 | ||
|
|
c12a5d777c | ||
|
|
456d1ba536 | ||
|
|
4aafab2fc9 | ||
|
|
ebbbedabc5 | ||
|
|
d1ece445d4 | ||
|
|
e0b1d8c21e | ||
|
|
6b3844bf99 | ||
|
|
24490c042e | ||
|
|
4dd2bab06e | ||
|
|
5b04be2fa0 | ||
|
|
949508d0ed | ||
|
|
f479cef939 | ||
|
|
807ca7465f | ||
|
|
cf79ca04e9 | ||
|
|
6569636abf | ||
|
|
f9e0aa82bc | ||
|
|
39f3549640 | ||
|
|
3ff3760621 | ||
|
|
5705359df9 | ||
|
|
cbf75a96f7 | ||
|
|
8344ac6963 | ||
|
|
a527afdc5a | ||
|
|
0d4e3928eb | ||
|
|
e4c57d6ac9 | ||
|
|
a021c392ec | ||
|
|
fee0a435fc | ||
|
|
e2e5289788 | ||
|
|
1a058b418a | ||
|
|
86d770aeeb | ||
|
|
889fdcd79c | ||
|
|
667553850d | ||
|
|
d9d4cc5405 | ||
|
|
728cb4b6c9 | ||
|
|
9d359ed84a | ||
|
|
58a5440c8a | ||
|
|
6da5225afc | ||
|
|
bcab625864 | ||
|
|
8e5830321c | ||
|
|
e601a3dcb3 | ||
|
|
20b76e318d | ||
|
|
ccd2c9eaf1 | ||
|
|
d596afcf13 | ||
|
|
dd4f255260 | ||
|
|
36f1592b90 | ||
|
|
5299bc441f | ||
|
|
1394c5c00d | ||
|
|
0124a0b9a1 | ||
|
|
ae0f139667 | ||
|
|
cc8801a27b | ||
|
|
376194a3e7 | ||
|
|
23aeda1664 |
No files matched your search
@@ -32,4 +32,4 @@ cp -r $SOURCE/decompiler/config $DEST/data/decompiler/
|
||||
cp -r $SOURCE/goal_src $DEST/data
|
||||
cp -r $SOURCE/game/assets $DEST/data/game/
|
||||
cp -r $SOURCE/game/graphics/opengl_renderer/shaders $DEST/data/game/graphics/opengl_renderer
|
||||
cp -r $SOURCE/custom_levels $DEST/data
|
||||
cp -r $SOURCE/custom_assets $DEST/data
|
||||
@@ -24,4 +24,4 @@ cp -r $SOURCE/decompiler/config $DEST/data/decompiler/
|
||||
cp -r $SOURCE/goal_src $DEST/data
|
||||
cp -r $SOURCE/game/assets $DEST/data/game/
|
||||
cp -r $SOURCE/game/graphics/opengl_renderer/shaders $DEST/data/game/graphics/opengl_renderer
|
||||
cp -r $SOURCE/custom_levels $DEST/data
|
||||
cp -r $SOURCE/custom_assets $DEST/data
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
libxi-dev zip ninja-build libgl1-mesa-dev libssl-dev
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]2
|
||||
uses: hendrikmuhs/[email protected]3
|
||||
with:
|
||||
variant: sccache
|
||||
key: linux-ubuntu-20.04-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
sudo update-alternatives --set g++ /usr/bin/g++-10
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]2
|
||||
uses: hendrikmuhs/[email protected]3
|
||||
with:
|
||||
variant: sccache
|
||||
key: linux-ubuntu-20.04-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
run: arch -arm64 brew install cmake ninja
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]2
|
||||
uses: hendrikmuhs/[email protected]3
|
||||
with:
|
||||
variant: sccache
|
||||
key: macos-12-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
run: brew install cmake nasm ninja
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]2
|
||||
uses: hendrikmuhs/[email protected]3
|
||||
with:
|
||||
variant: sccache
|
||||
key: macos-12-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]2
|
||||
uses: hendrikmuhs/[email protected]3
|
||||
with:
|
||||
variant: sccache
|
||||
key: windows-2022-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Setup sccache
|
||||
uses: hendrikmuhs/[email protected]2
|
||||
uses: hendrikmuhs/[email protected]3
|
||||
with:
|
||||
variant: sccache
|
||||
key: windows-2022-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
|
||||
|
||||
+9
-1
@@ -54,7 +54,14 @@ imgui.ini
|
||||
node_modules/
|
||||
|
||||
# texture replacements
|
||||
texture_replacements/*
|
||||
custom_assets/jak1/texture_replacements/*
|
||||
custom_assets/jak2/texture_replacements/*
|
||||
custom_assets/jak3/texture_replacements/*
|
||||
|
||||
# merc replacements
|
||||
custom_assets/jak1/merc_replacements/*
|
||||
custom_assets/jak2/merc_replacements/*
|
||||
custom_assets/jak3/merc_replacements/*
|
||||
|
||||
# generated cmake files
|
||||
svnrev.h
|
||||
@@ -76,3 +83,4 @@ __pycache__/
|
||||
/TODO.md
|
||||
unifont-15.0.03.ttf
|
||||
*.diff
|
||||
goalc-report.html
|
||||
+153
-33
@@ -7,42 +7,58 @@
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
|
||||
"name": "Tests - Unit-Tests - Summary",
|
||||
"args": ["--gtest_brief=1"]
|
||||
"args": [
|
||||
"--gtest_brief=1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
|
||||
"name": "Tests - Unit-Tests - Verbose",
|
||||
"args": ["--gtest_brief=0"]
|
||||
"args": [
|
||||
"--gtest_brief=0"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
|
||||
"name": "Tests - Draft Tests - Verbose",
|
||||
"args": ["--gtest_brief=0", "--gtest_filter=\"*Draft*\""]
|
||||
"args": [
|
||||
"--gtest_brief=0",
|
||||
"--gtest_filter=\"*Draft*\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
|
||||
"name": "Tests - TypeConsistency - Verbose",
|
||||
"args": ["--gtest_brief=0", "--gtest_filter=\"*TypeConsistency*\""]
|
||||
"args": [
|
||||
"--gtest_brief=0",
|
||||
"--gtest_filter=\"*TypeConsistency*\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
|
||||
"name": "Tests - TypeConsistency - Jak 2 - Verbose",
|
||||
"args": ["--gtest_brief=0", "--gtest_filter=\"*Jak2TypeConsistency*\""]
|
||||
"args": [
|
||||
"--gtest_brief=0",
|
||||
"--gtest_filter=\"*Jak2TypeConsistency*\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
|
||||
"name": "Tests - WithGameTests - Verbose",
|
||||
"args": ["--gtest_brief=0", "--gtest_filter=\"*WithGameTests*\""]
|
||||
"args": [
|
||||
"--gtest_brief=0",
|
||||
"--gtest_filter=\"*WithGameTests*\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
@@ -113,49 +129,109 @@
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "gk.exe (bin\\gk.exe)",
|
||||
"name": "Game - Jak 1 - Runtime",
|
||||
"args": ["-v", "--game", "jak1", "--", "-fakeiso", "-debug"]
|
||||
"args": [
|
||||
"-v",
|
||||
"--game",
|
||||
"jak1",
|
||||
"--",
|
||||
"-fakeiso",
|
||||
"-debug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "gk.exe (bin\\gk.exe)",
|
||||
"name": "Game - Jak 1 - Runtime (boot)",
|
||||
"args": ["-v", "--game", "jak1", "--", "-boot", "-fakeiso", "-debug"]
|
||||
"args": [
|
||||
"-v",
|
||||
"--game",
|
||||
"jak1",
|
||||
"--",
|
||||
"-boot",
|
||||
"-fakeiso",
|
||||
"-debug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "gk.exe (bin\\gk.exe)",
|
||||
"name": "Game - Jak 2 - Runtime (no boot)",
|
||||
"args": ["-v", "--game", "jak2", "--", "-fakeiso", "-debug"]
|
||||
"args": [
|
||||
"-v",
|
||||
"--game",
|
||||
"jak2",
|
||||
"--",
|
||||
"-fakeiso",
|
||||
"-debug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "gk.exe (bin\\gk.exe)",
|
||||
"name": "Game - Jak 2 - Runtime (boot)",
|
||||
"args": ["-v", "--game", "jak2", "--", "-boot", "-fakeiso", "-debug"]
|
||||
"args": [
|
||||
"-v",
|
||||
"--game",
|
||||
"jak2",
|
||||
"--",
|
||||
"-boot",
|
||||
"-fakeiso",
|
||||
"-debug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "gk.exe (bin\\gk.exe)",
|
||||
"name": "Game - Jak 2 - Runtime (release)",
|
||||
"args": ["-v", "--game", "jak2", "--", "-boot", "-fakeiso"]
|
||||
"args": [
|
||||
"-v",
|
||||
"--game",
|
||||
"jak2",
|
||||
"--",
|
||||
"-boot",
|
||||
"-fakeiso"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "gk.exe (bin\\gk.exe)",
|
||||
"name": "Game - Jak 3 - Runtime (boot)",
|
||||
"args": [
|
||||
"-v",
|
||||
"--game",
|
||||
"jak3",
|
||||
"--",
|
||||
"-boot",
|
||||
"-fakeiso",
|
||||
"-debug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "goalc.exe (bin\\goalc.exe)",
|
||||
"name": "REPL - Jak 1",
|
||||
"args": ["--user-auto", "--game", "jak1"]
|
||||
"args": [
|
||||
"--user-auto",
|
||||
"--game",
|
||||
"jak1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "goalc.exe (bin\\goalc.exe)",
|
||||
"name": "REPL - Jak 2",
|
||||
"args": ["--user-auto", "--game", "jak2"]
|
||||
"args": [
|
||||
"--user-auto",
|
||||
"--game",
|
||||
"jak2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
@@ -236,19 +312,45 @@
|
||||
"ntsc_v1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "decompiler.exe (bin\\decompiler.exe)",
|
||||
"name": "Decompiler - Jak 3 - Extract",
|
||||
"args": [
|
||||
"${workspaceRoot}/decompiler/config/jak3/jak3_config.jsonc",
|
||||
"${workspaceRoot}/iso_data",
|
||||
"${workspaceRoot}/decompiler_out",
|
||||
"--version",
|
||||
"ntsc_v1",
|
||||
"--config-override \"{\\\"decompile_code\\\": false, \\\"levels_extract\\\": true, \\\"allowed_objects\\\": []}\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "memory_dump_tool.exe (bin\\memory_dump_tool.exe)",
|
||||
"name": "Tools - EE Memory Analyze - Jak 1",
|
||||
"args": ["\"${workspaceRoot}/eeMemory.bin\"", "--output-path", "\"${workspaceRoot}\"", "--game", "jak1"]
|
||||
"args": [
|
||||
"\"${workspaceRoot}/eeMemory.bin\"",
|
||||
"--output-path",
|
||||
"\"${workspaceRoot}\"",
|
||||
"--game",
|
||||
"jak1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "memory_dump_tool.exe (bin\\memory_dump_tool.exe)",
|
||||
"name": "Tools - EE Memory Analyze - Jak 2",
|
||||
"args": ["\"${workspaceRoot}/eeMemory.bin\"", "--output-path", "\"${workspaceRoot}\"", "--game", "jak2"]
|
||||
"args": [
|
||||
"\"${workspaceRoot}/eeMemory.bin\"",
|
||||
"--output-path",
|
||||
"\"${workspaceRoot}\"",
|
||||
"--game",
|
||||
"jak2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
@@ -265,35 +367,53 @@
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "extractor.exe (bin\\extractor.exe)",
|
||||
"name": "Tools - Extractor - Full",
|
||||
"args": ["\"E:\\ISOs\\Jak\\Jak 1.iso\""]
|
||||
"args": [
|
||||
"\"E:\\ISOs\\Jak\\Jak 1.iso\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"type" : "default",
|
||||
"project" : "CMakeLists.txt",
|
||||
"projectTarget" : "lsp.exe (bin\\lsp.exe)",
|
||||
"name" : "Tools - LSP",
|
||||
"args" : []
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "lsp.exe (bin\\lsp.exe)",
|
||||
"name": "Tools - LSP",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"type" : "default",
|
||||
"project" : "CMakeLists.txt",
|
||||
"projectTarget" : "type_searcher.exe (bin\\type_searcher.exe)",
|
||||
"name" : "Tools - Type Searcher",
|
||||
"args" : ["--game", "jak2", "--output-path", "./search-results.json", "--size", 255, "--fields", "[{\\\"type\\\":\\\"quaternion\\\",\\\"offset\\\":48}]"]
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "type_searcher.exe (bin\\type_searcher.exe)",
|
||||
"name": "Tools - Type Searcher",
|
||||
"args": [
|
||||
"--game",
|
||||
"jak2",
|
||||
"--output-path",
|
||||
"./search-results.json",
|
||||
"--size",
|
||||
255,
|
||||
"--fields",
|
||||
"[{\\\"type\\\":\\\"quaternion\\\",\\\"offset\\\":48}]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type" : "default",
|
||||
"project" : "CMakeLists.txt",
|
||||
"projectTarget" : "formatter.exe (bin\\formatter.exe)",
|
||||
"name" : "Tools - Formatter - Inplace",
|
||||
"args" : ["--write", "--file", "C:\\Users\\xtvas\\Repos\\opengoal\\jak-project\\decompiler_out\\jak3\\mood-h_disasm.gc"]
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "formatter.exe (bin\\formatter.exe)",
|
||||
"name": "Tools - Formatter - Inplace",
|
||||
"args": [
|
||||
"--write",
|
||||
"--file",
|
||||
"C:\\Users\\xtvas\\Repositories\\opengoal\\jak-project\\goal_src\\jak1\\engine\\camera\\cam-states.gc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
|
||||
"name": "Tests - Formatter",
|
||||
"args": ["--gtest_brief=0", "--gtest_filter=\"*FormatterTests*\""]
|
||||
"args": [
|
||||
"--gtest_brief=0",
|
||||
"--gtest_filter=\"*FormatterTests*\""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Vendored
+2
-2
@@ -8,10 +8,10 @@
|
||||
"name": "run python script",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/scripts/gsrc/copy-common-naming.py",
|
||||
"program": "${workspaceFolder}/scripts/gsrc/compare-compilation-outputs.py",
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"args": ["--update-names-from-refs", "--decompiler", "./out/build/Release/bin/decompiler"]
|
||||
"args": []
|
||||
},
|
||||
]
|
||||
}
|
||||
+6
-1
@@ -101,7 +101,6 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
message(STATUS "AppleClang detected - Setting Defaults")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} \
|
||||
-march=native \
|
||||
-Wall \
|
||||
-Winit-self \
|
||||
-ggdb \
|
||||
@@ -117,6 +116,12 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
-Wsign-promo \
|
||||
-fdiagnostics-color=always"
|
||||
)
|
||||
|
||||
# pin to AVX for macOS, hopefully all macOS runners have atleast this architecture
|
||||
# technically speaking, SSE4 is the cutoff for Apple Silicon so...only a matter of time!
|
||||
if(NOT CMAKE_CXX_COMPILER_TARGET STREQUAL "arm64-apple-darwin")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx")
|
||||
endif()
|
||||
|
||||
# additional c++ flags for release mode for our projects
|
||||
if(CMAKE_BUILD_TYPE MATCHES "Release")
|
||||
|
||||
@@ -51,7 +51,7 @@ add_library(common
|
||||
repl/config.cpp
|
||||
repl/nrepl/ReplClient.cpp
|
||||
repl/nrepl/ReplServer.cpp
|
||||
repl/util.cpp
|
||||
repl/repl_wrapper.cpp
|
||||
serialization/subtitles/subtitles_v1.cpp
|
||||
serialization/subtitles/subtitles_v2.cpp
|
||||
serialization/subtitles/subtitles.cpp
|
||||
@@ -87,9 +87,11 @@ add_library(common
|
||||
util/term_util.cpp
|
||||
util/Timer.cpp
|
||||
util/unicode_util.cpp
|
||||
versions/versions.cpp)
|
||||
util/gltf_util.cpp
|
||||
versions/versions.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(common fmt lzokay replxx libzstd_static tree-sitter sqlite3 libtinyfiledialogs)
|
||||
target_link_libraries(common fmt lzokay replxx libzstd_static tree-sitter sqlite3 libtinyfiledialogs tiny_gltf)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(common wsock32 ws2_32 windowsapp)
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "common/cross_sockets/XSocket.h"
|
||||
#include "common/log/log.h"
|
||||
|
||||
#include "fmt/core.h"
|
||||
|
||||
// clang-format off
|
||||
#ifdef _WIN32
|
||||
#define NOMINMAX
|
||||
@@ -13,9 +15,7 @@
|
||||
#include <WinSock2.h>
|
||||
#include <WS2tcpip.h>
|
||||
#endif
|
||||
#include "common/repl/nrepl/ReplServer.h"
|
||||
|
||||
#include "fmt/core.h"
|
||||
// clang-format on
|
||||
|
||||
XSocketClient::XSocketClient(int _tcp_port) {
|
||||
|
||||
@@ -35,7 +35,7 @@ void XSocketServer::shutdown_server() {
|
||||
close_server_socket();
|
||||
}
|
||||
|
||||
bool XSocketServer::init_server() {
|
||||
bool XSocketServer::init_server(bool failure_may_occur) {
|
||||
listening_socket = open_socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listening_socket < 0) {
|
||||
listening_socket = -1;
|
||||
@@ -76,19 +76,27 @@ bool XSocketServer::init_server() {
|
||||
addr.sin_port = htons(tcp_port);
|
||||
|
||||
if (bind(listening_socket, (sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
lg::error("[XSocketServer:{}] failed to bind", tcp_port);
|
||||
if (failure_may_occur) {
|
||||
lg::debug("[XSocketServer:{}] failed to bind", tcp_port);
|
||||
} else {
|
||||
lg::error("[XSocketServer:{}] failed to bind", tcp_port);
|
||||
}
|
||||
close_server_socket();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (listen(listening_socket, 0) < 0) {
|
||||
lg::error("[XSocketServer:{}] failed to listen", tcp_port);
|
||||
if (failure_may_occur) {
|
||||
lg::debug("[XSocketServer:{}] failed to listen", tcp_port);
|
||||
} else {
|
||||
lg::error("[XSocketServer:{}] failed to listen", tcp_port);
|
||||
}
|
||||
close_server_socket();
|
||||
return false;
|
||||
}
|
||||
|
||||
server_initialized = true;
|
||||
lg::info("[XSocketServer:{}] initialized", tcp_port);
|
||||
lg::debug("[XSocketServer:{}] initialized", tcp_port);
|
||||
post_init();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class XSocketServer {
|
||||
XSocketServer(const XSocketServer&) = delete;
|
||||
XSocketServer& operator=(const XSocketServer&) = delete;
|
||||
|
||||
bool init_server();
|
||||
bool init_server(bool failure_may_occur = false);
|
||||
void shutdown_server();
|
||||
void close_server_socket();
|
||||
|
||||
|
||||
@@ -9,10 +9,16 @@
|
||||
#include "third-party/sse2neon/sse2neon.h"
|
||||
#endif
|
||||
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/Assert.h"
|
||||
|
||||
namespace tfrag3 {
|
||||
|
||||
void PackedTimeOfDay::serialize(Serializer& ser) {
|
||||
ser.from_pod_vector(&data);
|
||||
ser.from_ptr(&color_count);
|
||||
}
|
||||
|
||||
void PackedTieVertices::serialize(Serializer& ser) {
|
||||
ser.from_pod_vector(&color_indices);
|
||||
ser.from_pod_vector(&matrices);
|
||||
@@ -71,10 +77,9 @@ void TfragTree::serialize(Serializer& ser) {
|
||||
draw.serialize(ser);
|
||||
}
|
||||
|
||||
// ser.from_pod_vector(&vertices);
|
||||
ser.from_pod_vector(&packed_vertices.vertices);
|
||||
ser.from_pod_vector(&packed_vertices.cluster_origins);
|
||||
ser.from_pod_vector(&colors);
|
||||
colors.serialize(ser);
|
||||
bvh.serialize(ser);
|
||||
ser.from_ptr(&use_strips);
|
||||
}
|
||||
@@ -398,7 +403,7 @@ void TieTree::serialize(Serializer& ser) {
|
||||
}
|
||||
|
||||
packed_vertices.serialize(ser);
|
||||
ser.from_pod_vector(&colors);
|
||||
colors.serialize(ser);
|
||||
bvh.serialize(ser);
|
||||
|
||||
ser.from_ptr(&has_per_proto_visibility_toggle);
|
||||
@@ -406,7 +411,7 @@ void TieTree::serialize(Serializer& ser) {
|
||||
}
|
||||
|
||||
void ShrubTree::serialize(Serializer& ser) {
|
||||
ser.from_pod_vector(&time_of_day_colors);
|
||||
time_of_day_colors.serialize(ser);
|
||||
ser.from_pod_vector(&indices);
|
||||
packed_vertices.serialize(ser);
|
||||
if (ser.is_saving()) {
|
||||
@@ -422,6 +427,30 @@ void ShrubTree::serialize(Serializer& ser) {
|
||||
ser.from_string_vector(&proto_names);
|
||||
}
|
||||
|
||||
void HfragmentBucket::serialize(Serializer& ser) {
|
||||
ser.from_pod_vector(&corners);
|
||||
ser.from_ptr(&montage_table);
|
||||
}
|
||||
|
||||
void Hfragment::serialize(Serializer& ser) {
|
||||
ser.from_pod_vector(&vertices);
|
||||
ser.from_pod_vector(&indices);
|
||||
ser.from_pod_vector(&corners);
|
||||
|
||||
if (ser.is_saving()) {
|
||||
ser.save<size_t>(buckets.size());
|
||||
} else {
|
||||
buckets.resize(ser.load<size_t>());
|
||||
}
|
||||
for (auto& x : buckets) {
|
||||
x.serialize(ser);
|
||||
}
|
||||
time_of_day_colors.serialize(ser);
|
||||
ser.from_ptr(&wang_tree_tex_id);
|
||||
ser.from_ptr(&draw_mode);
|
||||
ser.from_ptr(&occlusion_offset);
|
||||
}
|
||||
|
||||
void BVH::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&first_leaf_node);
|
||||
ser.from_ptr(&last_leaf_node);
|
||||
@@ -463,6 +492,7 @@ void MercDraw::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&first_index);
|
||||
ser.from_ptr(&index_count);
|
||||
ser.from_ptr(&num_triangles);
|
||||
ser.from_ptr(&no_strip);
|
||||
}
|
||||
|
||||
void Blerc::serialize(Serializer& ser) {
|
||||
@@ -604,6 +634,8 @@ void Level::serialize(Serializer& ser) {
|
||||
tree.serialize(ser);
|
||||
}
|
||||
|
||||
hfrag.serialize(ser);
|
||||
|
||||
collision.serialize(ser);
|
||||
merc_data.serialize(ser);
|
||||
|
||||
@@ -654,8 +686,7 @@ void PackedShrubVertices::memory_usage(MemoryUsageTracker* tracker) const {
|
||||
}
|
||||
|
||||
void ShrubTree::memory_usage(MemoryUsageTracker* tracker) const {
|
||||
tracker->add(MemoryUsageCategory::SHRUB_TIME_OF_DAY,
|
||||
sizeof(TimeOfDayColor) * time_of_day_colors.size());
|
||||
tracker->add(MemoryUsageCategory::SHRUB_TIME_OF_DAY, sizeof(u8) * time_of_day_colors.data.size());
|
||||
packed_vertices.memory_usage(tracker);
|
||||
tracker->add(MemoryUsageCategory::SHRUB_DRAW, sizeof(ShrubDraw) * static_draws.size());
|
||||
tracker->add(MemoryUsageCategory::SHRUB_IND, sizeof(u32) * indices.size());
|
||||
@@ -683,7 +714,7 @@ void TieTree::memory_usage(MemoryUsageTracker* tracker) const {
|
||||
draw.vis_groups.size() * sizeof(StripDraw::VisGroup));
|
||||
}
|
||||
packed_vertices.memory_usage(tracker);
|
||||
tracker->add(MemoryUsageCategory::TIE_TIME_OF_DAY, sizeof(TimeOfDayColor) * colors.size());
|
||||
tracker->add(MemoryUsageCategory::TIE_TIME_OF_DAY, sizeof(u8) * colors.data.size());
|
||||
|
||||
for (auto& draw : instanced_wind_draws) {
|
||||
draw.memory_usage(tracker);
|
||||
@@ -707,7 +738,7 @@ void TfragTree::memory_usage(MemoryUsageTracker* tracker) const {
|
||||
draw.vis_groups.size() * sizeof(StripDraw::VisGroup));
|
||||
}
|
||||
packed_vertices.memory_usage(tracker);
|
||||
tracker->add(MemoryUsageCategory::TFRAG_TIME_OF_DAY, sizeof(TimeOfDayColor) * colors.size());
|
||||
tracker->add(MemoryUsageCategory::TFRAG_TIME_OF_DAY, sizeof(u8) * colors.data.size());
|
||||
tracker->add(MemoryUsageCategory::TFRAG_BVH, sizeof(VisNode) * bvh.vis_nodes.size());
|
||||
}
|
||||
|
||||
@@ -720,6 +751,13 @@ void IndexTexture::memory_usage(MemoryUsageTracker* tracker) const {
|
||||
tracker->add(MemoryUsageCategory::SPECIAL_TEXTURE, 256 * 4); // clut
|
||||
}
|
||||
|
||||
void Hfragment::memory_usage(tfrag3::MemoryUsageTracker* tracker) const {
|
||||
tracker->add(MemoryUsageCategory::HFRAG_VERTS, vertices.size() * sizeof(HfragmentVertex));
|
||||
tracker->add(MemoryUsageCategory::HFRAG_INDEX, indices.size() * sizeof(u32));
|
||||
tracker->add(MemoryUsageCategory::HFRAG_TIME_OF_DAY, time_of_day_colors.data.size() * sizeof(u8));
|
||||
tracker->add(MemoryUsageCategory::HFRAG_CORNERS, corners.size() * sizeof(HfragmentCorner));
|
||||
}
|
||||
|
||||
void Level::memory_usage(MemoryUsageTracker* tracker) const {
|
||||
for (const auto& texture : textures) {
|
||||
texture.memory_usage(tracker);
|
||||
@@ -740,6 +778,7 @@ void Level::memory_usage(MemoryUsageTracker* tracker) const {
|
||||
for (const auto& tree : shrub_trees) {
|
||||
tree.memory_usage(tracker);
|
||||
}
|
||||
hfrag.memory_usage(tracker);
|
||||
collision.memory_usage(tracker);
|
||||
merc_data.memory_usage(tracker);
|
||||
}
|
||||
@@ -783,6 +822,11 @@ void print_memory_usage(const tfrag3::Level& lev, int uncompressed_data_size) {
|
||||
{"merc-mod-draw-1", mem_use.data[tfrag3::MemoryUsageCategory::MERC_MOD_DRAW_1]},
|
||||
{"merc-mod-draw-2", mem_use.data[tfrag3::MemoryUsageCategory::MERC_MOD_DRAW_2]},
|
||||
{"blerc", mem_use.data[tfrag3::MemoryUsageCategory::BLERC]},
|
||||
{"hfrag-verts", mem_use.data[tfrag3::MemoryUsageCategory::HFRAG_VERTS]},
|
||||
{"hfrag-index", mem_use.data[tfrag3::MemoryUsageCategory::HFRAG_INDEX]},
|
||||
{"hfrag-time-of-day", mem_use.data[tfrag3::MemoryUsageCategory::HFRAG_TIME_OF_DAY]},
|
||||
{"hfrag-corners", mem_use.data[tfrag3::MemoryUsageCategory::HFRAG_CORNERS]}
|
||||
|
||||
};
|
||||
for (auto& known : known_categories) {
|
||||
total_accounted += known.second;
|
||||
@@ -795,8 +839,8 @@ void print_memory_usage(const tfrag3::Level& lev, int uncompressed_data_size) {
|
||||
|
||||
for (const auto& x : known_categories) {
|
||||
if (x.second) {
|
||||
fmt::print("{:30s} : {:6d} kB {:3.1f}%\n", x.first, x.second / 1024,
|
||||
100.f * (float)x.second / uncompressed_data_size);
|
||||
lg::print("{:30s} : {:6d} kB {:3.1f}%\n", x.first, x.second / 1024,
|
||||
100.f * (float)x.second / uncompressed_data_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace tfrag3 {
|
||||
// - if changing any large things (vertices, vis, bvh, colors, textures) update get_memory_usage
|
||||
// - if adding a new category to the memory usage, update extract_level to print it.
|
||||
|
||||
constexpr int TFRAG3_VERSION = 39;
|
||||
constexpr int TFRAG3_VERSION = 41;
|
||||
|
||||
enum MemoryUsageCategory {
|
||||
TEXTURE,
|
||||
@@ -61,6 +61,11 @@ enum MemoryUsageCategory {
|
||||
MERC_MOD_TABLE,
|
||||
BLERC,
|
||||
|
||||
HFRAG_VERTS,
|
||||
HFRAG_INDEX,
|
||||
HFRAG_TIME_OF_DAY,
|
||||
HFRAG_CORNERS,
|
||||
|
||||
COLLISION,
|
||||
|
||||
NUM_CATEGORIES
|
||||
@@ -269,18 +274,23 @@ struct BVH {
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
// A time-of-day color. Each stores 8 colors. At a given "time of day", they are interpolated
|
||||
// to find a single color which goes into a color palette.
|
||||
struct TimeOfDayColor {
|
||||
math::Vector<u8, 4> rgba[8];
|
||||
// This is split into groups of 4 colors.
|
||||
// The data in these groups is stored first by palette, then color, then channel.
|
||||
struct PackedTimeOfDay {
|
||||
std::vector<u8> data;
|
||||
u32 color_count = 0;
|
||||
void serialize(Serializer& ser);
|
||||
|
||||
bool operator==(const TimeOfDayColor& other) const {
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
if (rgba[i] != other.rgba[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
u8 read(int color, int palette, int channel) const {
|
||||
const int color_quad = color / 4;
|
||||
const int color_in_quad = color % 4;
|
||||
return data[color_quad * 4 * 4 * 8 + palette * 4 * 4 + color_in_quad * 4 + channel];
|
||||
}
|
||||
|
||||
u8& read(int color, int palette, int channel) {
|
||||
const int color_quad = color / 4;
|
||||
const int color_in_quad = color % 4;
|
||||
return data[color_quad * 4 * 4 * 8 + palette * 4 * 4 + color_in_quad * 4 + channel];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -319,8 +329,8 @@ struct TfragTree {
|
||||
TFragmentTreeKind kind; // our tfrag kind
|
||||
std::vector<StripDraw> draws; // the actual topology and settings
|
||||
PackedTfragVertices packed_vertices;
|
||||
std::vector<TimeOfDayColor> colors; // vertex colors (pre-interpolation)
|
||||
BVH bvh; // the bvh for frustum culling
|
||||
PackedTimeOfDay colors; // vertex colors (pre-interpolation)
|
||||
BVH bvh; // the bvh for frustum culling
|
||||
bool use_strips = true;
|
||||
|
||||
struct {
|
||||
@@ -401,7 +411,7 @@ struct TieTree {
|
||||
std::array<u32, kNumTieCategories + 1> category_draw_indices;
|
||||
|
||||
PackedTieVertices packed_vertices;
|
||||
std::vector<TimeOfDayColor> colors; // vertex colors (pre-interpolation)
|
||||
PackedTimeOfDay colors; // vertex colors (pre-interpolation)
|
||||
|
||||
std::vector<InstancedStripDraw> instanced_wind_draws;
|
||||
std::vector<TieWindInstance> wind_instance_info;
|
||||
@@ -422,7 +432,7 @@ struct TieTree {
|
||||
|
||||
struct ShrubTree {
|
||||
// todo some visibility structure
|
||||
std::vector<TimeOfDayColor> time_of_day_colors; // multiplier colors
|
||||
PackedTimeOfDay time_of_day_colors; // multiplier colors
|
||||
|
||||
PackedShrubVertices packed_vertices;
|
||||
std::vector<ShrubDraw> static_draws; // the actual topology and settings
|
||||
@@ -441,6 +451,43 @@ struct ShrubTree {
|
||||
void unpack();
|
||||
};
|
||||
|
||||
struct HfragmentVertex {
|
||||
float height = 0;
|
||||
u32 vi = 0;
|
||||
u16 color_index = 0;
|
||||
u8 u = 0, v = 0;
|
||||
u32 pad = 0;
|
||||
};
|
||||
|
||||
struct HfragmentCorner {
|
||||
math::Vector<float, 4> bsphere;
|
||||
u32 vis_id = 0;
|
||||
u32 index_start = 0;
|
||||
u32 index_length = 0;
|
||||
u32 num_tris = 0;
|
||||
};
|
||||
|
||||
struct HfragmentBucket {
|
||||
std::vector<u32> corners;
|
||||
std::array<u16, 16> montage_table;
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
struct Hfragment {
|
||||
std::vector<HfragmentVertex> vertices;
|
||||
std::vector<u32> indices;
|
||||
std::vector<HfragmentCorner> corners;
|
||||
std::vector<HfragmentBucket> buckets;
|
||||
PackedTimeOfDay time_of_day_colors;
|
||||
|
||||
std::array<s32, 4> wang_tree_tex_id;
|
||||
DrawMode draw_mode;
|
||||
u32 occlusion_offset;
|
||||
|
||||
void serialize(Serializer& ser);
|
||||
void memory_usage(MemoryUsageTracker* tracker) const;
|
||||
};
|
||||
|
||||
struct CollisionMesh {
|
||||
struct Vertex {
|
||||
float x, y, z;
|
||||
@@ -483,6 +530,8 @@ struct MercDraw {
|
||||
u32 first_index;
|
||||
u32 index_count;
|
||||
u32 num_triangles;
|
||||
// no strip hack for custom models
|
||||
bool no_strip = false;
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
@@ -566,6 +615,7 @@ struct Level {
|
||||
std::array<std::vector<TfragTree>, TFRAG_GEOS> tfrag_trees;
|
||||
std::array<std::vector<TieTree>, TIE_GEOS> tie_trees;
|
||||
std::vector<ShrubTree> shrub_trees;
|
||||
Hfragment hfrag;
|
||||
CollisionMesh collision;
|
||||
MercModelGroup merc_data;
|
||||
u16 version2 = TFRAG3_VERSION;
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "fmt/core.h"
|
||||
|
||||
std::string DmaTag::print() {
|
||||
std::string DmaTag::print() const {
|
||||
std::string result;
|
||||
const char* mode_names[8] = {"refe", "cnt", "next", "ref", "refs", "call", "ret", "end"};
|
||||
result += fmt::format("TAG: 0x{:08x} {:4s} qwc 0x{:04x}", addr, mode_names[(int)kind], qwc);
|
||||
@@ -15,7 +15,7 @@ std::string DmaTag::print() {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string VifCode::print() {
|
||||
std::string VifCode::print() const {
|
||||
std::string result;
|
||||
|
||||
switch (kind) {
|
||||
|
||||
+2
-2
@@ -52,7 +52,7 @@ struct DmaTag {
|
||||
|
||||
bool operator!=(const DmaTag& other) const { return !((*this) == other); }
|
||||
|
||||
std::string print();
|
||||
std::string print() const;
|
||||
};
|
||||
|
||||
inline void emulate_dma(const void* source_base, void* dest_base, u32 tadr, u32 dadr) {
|
||||
@@ -148,7 +148,7 @@ struct VifCode {
|
||||
u16 num;
|
||||
u16 immediate;
|
||||
|
||||
std::string print();
|
||||
std::string print() const;
|
||||
};
|
||||
|
||||
struct VifCodeStcycl {
|
||||
|
||||
@@ -12,7 +12,6 @@ Also in general I found it _really_ hard to find modern and easy to understand a
|
||||
Atleast for me, it helps to understand the path code takes as it flows through the formatting process. Originally I tried to do as much at once for sake of efficiency but this just makes things incredibly hard to reason about and fix bugs. So like any problem that is complex, break it down, the formatter goes through many distinct phases chipping away at the problem:
|
||||
|
||||
```mermaid
|
||||
%%{init: {'theme': 'dark', "flowchart" : { "curve" : "basis" } } }%%
|
||||
flowchart TB
|
||||
subgraph top1 [Build a Formatting Tree]
|
||||
direction TB
|
||||
|
||||
@@ -33,14 +33,16 @@ int hang_indentation_width(const FormatterTreeNode& curr_node) {
|
||||
return 1 + hang_indentation_width(first_elt);
|
||||
}
|
||||
|
||||
// TODO - this doesn't account for paren's width contribution!
|
||||
int get_total_form_inlined_width(const FormatterTreeNode& curr_node) {
|
||||
if (curr_node.token) {
|
||||
return curr_node.token->length();
|
||||
}
|
||||
int width = 1;
|
||||
for (const auto& ref : curr_node.refs) {
|
||||
width += get_total_form_inlined_width(ref);
|
||||
for (int i = 0; i < curr_node.refs.size(); i++) {
|
||||
width += get_total_form_inlined_width(curr_node.refs.at(i));
|
||||
if (i != curr_node.refs.size() - 1) {
|
||||
width += 1; // add the space between elements
|
||||
}
|
||||
}
|
||||
return width + 1;
|
||||
}
|
||||
@@ -49,7 +51,9 @@ int get_total_form_inlined_width(const FormatterTreeNode& curr_node) {
|
||||
void apply_formatting_config(
|
||||
FormatterTreeNode& curr_node,
|
||||
std::optional<std::shared_ptr<formatter_rules::config::FormFormattingConfig>>
|
||||
config_from_parent = {}) {
|
||||
config_from_parent = {},
|
||||
std::optional<std::shared_ptr<formatter_rules::config::FormFormattingConfig>>
|
||||
config_merge_from_parent = {}) {
|
||||
using namespace formatter_rules;
|
||||
// node is empty, base-case
|
||||
if (curr_node.token || curr_node.refs.empty()) {
|
||||
@@ -65,6 +69,13 @@ void apply_formatting_config(
|
||||
predefined_config = config::opengoal_form_config.at(form_head.value());
|
||||
curr_node.formatting_config = predefined_config.value();
|
||||
}
|
||||
|
||||
if (config_merge_from_parent) {
|
||||
const auto& merge_config = *config_merge_from_parent.value();
|
||||
curr_node.formatting_config.parent_mutable_extra_indent +=
|
||||
merge_config.parent_mutable_extra_indent;
|
||||
curr_node.formatting_config.prevent_inlining = merge_config.prevent_inlining;
|
||||
}
|
||||
} else if (config_from_parent) {
|
||||
// TODO - doesn't merge just replaces, a bit inflexible
|
||||
predefined_config = *config_from_parent.value();
|
||||
@@ -104,7 +115,7 @@ void apply_formatting_config(
|
||||
if (curr_node.formatting_config.has_constant_pairs) {
|
||||
for (int i = 0; i < (int)curr_node.refs.size(); i++) {
|
||||
auto& child_ref = curr_node.refs.at(i);
|
||||
const auto type = child_ref.metadata.node_type;
|
||||
const auto& type = child_ref.metadata.node_type;
|
||||
if (constant_types.find(type) == constant_types.end() &&
|
||||
constant_pairs::is_element_second_in_constant_pair(curr_node, child_ref, i)) {
|
||||
child_ref.formatting_config.parent_mutable_extra_indent = 2;
|
||||
@@ -129,13 +140,16 @@ void apply_formatting_config(
|
||||
auto& ref = curr_node.refs.at(i);
|
||||
if (!ref.token) {
|
||||
// If the child has a pre-defined configuration at that index, we pass it along
|
||||
if (predefined_config &&
|
||||
predefined_config->index_configs.find(i) != predefined_config->index_configs.end()) {
|
||||
apply_formatting_config(ref, predefined_config->index_configs.at(i));
|
||||
if (predefined_config && predefined_config->index_config_override.find(i) !=
|
||||
predefined_config->index_config_override.end()) {
|
||||
apply_formatting_config(ref, {}, predefined_config->index_config_override.at(i));
|
||||
} else if (predefined_config && predefined_config->index_configs.find(i) !=
|
||||
predefined_config->index_configs.end()) {
|
||||
apply_formatting_config(ref, predefined_config->index_configs.at(i), {});
|
||||
} else if (predefined_config && predefined_config->default_index_config) {
|
||||
apply_formatting_config(ref, predefined_config->default_index_config);
|
||||
apply_formatting_config(ref, predefined_config->default_index_config, {});
|
||||
} else {
|
||||
apply_formatting_config(ref);
|
||||
apply_formatting_config(ref, {}, {});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,10 +165,27 @@ void apply_formatting_config(
|
||||
max_columns = field.refs.size();
|
||||
}
|
||||
}
|
||||
// if only one field has a value in the max col position, it looks weird for it to be indented
|
||||
bool ignore_final_column_width = true;
|
||||
int fields_with_atleast_max_col = 0;
|
||||
for (const auto& field : curr_node.refs) {
|
||||
if ((int)field.refs.size() == max_columns) {
|
||||
fields_with_atleast_max_col++;
|
||||
if (fields_with_atleast_max_col > 1) {
|
||||
ignore_final_column_width = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now find the column max widths
|
||||
std::vector<int> column_max_widths = {};
|
||||
for (int col = 0; col < max_columns; col++) {
|
||||
column_max_widths.push_back(0);
|
||||
// -2 because its the indentation before the final column that we want to skip
|
||||
if (col >= curr_node.formatting_config.num_columns_to_compute_widths ||
|
||||
(ignore_final_column_width && col == max_columns - 2)) {
|
||||
continue;
|
||||
}
|
||||
for (const auto& field : curr_node.refs) {
|
||||
if ((int)field.refs.size() > col) {
|
||||
const auto width = get_total_form_inlined_width(field.refs.at(col));
|
||||
@@ -202,6 +233,10 @@ bool form_contains_node_that_prevents_inlining(const FormatterTreeNode& curr_nod
|
||||
bool can_node_be_inlined(const FormatterTreeNode& curr_node, int cursor_pos) {
|
||||
using namespace formatter_rules;
|
||||
if (curr_node.formatting_config.force_inline) {
|
||||
// Ensure there are no comments, this still trumps this
|
||||
if (form_contains_comment(curr_node)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// First off, we cannot inline the top level
|
||||
@@ -264,13 +299,15 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
|
||||
// Add new line entry
|
||||
if (ref.token) {
|
||||
// Cleanup block-comments
|
||||
std::string val = ref.token_str();
|
||||
if (ref.metadata.node_type == "block_comment") {
|
||||
// TODO - change this sanitization to return a list of lines instead of a single new-lined
|
||||
// line
|
||||
val = comments::format_block_comment(ref.token_str());
|
||||
const auto comment_lines = comments::format_block_comment(ref.token_str());
|
||||
for (const auto& line : comment_lines) {
|
||||
form_lines.push_back(line);
|
||||
}
|
||||
} else {
|
||||
form_lines.push_back(ref.token_str());
|
||||
}
|
||||
form_lines.push_back(val);
|
||||
|
||||
if (!curr_node.metadata.is_top_level && i == (int)curr_node.refs.size() - 1 &&
|
||||
(ref.metadata.is_comment)) {
|
||||
// if there's an inline comment at the end of a form, we have to force the paren to the next
|
||||
@@ -292,26 +329,41 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
|
||||
if (i == (int)curr_node.refs.size() - 1 && form_lines.size() > 1 &&
|
||||
(curr_node.formatting_config.hang_forms ||
|
||||
curr_node.formatting_config.combine_first_two_lines)) {
|
||||
form_lines.at(0) += fmt::format(" {}", form_lines.at(1));
|
||||
form_lines.at(0) += fmt::format(" {}", str_util::ltrim(form_lines.at(1)));
|
||||
form_lines.erase(form_lines.begin() + 1);
|
||||
} else if ((i + 1) < (int)curr_node.refs.size()) {
|
||||
const auto& next_ref = curr_node.refs.at(i + 1);
|
||||
// combine the next inline comment or constant pair
|
||||
if ((next_ref.metadata.node_type == "comment" && next_ref.metadata.is_inline) ||
|
||||
(curr_node.formatting_config.has_constant_pairs &&
|
||||
constant_pairs::is_element_second_in_constant_pair(curr_node, next_ref, i + 1))) {
|
||||
constant_pairs::is_element_second_in_constant_pair(curr_node, next_ref, i + 1)) ||
|
||||
constant_pairs::is_element_second_in_constant_pair_new(curr_node.refs.at(i), next_ref)) {
|
||||
// TODO
|
||||
// has issues with not consolidating first lines, this should probably just be moved to
|
||||
// outside this loop for simplicity, do it later
|
||||
if (next_ref.token) {
|
||||
form_lines.at(form_lines.size() - 1) += fmt::format(" {}", next_ref.token.value());
|
||||
form_lines.at(form_lines.size() - 1) += fmt::format(" {}", next_ref.token_str());
|
||||
i++;
|
||||
// We have to handle hang-consolidation here or else it will never be reached above!
|
||||
if (i == (int)curr_node.refs.size() - 1 && form_lines.size() > 1 &&
|
||||
(curr_node.formatting_config.hang_forms ||
|
||||
curr_node.formatting_config.combine_first_two_lines)) {
|
||||
form_lines.at(0) += fmt::format(" {}", form_lines.at(1));
|
||||
form_lines.erase(form_lines.begin() + 1);
|
||||
}
|
||||
} else if (can_node_be_inlined(next_ref, cursor_pos)) {
|
||||
const auto& lines = apply_formatting(next_ref, {}, cursor_pos); // TODO - cursor pos
|
||||
for (const auto& line : lines) {
|
||||
form_lines.at(form_lines.size() - 1) += fmt::format(" {}", line);
|
||||
}
|
||||
i++;
|
||||
// We have to handle hang-consolidation here or else it will never be reached above!
|
||||
if (i == (int)curr_node.refs.size() - 1 && form_lines.size() > 1 &&
|
||||
(curr_node.formatting_config.hang_forms ||
|
||||
curr_node.formatting_config.combine_first_two_lines)) {
|
||||
form_lines.at(0) += fmt::format(" {}", form_lines.at(1));
|
||||
form_lines.erase(form_lines.begin() + 1);
|
||||
}
|
||||
}
|
||||
if (!curr_node.metadata.is_top_level && next_ref.metadata.node_type == "comment" &&
|
||||
(i + 1) == (int)curr_node.refs.size()) {
|
||||
@@ -328,7 +380,9 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
|
||||
// Consolidate any lines if the configuration requires it
|
||||
// TODO there is a hack here so that multi-line forms that are consolidated still line up properly
|
||||
// i have to make consolidate a more first-class feature of the config
|
||||
if (curr_node.formatting_config.inline_until_index(form_lines)) {
|
||||
// TODO - hacky, but prevents a bad situation, clean up
|
||||
if (curr_node.formatting_config.inline_until_index(form_lines) &&
|
||||
!str_util::contains(form_lines.at(0), ";")) {
|
||||
std::vector<std::string> new_form_lines = {};
|
||||
const auto original_form_head_width = str_util::split(form_lines.at(0), '\n').at(0).length();
|
||||
bool consolidating_lines = true;
|
||||
@@ -374,22 +428,32 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
|
||||
form_lines[form_lines.size() - 1] =
|
||||
fmt::format("{}{}", form_lines[form_lines.size() - 1], form_surround_end);
|
||||
}
|
||||
std::string curr_form = "";
|
||||
if (curr_node.formatting_config.parent_mutable_extra_indent > 0) {
|
||||
curr_form += str_util::repeat(curr_node.formatting_config.parent_mutable_extra_indent, " ");
|
||||
}
|
||||
if (inline_form) {
|
||||
form_lines = {fmt::format("{}", fmt::join(form_lines, " "))};
|
||||
// NOTE - not sure about this, if we are inlining a form, it always makes sense to eliminate
|
||||
// trailing whitespace the only issue i can foresee is related to strings that span multiple
|
||||
// lines.
|
||||
std::vector<std::string> new_form_lines = {};
|
||||
for (const auto& form_line : form_lines) {
|
||||
new_form_lines.push_back(str_util::ltrim(form_line));
|
||||
}
|
||||
form_lines = {fmt::format("{}", fmt::join(new_form_lines, " "))};
|
||||
} else {
|
||||
bool currently_in_block_comment = false;
|
||||
for (int i = 0; i < (int)form_lines.size(); i++) {
|
||||
if (i > 0) {
|
||||
auto& line = form_lines.at(i);
|
||||
auto& line = form_lines.at(i);
|
||||
if (str_util::contains(line, "|#")) {
|
||||
currently_in_block_comment = false;
|
||||
}
|
||||
if (i > 0 && !currently_in_block_comment) {
|
||||
line = fmt::format("{}{}",
|
||||
str_util::repeat(curr_node.formatting_config.indentation_width_for_index(
|
||||
curr_node.formatting_config, i),
|
||||
" "),
|
||||
line);
|
||||
}
|
||||
if (str_util::contains(line, "#|") && !str_util::contains(line, "|#")) {
|
||||
currently_in_block_comment = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return form_lines;
|
||||
|
||||
@@ -79,18 +79,18 @@ FormatterTree::FormatterTree(const std::string& source, const TSNode& root_node)
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, std::vector<std::string>> node_type_ignorable_contents = {
|
||||
{"list_lit", {"(", ")"}},
|
||||
{"quoting_lit", {"'"}},
|
||||
{"unquoting_lit", {","}},
|
||||
{"quasi_quoting_lit", {"`"}}};
|
||||
{"list_lit", {"(", ")"}}};
|
||||
|
||||
// TODO make an imperative version eventually
|
||||
// TODO - cleanup duplication
|
||||
void FormatterTree::construct_formatter_tree_recursive(const std::string& source,
|
||||
TSNode curr_node,
|
||||
FormatterTreeNode& tree_node,
|
||||
std::optional<std::string> node_prefix) {
|
||||
if (ts_node_child_count(curr_node) == 0) {
|
||||
tree_node.refs.push_back(FormatterTreeNode(source, curr_node));
|
||||
auto new_node = FormatterTreeNode(source, curr_node);
|
||||
new_node.node_prefix = node_prefix;
|
||||
tree_node.refs.push_back(new_node);
|
||||
return;
|
||||
}
|
||||
const std::string curr_node_type = ts_node_type(curr_node);
|
||||
@@ -105,11 +105,37 @@ void FormatterTree::construct_formatter_tree_recursive(const std::string& source
|
||||
tree_node.refs.push_back(FormatterTreeNode(source, curr_node));
|
||||
return;
|
||||
} else if (curr_node_type == "quoting_lit") {
|
||||
next_node_prefix = "'";
|
||||
if (node_prefix) {
|
||||
node_prefix.value() += "'";
|
||||
} else {
|
||||
node_prefix = "'";
|
||||
}
|
||||
construct_formatter_tree_recursive(source, ts_node_child(curr_node, 1), tree_node, node_prefix);
|
||||
return;
|
||||
} else if (curr_node_type == "unquoting_lit") {
|
||||
next_node_prefix = ",";
|
||||
if (node_prefix) {
|
||||
node_prefix.value() += ",";
|
||||
} else {
|
||||
node_prefix = ",";
|
||||
}
|
||||
construct_formatter_tree_recursive(source, ts_node_child(curr_node, 1), tree_node, node_prefix);
|
||||
return;
|
||||
} else if (curr_node_type == "quasi_quoting_lit") {
|
||||
next_node_prefix = "`";
|
||||
if (node_prefix) {
|
||||
node_prefix.value() += "`";
|
||||
} else {
|
||||
node_prefix = "`";
|
||||
}
|
||||
construct_formatter_tree_recursive(source, ts_node_child(curr_node, 1), tree_node, node_prefix);
|
||||
return;
|
||||
} else if (curr_node_type == "unquote_splicing_lit") {
|
||||
if (node_prefix) {
|
||||
node_prefix.value() += ",@";
|
||||
} else {
|
||||
node_prefix = ",@";
|
||||
}
|
||||
construct_formatter_tree_recursive(source, ts_node_child(curr_node, 1), tree_node, node_prefix);
|
||||
return;
|
||||
}
|
||||
std::vector<std::string> skippable_nodes = {};
|
||||
if (node_type_ignorable_contents.find(curr_node_type) != node_type_ignorable_contents.end()) {
|
||||
@@ -117,6 +143,7 @@ void FormatterTree::construct_formatter_tree_recursive(const std::string& source
|
||||
}
|
||||
for (size_t i = 0; i < ts_node_child_count(curr_node); i++) {
|
||||
const auto child_node = ts_node_child(curr_node, i);
|
||||
auto debug_child = ts_node_string(child_node);
|
||||
const auto contents = get_source_code(source, child_node);
|
||||
bool skip_node = false;
|
||||
for (const auto& skippable_content : skippable_nodes) {
|
||||
@@ -129,19 +156,22 @@ void FormatterTree::construct_formatter_tree_recursive(const std::string& source
|
||||
continue;
|
||||
}
|
||||
if (curr_node_type == "list_lit") {
|
||||
construct_formatter_tree_recursive(source, child_node, list_node, next_node_prefix);
|
||||
construct_formatter_tree_recursive(source, child_node, list_node, {});
|
||||
if (node_prefix) {
|
||||
list_node.node_prefix = node_prefix;
|
||||
}
|
||||
} else {
|
||||
construct_formatter_tree_recursive(source, child_node, tree_node, next_node_prefix);
|
||||
// TODO - im not sure if this is correct
|
||||
construct_formatter_tree_recursive(source, child_node, tree_node, node_prefix);
|
||||
if (node_prefix && !tree_node.refs.empty()) {
|
||||
tree_node.refs.at(tree_node.refs.size() - 1).node_prefix = node_prefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (curr_node_type == "list_lit") {
|
||||
// special case for empty lists
|
||||
if (node_prefix && !list_node.node_prefix) {
|
||||
list_node.node_prefix = node_prefix;
|
||||
}
|
||||
tree_node.refs.push_back(list_node);
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,16 @@ namespace formatter_rules {
|
||||
// differentiate between a quoted symbol and a quoted form
|
||||
const std::set<std::string> constant_types = {"kwd_lit", "num_lit", "str_lit",
|
||||
"char_lit", "null_lit", "bool_lit"};
|
||||
const std::set<std::string> constant_type_forms = {"meters", "seconds", "degrees"};
|
||||
|
||||
namespace constant_list {
|
||||
bool is_constant_list(const FormatterTreeNode& node) {
|
||||
if (!node.is_list() || node.refs.empty()) {
|
||||
return false;
|
||||
}
|
||||
if (!node.refs.at(0).token) {
|
||||
return true;
|
||||
}
|
||||
const auto& type = node.refs.at(0).metadata.node_type;
|
||||
return constant_types.find(type) != constant_types.end();
|
||||
}
|
||||
@@ -36,21 +40,28 @@ bool should_insert_blank_line(const FormatterTreeNode& containing_node,
|
||||
if (node.metadata.is_comment && node.metadata.num_blank_lines_following == 0) {
|
||||
return false;
|
||||
}
|
||||
// If the next form is a comment and is inline, don't insert a comment
|
||||
// If the next form is a comment and is inline, don't insert a new line
|
||||
if ((index + 1) < (int)containing_node.refs.size() &&
|
||||
containing_node.refs.at(index + 1).metadata.is_comment &&
|
||||
containing_node.refs.at(index + 1).metadata.is_inline) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO - only if the form doesn't fit on a single line
|
||||
if (node.formatting_config.elide_top_level_newline) {
|
||||
if ((index + 1) < (int)containing_node.refs.size() &&
|
||||
containing_node.refs.at(index + 1).metadata.is_comment) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace blank_lines
|
||||
|
||||
namespace comments {
|
||||
std::string format_block_comment(const std::string& comment) {
|
||||
std::vector<std::string> format_block_comment(const std::string& comment) {
|
||||
// Normalize block comments, remove any trailing or leading whitespace
|
||||
// Only allow annotations on the first line, like #|@file
|
||||
// Don't mess with internal indentation as the user might intend it to be a certain way.
|
||||
@@ -71,12 +82,22 @@ std::string format_block_comment(const std::string& comment) {
|
||||
// Remove trailing whitespace
|
||||
comment_contents = str_util::rtrim(comment_contents);
|
||||
// remove |#
|
||||
// TODO - check suffix
|
||||
comment_contents.pop_back();
|
||||
comment_contents.pop_back();
|
||||
if (str_util::ends_with(comment_contents, "|#")) {
|
||||
comment_contents.pop_back();
|
||||
comment_contents.pop_back();
|
||||
}
|
||||
comment_contents = str_util::rtrim(comment_contents);
|
||||
new_comment += fmt::format("\n{}\n|#", comment_contents);
|
||||
return new_comment;
|
||||
std::vector<std::string> lines = {new_comment};
|
||||
const auto contents_as_lines = str_util::split_string(comment_contents, "\n");
|
||||
if (contents_as_lines.size() > 1) {
|
||||
for (const auto& line : contents_as_lines) {
|
||||
lines.push_back(line);
|
||||
}
|
||||
lines.push_back("|#");
|
||||
} else {
|
||||
lines.at(0) = fmt::format("{} {} |#", new_comment, str_util::trim(contents_as_lines.at(0)));
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
} // namespace comments
|
||||
|
||||
@@ -101,6 +122,46 @@ bool is_element_second_in_constant_pair(const FormatterTreeNode& containing_node
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO - potentially remove the above
|
||||
bool is_element_second_in_constant_pair_new(const FormatterTreeNode& prev_node,
|
||||
const FormatterTreeNode& curr_node) {
|
||||
if (prev_node.metadata.node_type == "kwd_lit") {
|
||||
// Handle standard constant types
|
||||
// TODO - pair up sym_names as well
|
||||
if (constant_types.find(curr_node.metadata.node_type) != constant_types.end()) {
|
||||
if (curr_node.metadata.node_type != "kwd_lit") {
|
||||
// NOTE - there is ambiugity here which cannot be totally solved (i think?)
|
||||
// if the element itself is also a keyword, assume this is two adjacent keywords and they
|
||||
// should not be paired
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Quoted symbols
|
||||
if (curr_node.metadata.node_type == "sym_name" && curr_node.node_prefix &&
|
||||
(curr_node.node_prefix.value() == "'" || curr_node.node_prefix.value() == ",")) {
|
||||
return true;
|
||||
}
|
||||
if (!curr_node.refs.empty()) {
|
||||
// Constant forms special cases (ie. meters)
|
||||
if (constant_type_forms.find(curr_node.refs.at(0).token_str()) != constant_type_forms.end()) {
|
||||
return true;
|
||||
}
|
||||
// If they are just a list of symbol names (enum or simple method call)
|
||||
bool all_symbols = true;
|
||||
for (const auto& ref : curr_node.refs) {
|
||||
if (ref.metadata.node_type != "sym_name") {
|
||||
all_symbols = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all_symbols) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool form_should_be_constant_paired(const FormatterTreeNode& node) {
|
||||
// Criteria for a list to be constant paired:
|
||||
// - needs to start with a non-symbol
|
||||
|
||||
@@ -36,7 +36,7 @@ bool should_insert_blank_line(const FormatterTreeNode& containing_node,
|
||||
//
|
||||
// Reference - https://github.com/kkinnear/zprint/blob/main/doc/options/comments.md
|
||||
namespace comments {
|
||||
std::string format_block_comment(const std::string& comment);
|
||||
std::vector<std::string> format_block_comment(const std::string& comment);
|
||||
}
|
||||
|
||||
// Paired elements in a list will be kept in-line rather than the default new-line indentation
|
||||
@@ -72,6 +72,8 @@ const static int min_pair_amount = 4;
|
||||
bool is_element_second_in_constant_pair(const FormatterTreeNode& containing_node,
|
||||
const FormatterTreeNode& node,
|
||||
const int index);
|
||||
bool is_element_second_in_constant_pair_new(const FormatterTreeNode& prev_node,
|
||||
const FormatterTreeNode& curr_node);
|
||||
bool form_should_be_constant_paired(const FormatterTreeNode& node);
|
||||
} // namespace constant_pairs
|
||||
|
||||
|
||||
@@ -1,24 +1,146 @@
|
||||
#include "rule_config.h"
|
||||
|
||||
#include "common/util/string_util.h"
|
||||
|
||||
namespace formatter_rules {
|
||||
namespace config {
|
||||
|
||||
static FormFormattingConfig new_inlinable_simple_flow_rule() {
|
||||
return {.config_set = true, .hang_forms = false};
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_permissive_flow_rule() {
|
||||
return {.config_set = true, .hang_forms = false, .combine_first_two_lines = true};
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_flow_rule(int start_index) {
|
||||
static FormFormattingConfig new_flow_rule(int start_index, bool has_constant_pairs = false) {
|
||||
return {.config_set = true,
|
||||
.hang_forms = false,
|
||||
.inline_until_index = [start_index](const std::vector<std::string>& /*curr_lines*/) {
|
||||
return start_index;
|
||||
}};
|
||||
.inline_until_index =
|
||||
[start_index](const std::vector<std::string>& /*curr_lines*/) { return start_index; },
|
||||
.has_constant_pairs = has_constant_pairs};
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_function_rule(int start_index, bool has_constant_pairs = false) {
|
||||
FormFormattingConfig cfg = {
|
||||
.config_set = true,
|
||||
.hang_forms = false,
|
||||
.inline_until_index =
|
||||
[start_index](const std::vector<std::string>& /*curr_lines*/) { return start_index; },
|
||||
.has_constant_pairs = has_constant_pairs};
|
||||
auto arg_list_config = std::make_shared<FormFormattingConfig>();
|
||||
arg_list_config->force_inline = true;
|
||||
arg_list_config->hang_forms = false;
|
||||
cfg.index_configs.emplace(2, arg_list_config);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_inlineable_flow_rule(int start_index,
|
||||
bool has_constant_pairs = false) {
|
||||
return {.config_set = true,
|
||||
.hang_forms = false,
|
||||
.inline_until_index =
|
||||
[start_index](const std::vector<std::string>& curr_lines) {
|
||||
int total_width = 0;
|
||||
for (const auto& line : curr_lines) {
|
||||
// Check for comments
|
||||
// TODO - this shows how this isn't really the best strategy but it holds up
|
||||
if (str_util::contains(line, ";")) {
|
||||
// Can't inline, there's a comment!
|
||||
return start_index;
|
||||
}
|
||||
total_width += line.length();
|
||||
// an empty line implies a new-line was forced, this is bleeding implementation
|
||||
// details, but fine for now
|
||||
if (line.empty()) {
|
||||
return start_index;
|
||||
}
|
||||
}
|
||||
if (total_width <= 120) {
|
||||
return (int)curr_lines.size();
|
||||
}
|
||||
return start_index;
|
||||
},
|
||||
.has_constant_pairs = has_constant_pairs};
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_defstate_rule(int start_index, bool has_constant_pairs = false) {
|
||||
FormFormattingConfig cfg = {
|
||||
.config_set = true,
|
||||
.hang_forms = false,
|
||||
.inline_until_index =
|
||||
[start_index](const std::vector<std::string>& /*curr_lines*/) { return start_index; },
|
||||
.has_constant_pairs = has_constant_pairs};
|
||||
std::vector<int> state_handler_indexes = {4, 6, 8, 10,
|
||||
12, 14}; // NOTE - not all of these have to be defined
|
||||
for (const auto& index : state_handler_indexes) {
|
||||
auto temp_config = std::make_shared<FormFormattingConfig>();
|
||||
temp_config->prevent_inlining = true;
|
||||
temp_config->parent_mutable_extra_indent = 2;
|
||||
cfg.index_config_override.emplace(index, temp_config);
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_defmethod_rule(int start_index, bool has_constant_pairs = false) {
|
||||
// TODO - might be nice to have a function that returns a config based on a given index, instead
|
||||
// of hardcoding them!
|
||||
// Right now this only works for non-`new` methods (else we may bleed into the body of a normal
|
||||
// method)
|
||||
auto arg_list_config = std::make_shared<FormFormattingConfig>();
|
||||
arg_list_config->force_inline = true;
|
||||
arg_list_config->hang_forms = false;
|
||||
FormFormattingConfig cfg = {.config_set = true,
|
||||
.hang_forms = false,
|
||||
.inline_until_index =
|
||||
[start_index](const std::vector<std::string>& curr_lines) {
|
||||
if (curr_lines.size() >= 2 && curr_lines.at(1) == "new") {
|
||||
// defmethod was changed to omit the type name for everything
|
||||
// except the `new` method, so special case.
|
||||
return start_index + 1;
|
||||
}
|
||||
return start_index;
|
||||
},
|
||||
.has_constant_pairs = has_constant_pairs};
|
||||
cfg.index_configs.emplace(2, arg_list_config);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_lambda_rule(int start_index, bool has_constant_pairs = false) {
|
||||
FormFormattingConfig cfg = {.config_set = true,
|
||||
.hang_forms = false,
|
||||
.inline_until_index =
|
||||
[start_index](const std::vector<std::string>& curr_lines) {
|
||||
if (curr_lines.size() >= 2 && curr_lines.at(1) == ":behavior") {
|
||||
// defmethod was changed to omit the type name for everything
|
||||
// except the `new` method, so special case.
|
||||
return start_index + 2;
|
||||
}
|
||||
return start_index;
|
||||
},
|
||||
.has_constant_pairs = has_constant_pairs};
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_defenum_rule() {
|
||||
auto temp_list_config = std::make_shared<FormFormattingConfig>();
|
||||
temp_list_config->force_inline = true;
|
||||
temp_list_config->hang_forms = false;
|
||||
return {
|
||||
.config_set = true,
|
||||
.hang_forms = false,
|
||||
.inline_until_index = [](const std::vector<std::string>& /*curr_lines*/) { return 2; },
|
||||
.has_constant_pairs = true,
|
||||
.default_index_config = temp_list_config,
|
||||
};
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_deftype_rule(
|
||||
int start_index,
|
||||
int num_columns_to_compute_widths,
|
||||
const std::vector<int>& inlining_preventation_indices) {
|
||||
FormFormattingConfig cfg;
|
||||
cfg.has_constant_pairs = true;
|
||||
cfg.config_set = true;
|
||||
cfg.hang_forms = false;
|
||||
cfg.inline_until_index = [start_index](std::vector<std::string> curr_lines) {
|
||||
@@ -39,6 +161,7 @@ static FormFormattingConfig new_deftype_rule(
|
||||
temp_config->default_index_config = temp_list_config;
|
||||
if (index == 3) {
|
||||
temp_config->determine_column_widths_for_list_elements = true;
|
||||
temp_config->num_columns_to_compute_widths = num_columns_to_compute_widths;
|
||||
}
|
||||
cfg.index_configs.emplace(index, temp_config);
|
||||
}
|
||||
@@ -74,6 +197,29 @@ static FormFormattingConfig new_binding_rule(int form_head_width) {
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_inline_binding_rule(int form_head_width) {
|
||||
FormFormattingConfig cfg;
|
||||
cfg.config_set = true;
|
||||
cfg.hang_forms = false;
|
||||
cfg.combine_first_two_lines = true;
|
||||
auto binding_list_config = std::make_shared<FormFormattingConfig>();
|
||||
binding_list_config->config_set = true;
|
||||
binding_list_config->hang_forms = false;
|
||||
binding_list_config->indentation_width = 1;
|
||||
binding_list_config->indentation_width_for_index = [form_head_width](FormFormattingConfig /*cfg*/,
|
||||
int index) {
|
||||
if (index == 0) {
|
||||
return 0;
|
||||
}
|
||||
return form_head_width;
|
||||
};
|
||||
binding_list_config->should_prevent_inlining = [](FormFormattingConfig /*config*/, int num_refs) {
|
||||
return false;
|
||||
};
|
||||
cfg.index_configs.emplace(1, binding_list_config);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_pair_rule(bool combine_first_two_expr) {
|
||||
FormFormattingConfig cfg;
|
||||
cfg.config_set = true;
|
||||
@@ -88,23 +234,71 @@ static FormFormattingConfig new_pair_rule(bool combine_first_two_expr) {
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static FormFormattingConfig new_top_level_inline_form(bool elide_new_line) {
|
||||
return {.force_inline = true, .elide_top_level_newline = elide_new_line};
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config = {
|
||||
{"case", new_pair_rule(true)},
|
||||
{"case-str", new_pair_rule(true)},
|
||||
{"cond", new_pair_rule(false)},
|
||||
{"defmethod", new_flow_rule(3)},
|
||||
{"deftype", new_deftype_rule(3, {3, 4, 5, 6})},
|
||||
{"#cond", new_pair_rule(false)},
|
||||
{"in-package", new_top_level_inline_form(true)},
|
||||
{"bundles", new_top_level_inline_form(true)},
|
||||
{"require", new_top_level_inline_form(true)},
|
||||
{"def-art-elt", new_top_level_inline_form(true)},
|
||||
{"def-joint-node", new_top_level_inline_form(true)},
|
||||
{"declare-file", new_top_level_inline_form(false)},
|
||||
{"defenum", new_defenum_rule()},
|
||||
{"defmethod", new_defmethod_rule(3)},
|
||||
{"lambda", new_lambda_rule(2)},
|
||||
{"deftype", new_deftype_rule(3, 1, {3, 4, 5, 6})},
|
||||
{"defun", new_flow_rule(3)},
|
||||
{"defun-recursive", new_flow_rule(4)},
|
||||
{"defun-debug-recursive", new_flow_rule(4)},
|
||||
{"defun-debug", new_flow_rule(3)},
|
||||
{"defbehavior", new_flow_rule(4)},
|
||||
{"if", new_permissive_flow_rule()},
|
||||
{"if", new_inlineable_flow_rule(2)},
|
||||
{"#if", new_inlineable_flow_rule(2)},
|
||||
{"define", new_permissive_flow_rule()},
|
||||
{"def-mips2c", new_permissive_flow_rule()},
|
||||
{"defconstant", new_permissive_flow_rule()},
|
||||
{"defglobalconstant", new_permissive_flow_rule()},
|
||||
{"defmethod-mips2c", new_permissive_flow_rule()},
|
||||
{"define-extern", new_permissive_flow_rule()},
|
||||
{"defmacro", new_flow_rule(3)},
|
||||
{"declare-type", new_permissive_flow_rule()},
|
||||
{"defmacro", new_function_rule(3)},
|
||||
{"desfun", new_function_rule(3)},
|
||||
{"defskelgroup", new_flow_rule(2, true)},
|
||||
{"defpartgroup", new_flow_rule(2, true)},
|
||||
{"defpart", new_flow_rule(2, true)},
|
||||
{"defstate", new_defstate_rule(3, true)},
|
||||
{"behavior", new_flow_rule(2)},
|
||||
{"dotimes", new_flow_rule(2)},
|
||||
{"dolist", new_flow_rule(2)},
|
||||
{"process-spawn-function", new_flow_rule(2)},
|
||||
{"let", new_binding_rule(4)},
|
||||
{"protect", new_binding_rule(4)},
|
||||
{"let*", new_binding_rule(5)},
|
||||
{"rlet", new_binding_rule(5)},
|
||||
{"when", new_flow_rule(2)},
|
||||
{"unless", new_flow_rule(2)},
|
||||
{"with-profiler", new_flow_rule(2)},
|
||||
{"with-pc", new_flow_rule(0)},
|
||||
{"#unless", new_flow_rule(2)},
|
||||
{"#when", new_flow_rule(2)},
|
||||
{"countdown", new_flow_rule(2)},
|
||||
{"until", new_flow_rule(2)},
|
||||
{"loop", new_flow_rule(0)},
|
||||
{"while", new_flow_rule(2)},
|
||||
{"begin", new_flow_rule(0)},
|
||||
{"seval", new_flow_rule(0)},
|
||||
{"with-pp", new_flow_rule(0)},
|
||||
{"with-gensyms", new_flow_rule(2)},
|
||||
{"with-vf0", new_flow_rule(0)},
|
||||
{"with-vf", new_inline_binding_rule(8)},
|
||||
{"with-cnt-vif-block", new_inline_binding_rule(19)},
|
||||
{"local-vars", new_inlinable_simple_flow_rule()},
|
||||
{"with-dma-buffer-add-bucket", new_flow_rule(2)}};
|
||||
} // namespace config
|
||||
} // namespace formatter_rules
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// TODO - some way to apply a config to all list elements (index configs with -1?)
|
||||
namespace formatter_rules {
|
||||
namespace config {
|
||||
struct FormFormattingConfig {
|
||||
@@ -33,9 +32,14 @@ struct FormFormattingConfig {
|
||||
int parent_mutable_extra_indent = 0;
|
||||
std::optional<std::shared_ptr<FormFormattingConfig>> default_index_config;
|
||||
std::unordered_map<int, std::shared_ptr<FormFormattingConfig>> index_configs = {};
|
||||
// TODO / NOTe - not fully implemented, only doing `parent_mutable_extra_indent` right now
|
||||
std::unordered_map<int, std::shared_ptr<FormFormattingConfig>> index_config_override = {};
|
||||
|
||||
bool determine_column_widths_for_list_elements = false;
|
||||
int num_columns_to_compute_widths = 0;
|
||||
std::vector<int> list_element_column_widths = {};
|
||||
|
||||
bool elide_top_level_newline = false;
|
||||
};
|
||||
|
||||
extern const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config;
|
||||
|
||||
@@ -26,6 +26,8 @@ u64 get_current_tid() {
|
||||
}
|
||||
#endif
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/compress.h"
|
||||
#include "common/util/string_util.h"
|
||||
// clang-format on
|
||||
|
||||
u64 get_current_ts() {
|
||||
@@ -34,12 +36,12 @@ u64 get_current_ts() {
|
||||
|
||||
GlobalProfiler::GlobalProfiler() {
|
||||
m_t0 = get_current_ts();
|
||||
set_max_events(65536);
|
||||
m_nodes.resize(m_max_events);
|
||||
}
|
||||
|
||||
void GlobalProfiler::set_max_events(size_t event_count) {
|
||||
ASSERT(!m_enabled);
|
||||
m_nodes.resize(event_count);
|
||||
void GlobalProfiler::update_event_buffer_size(size_t new_size) {
|
||||
m_max_events = new_size;
|
||||
m_nodes.resize(m_max_events);
|
||||
}
|
||||
|
||||
void GlobalProfiler::set_waiting_for_event(const std::string& event_name) {
|
||||
@@ -72,6 +74,10 @@ void GlobalProfiler::root_event() {
|
||||
instant_event("ROOT");
|
||||
}
|
||||
|
||||
size_t GlobalProfiler::get_next_idx() {
|
||||
return (m_next_idx % m_nodes.size());
|
||||
}
|
||||
|
||||
void GlobalProfiler::begin_event(const char* name) {
|
||||
event(name, ProfNode::BEGIN);
|
||||
}
|
||||
@@ -96,8 +102,10 @@ void GlobalProfiler::set_enable(bool en) {
|
||||
m_enabled = en;
|
||||
}
|
||||
|
||||
void GlobalProfiler::dump_to_json(const std::string& path) {
|
||||
ASSERT(!m_enabled);
|
||||
void GlobalProfiler::dump_to_json() {
|
||||
if (m_enabled) {
|
||||
set_enable(false);
|
||||
}
|
||||
|
||||
nlohmann::json json;
|
||||
auto& trace_events = json["traceEvents"];
|
||||
@@ -185,7 +193,20 @@ void GlobalProfiler::dump_to_json(const std::string& path) {
|
||||
t.second.highest_at_target);
|
||||
}
|
||||
|
||||
file_util::write_text_file(path, json.dump());
|
||||
if (m_enable_compression) {
|
||||
const auto json_str = json.dump();
|
||||
const auto compressed_data =
|
||||
compression::compress_zstd_no_header(json_str.data(), json_str.size());
|
||||
auto file_path = file_util::get_jak_project_dir() / "profile_data" /
|
||||
fmt::format("prof-{}.json.zst", str_util::current_local_timestamp_no_colons());
|
||||
file_util::create_dir_if_needed_for_file(file_path);
|
||||
file_util::write_binary_file(file_path, compressed_data.data(), compressed_data.size());
|
||||
} else {
|
||||
auto file_path = file_util::get_jak_project_dir() / "profile_data" /
|
||||
fmt::format("prof-{}.json", str_util::current_local_timestamp_no_colons());
|
||||
file_util::create_dir_if_needed_for_file(file_path);
|
||||
file_util::write_text_file(file_path, json.dump());
|
||||
}
|
||||
}
|
||||
|
||||
GlobalProfiler gprof;
|
||||
|
||||
@@ -17,7 +17,8 @@ struct ProfNode {
|
||||
class GlobalProfiler {
|
||||
public:
|
||||
GlobalProfiler();
|
||||
void set_max_events(size_t event_count);
|
||||
size_t get_max_events() { return m_max_events; }
|
||||
void update_event_buffer_size(size_t new_size);
|
||||
void set_waiting_for_event(const std::string& event_name);
|
||||
void instant_event(const char* name);
|
||||
void begin_event(const char* name);
|
||||
@@ -25,11 +26,16 @@ class GlobalProfiler {
|
||||
void end_event();
|
||||
void clear();
|
||||
void set_enable(bool en);
|
||||
void dump_to_json(const std::string& path);
|
||||
void dump_to_json();
|
||||
void root_event();
|
||||
bool is_enabled() { return m_enabled; }
|
||||
size_t get_next_idx();
|
||||
|
||||
bool m_enable_compression = false;
|
||||
|
||||
private:
|
||||
std::atomic_bool m_enabled = false;
|
||||
size_t m_max_events = 65536;
|
||||
u64 m_t0 = 0;
|
||||
std::atomic_size_t m_next_idx = 0;
|
||||
std::vector<ProfNode> m_nodes;
|
||||
|
||||
@@ -571,104 +571,6 @@ Object Interpreter::eval(Object obj, const std::shared_ptr<EnvironmentObject>& e
|
||||
}
|
||||
}
|
||||
|
||||
EnvironmentMap::EnvironmentMap() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void EnvironmentMap::clear() {
|
||||
m_entries.clear();
|
||||
m_power_of_two_size = 3; // 2 ^ 3 = 8
|
||||
m_entries.resize(8);
|
||||
m_used_entries = 0;
|
||||
m_next_resize = (m_entries.size() * kMaxUsed);
|
||||
m_mask = 0b111;
|
||||
}
|
||||
|
||||
Object* EnvironmentMap::lookup(InternedSymbolPtr str) {
|
||||
if (m_entries.size() < 10) {
|
||||
for (auto& e : m_entries) {
|
||||
if (e.key == str.name_ptr) {
|
||||
return &e.value;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
u32 hash = crc32((const u8*)&str.name_ptr, sizeof(const char*));
|
||||
|
||||
// probe
|
||||
for (u32 i = 0; i < m_entries.size(); i++) {
|
||||
u32 slot_addr = (hash + i) & m_mask;
|
||||
auto& slot = m_entries[slot_addr];
|
||||
if (!slot.key) {
|
||||
return nullptr;
|
||||
} else {
|
||||
if (slot.key != str.name_ptr) {
|
||||
continue; // bad hash
|
||||
}
|
||||
return &slot.value;
|
||||
}
|
||||
}
|
||||
|
||||
// should be impossible to reach.
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void EnvironmentMap::set(InternedSymbolPtr ptr, const Object& obj) {
|
||||
u32 hash = crc32((const u8*)&ptr.name_ptr, sizeof(const char*));
|
||||
|
||||
// probe
|
||||
for (u32 i = 0; i < m_entries.size(); i++) {
|
||||
u32 slot_addr = (hash + i) & m_mask;
|
||||
auto& slot = m_entries[slot_addr];
|
||||
if (!slot.key) {
|
||||
// not found, insert!
|
||||
slot.key = ptr.name_ptr;
|
||||
slot.value = obj;
|
||||
m_used_entries++;
|
||||
|
||||
if (m_used_entries >= m_next_resize) {
|
||||
resize();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (slot.key == ptr.name_ptr) {
|
||||
slot.value = obj;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// should be impossible to reach.
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
void EnvironmentMap::resize() {
|
||||
m_power_of_two_size++;
|
||||
m_mask = (1U << m_power_of_two_size) - 1;
|
||||
|
||||
std::vector<Entry> new_entries(m_entries.size() * 2);
|
||||
for (const auto& old_entry : m_entries) {
|
||||
if (old_entry.key) {
|
||||
bool done = false;
|
||||
u32 hash = crc32((const u8*)&old_entry.key, sizeof(const char*));
|
||||
for (u32 i = 0; i < new_entries.size(); i++) {
|
||||
u32 slot_addr = (hash + i) & m_mask;
|
||||
auto& slot = new_entries[slot_addr];
|
||||
if (!slot.key) {
|
||||
slot.key = old_entry.key;
|
||||
slot.value = std::move(old_entry.value);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(done);
|
||||
}
|
||||
}
|
||||
|
||||
m_entries = std::move(new_entries);
|
||||
m_next_resize = kMaxUsed * m_entries.size();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/*!
|
||||
|
||||
+100
-9
@@ -55,6 +55,7 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/Assert.h"
|
||||
#include "common/util/crc32.h"
|
||||
|
||||
namespace goos {
|
||||
|
||||
@@ -456,23 +457,111 @@ class PairObject : public HeapObject {
|
||||
~PairObject() = default;
|
||||
};
|
||||
|
||||
class EnvironmentMap {
|
||||
template <typename T>
|
||||
class InternedPtrMap {
|
||||
public:
|
||||
EnvironmentMap(const EnvironmentMap&) = delete;
|
||||
EnvironmentMap& operator=(const EnvironmentMap&) = delete;
|
||||
EnvironmentMap();
|
||||
Object* lookup(InternedSymbolPtr ptr);
|
||||
void set(InternedSymbolPtr ptr, const Object& obj);
|
||||
void clear();
|
||||
InternedPtrMap(const InternedPtrMap&) = delete;
|
||||
InternedPtrMap& operator=(const InternedPtrMap&) = delete;
|
||||
InternedPtrMap() { clear(); }
|
||||
|
||||
T* lookup(InternedSymbolPtr str) {
|
||||
if (m_entries.size() < 10) {
|
||||
for (auto& e : m_entries) {
|
||||
if (e.key == str.name_ptr) {
|
||||
return &e.value;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
u32 hash = crc32((const u8*)&str.name_ptr, sizeof(const char*));
|
||||
|
||||
// probe
|
||||
for (u32 i = 0; i < m_entries.size(); i++) {
|
||||
u32 slot_addr = (hash + i) & m_mask;
|
||||
auto& slot = m_entries[slot_addr];
|
||||
if (!slot.key) {
|
||||
return nullptr;
|
||||
} else {
|
||||
if (slot.key != str.name_ptr) {
|
||||
continue; // bad hash
|
||||
}
|
||||
return &slot.value;
|
||||
}
|
||||
}
|
||||
|
||||
// should be impossible to reach.
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
void set(InternedSymbolPtr ptr, const T& obj) {
|
||||
u32 hash = crc32((const u8*)&ptr.name_ptr, sizeof(const char*));
|
||||
|
||||
// probe
|
||||
for (u32 i = 0; i < m_entries.size(); i++) {
|
||||
u32 slot_addr = (hash + i) & m_mask;
|
||||
auto& slot = m_entries[slot_addr];
|
||||
if (!slot.key) {
|
||||
// not found, insert!
|
||||
slot.key = ptr.name_ptr;
|
||||
slot.value = obj;
|
||||
m_used_entries++;
|
||||
|
||||
if (m_used_entries >= m_next_resize) {
|
||||
resize();
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (slot.key == ptr.name_ptr) {
|
||||
slot.value = obj;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// should be impossible to reach.
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
void clear() {
|
||||
m_entries.clear();
|
||||
m_power_of_two_size = 3; // 2 ^ 3 = 8
|
||||
m_entries.resize(8);
|
||||
m_used_entries = 0;
|
||||
m_next_resize = (m_entries.size() * kMaxUsed);
|
||||
m_mask = 0b111;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
const char* key = nullptr;
|
||||
Object value;
|
||||
T value;
|
||||
};
|
||||
std::vector<Entry> m_entries;
|
||||
|
||||
void resize();
|
||||
void resize() {
|
||||
m_power_of_two_size++;
|
||||
m_mask = (1U << m_power_of_two_size) - 1;
|
||||
|
||||
std::vector<Entry> new_entries(m_entries.size() * 2);
|
||||
for (const auto& old_entry : m_entries) {
|
||||
if (old_entry.key) {
|
||||
bool done = false;
|
||||
u32 hash = crc32((const u8*)&old_entry.key, sizeof(const char*));
|
||||
for (u32 i = 0; i < new_entries.size(); i++) {
|
||||
u32 slot_addr = (hash + i) & m_mask;
|
||||
auto& slot = new_entries[slot_addr];
|
||||
if (!slot.key) {
|
||||
slot.key = old_entry.key;
|
||||
slot.value = std::move(old_entry.value);
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(done);
|
||||
}
|
||||
}
|
||||
|
||||
m_entries = std::move(new_entries);
|
||||
m_next_resize = kMaxUsed * m_entries.size();
|
||||
}
|
||||
int m_power_of_two_size = 0;
|
||||
int m_used_entries = 0;
|
||||
int m_next_resize = 0;
|
||||
@@ -480,6 +569,8 @@ class EnvironmentMap {
|
||||
static constexpr float kMaxUsed = 0.7;
|
||||
};
|
||||
|
||||
using EnvironmentMap = InternedPtrMap<Object>;
|
||||
|
||||
class EnvironmentObject : public HeapObject {
|
||||
public:
|
||||
std::string name;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "Reader.h"
|
||||
|
||||
#include "common/log/log.h"
|
||||
#include "common/repl/util.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "common/util/FontUtils.h"
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#include "common/goos/Object.h"
|
||||
#include "common/goos/TextDB.h"
|
||||
#include "common/repl/util.h"
|
||||
#include "common/repl/repl_wrapper.h"
|
||||
#include "common/util/Assert.h"
|
||||
|
||||
namespace goos {
|
||||
|
||||
+4
-4
@@ -140,7 +140,7 @@ void printstd(const char* format, va_list arg_list) {
|
||||
internal::log_vprintf(format, arg_list);
|
||||
}
|
||||
|
||||
// how many extra log files for a single program should be kept?
|
||||
// how many extra log files for a single program should be kept
|
||||
constexpr int LOG_ROTATE_MAX = 10;
|
||||
|
||||
void set_file(const std::string& filename,
|
||||
@@ -163,7 +163,7 @@ void set_file(const std::string& filename,
|
||||
file_util::find_files_in_dir(fs::path(complete_filename).parent_path(),
|
||||
std::regex(fmt::format("{}\\.(\\d\\.)?log", filename)));
|
||||
for (const auto& file : old_log_files) {
|
||||
lg::info("removing {}", file.string());
|
||||
lg::debug("removing {}", file.string());
|
||||
fs::remove(file);
|
||||
}
|
||||
// remove the oldest log file if there are more than LOG_ROTATE_MAX
|
||||
@@ -172,9 +172,9 @@ void set_file(const std::string& filename,
|
||||
// sort the names and remove them
|
||||
existing_log_files = file_util::sort_filepaths(existing_log_files, true);
|
||||
if (existing_log_files.size() > (LOG_ROTATE_MAX - 1)) {
|
||||
lg::info("removing {} log files", existing_log_files.size() - (LOG_ROTATE_MAX - 1));
|
||||
lg::debug("removing {} log files", existing_log_files.size() - (LOG_ROTATE_MAX - 1));
|
||||
for (int i = 0; i < (int)existing_log_files.size() - (LOG_ROTATE_MAX - 1); i++) {
|
||||
lg::info("removing {}", existing_log_files.at(i).string());
|
||||
lg::debug("removing {}", existing_log_files.at(i).string());
|
||||
fs::remove(existing_log_files.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,15 +7,21 @@
|
||||
namespace REPL {
|
||||
void to_json(json& j, const Config& obj) {
|
||||
j = json{
|
||||
{"nreplPort", obj.nrepl_port},
|
||||
{"gameVersionFolder", obj.game_version_folder},
|
||||
{"numConnectToTargetAttempts", obj.target_connect_attempts},
|
||||
{"asmFileSearchDirs", obj.asm_file_search_dirs},
|
||||
{"keybinds", obj.keybinds},
|
||||
{"perGameHistory", obj.per_game_history},
|
||||
{"permissiveRedefinitions", obj.permissive_redefinitions},
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json& j, Config& obj) {
|
||||
// TODO - make a camelCase variant of json_serialize/deserialize macros
|
||||
if (j.contains("nreplPort")) {
|
||||
j.at("nreplPort").get_to(obj.nrepl_port);
|
||||
}
|
||||
if (j.contains("gameVersionFolder")) {
|
||||
j.at("gameVersionFolder").get_to(obj.game_version_folder);
|
||||
}
|
||||
@@ -55,6 +61,9 @@ void from_json(const json& j, Config& obj) {
|
||||
if (j.contains("perGameHistory")) {
|
||||
j.at("perGameHistory").get_to(obj.per_game_history);
|
||||
}
|
||||
if (j.contains("permissiveRedefinitions")) {
|
||||
j.at("permissiveRedefinitions").get_to(obj.permissive_redefinitions);
|
||||
}
|
||||
// if there is game specific configuration, override any values we just set
|
||||
if (j.contains(version_to_game_name(obj.game_version))) {
|
||||
from_json(j.at(version_to_game_name(obj.game_version)), obj);
|
||||
|
||||
@@ -26,11 +26,14 @@ struct KeyBind {
|
||||
void to_json(json& j, const KeyBind& obj);
|
||||
void from_json(const json& j, KeyBind& obj);
|
||||
|
||||
// TODO - per-game config
|
||||
struct Config {
|
||||
GameVersion game_version;
|
||||
Config(GameVersion _game_version) : game_version(_game_version){};
|
||||
|
||||
// this is the default REPL configuration
|
||||
int nrepl_port = 8181;
|
||||
int temp_nrepl_port = -1;
|
||||
std::string game_version_folder;
|
||||
int target_connect_attempts = 30;
|
||||
std::vector<std::string> asm_file_search_dirs = {};
|
||||
@@ -45,6 +48,14 @@ struct Config {
|
||||
{KeyBind::Modifier::CTRL, "B", "Displays the most recently caught backtrace", "(:di)"},
|
||||
{KeyBind::Modifier::CTRL, "N", "Full build of the game", "(mi)"}};
|
||||
bool per_game_history = true;
|
||||
bool permissive_redefinitions = false;
|
||||
|
||||
int get_nrepl_port() {
|
||||
if (temp_nrepl_port != -1) {
|
||||
return temp_nrepl_port;
|
||||
}
|
||||
return nrepl_port;
|
||||
}
|
||||
};
|
||||
void to_json(json& j, const Config& obj);
|
||||
void from_json(const json& j, Config& obj);
|
||||
|
||||
@@ -16,10 +16,6 @@
|
||||
#include "common/log/log.h"
|
||||
// clang-format on
|
||||
|
||||
// TODO - basically REPL to listen and inject commands into a running REPL
|
||||
// - we will need a C++ side client as well which will let us communicate with the repl via for
|
||||
// example, ImgUI
|
||||
//
|
||||
// TODO - The server also needs to eventually return the result of the evaluation
|
||||
|
||||
ReplServer::~ReplServer() {
|
||||
@@ -31,7 +27,18 @@ ReplServer::~ReplServer() {
|
||||
|
||||
void ReplServer::post_init() {
|
||||
// Add the listening socket to our set of sockets
|
||||
lg::info("[nREPL:{}:{}] awaiting connections", tcp_port, listening_socket);
|
||||
lg::debug("[nREPL:{}:{}] awaiting connections", tcp_port, listening_socket);
|
||||
}
|
||||
|
||||
void ReplServer::error_response(int socket, const std::string& error) {
|
||||
std::string msg = fmt::format("[ERROR]: {}", error);
|
||||
auto resp = write_to_socket(socket, msg.c_str(), msg.size());
|
||||
if (resp == -1) {
|
||||
lg::warn("[nREPL:{}] Client Disconnected: {}", tcp_port, address_to_string(addr),
|
||||
ntohs(addr.sin_port), socket);
|
||||
close_socket(socket);
|
||||
client_sockets.erase(socket);
|
||||
}
|
||||
}
|
||||
|
||||
void ReplServer::ping_response(int socket) {
|
||||
@@ -52,7 +59,6 @@ std::optional<std::string> ReplServer::get_msg() {
|
||||
|
||||
// Add the server's main listening socket (where we accept clients from)
|
||||
FD_SET(listening_socket, &read_sockets);
|
||||
|
||||
int max_sd = listening_socket;
|
||||
for (const int& sock : client_sockets) {
|
||||
if (sock > max_sd) {
|
||||
@@ -64,12 +70,11 @@ std::optional<std::string> ReplServer::get_msg() {
|
||||
}
|
||||
|
||||
// Wait for activity on _something_, with a timeout so we don't get stuck here on exit.
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 100000;
|
||||
struct timeval timeout = {0, 100000};
|
||||
auto activity = select(max_sd + 1, &read_sockets, NULL, NULL, &timeout);
|
||||
|
||||
if (activity < 0) { // TODO - || error!
|
||||
if (activity < 0 && errno != EINTR) {
|
||||
lg::error("[nREPL:{}] select error, returned: {}, errno: {}", tcp_port, activity,
|
||||
strerror(errno));
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -78,44 +83,46 @@ std::optional<std::string> ReplServer::get_msg() {
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
auto new_socket = accept_socket(listening_socket, (sockaddr*)&addr, &addr_len);
|
||||
if (new_socket < 0) {
|
||||
// TODO - handle error
|
||||
if (new_socket != -1) {
|
||||
lg::error("[nREPL:{}] accept error, returned: {}, errono: {}", tcp_port, new_socket,
|
||||
strerror(errno));
|
||||
}
|
||||
} else {
|
||||
lg::info("[nREPL:{}]: New socket connection: {}:{}:{}", tcp_port, address_to_string(addr),
|
||||
ntohs(addr.sin_port), new_socket);
|
||||
|
||||
// Say hello
|
||||
ping_response(new_socket);
|
||||
// Track the new socket
|
||||
if ((int)client_sockets.size() < max_clients) {
|
||||
client_sockets.insert(new_socket);
|
||||
} else {
|
||||
// TODO - Respond with NO
|
||||
// Respond with NO and close the socket
|
||||
lg::warn("[nREPL:{}]: Maximum clients reached. Rejecting connection.", tcp_port);
|
||||
error_response(new_socket, "Maximum clients reached. Rejecting connection.");
|
||||
close_socket(new_socket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise (and no matter what) check all the clients to see if they have sent us anything
|
||||
// else its some IO operation on some other socket
|
||||
//
|
||||
// RACE - the first client wins
|
||||
|
||||
// TODO - there are ways to do this with iterators but, couldn't figure it out!
|
||||
std::vector<int> sockets_to_scan(client_sockets.begin(), client_sockets.end());
|
||||
for (const int& sock : sockets_to_scan) {
|
||||
// Check all clients for activity
|
||||
for (auto it = client_sockets.begin(); it != client_sockets.end();) {
|
||||
int sock = *it;
|
||||
if (FD_ISSET(sock, &read_sockets)) {
|
||||
// Attempt to read a header
|
||||
// TODO - should this be in a loop?
|
||||
auto req_bytes = read_from_socket(sock, header_buffer.data(), header_buffer.size());
|
||||
if (req_bytes == 0) {
|
||||
// Socket disconnected
|
||||
if (req_bytes <= 0) {
|
||||
// TODO - add a queue of messages in the REPL::Wrapper so we can print _BEFORE_ the prompt
|
||||
// is output
|
||||
lg::warn("[nREPL:{}] Client Disconnected: {}", tcp_port, address_to_string(addr),
|
||||
ntohs(addr.sin_port), sock);
|
||||
|
||||
if (req_bytes == 0) {
|
||||
lg::warn("[nREPL:{}] Client Disconnected: {}", tcp_port, address_to_string(addr));
|
||||
} else {
|
||||
lg::warn("[nREPL:{}] Error reading from socket on {}: {}", tcp_port,
|
||||
address_to_string(addr), strerror(errno));
|
||||
}
|
||||
// Cleanup the socket and remove it from our set
|
||||
close_socket(sock);
|
||||
client_sockets.erase(sock);
|
||||
it = client_sockets.erase(it); // Erase and move to the next element
|
||||
continue;
|
||||
} else {
|
||||
// Otherwise, process the message
|
||||
auto* header = (ReplServerHeader*)(header_buffer.data());
|
||||
@@ -123,7 +130,12 @@ std::optional<std::string> ReplServer::get_msg() {
|
||||
int expected_size = header->length;
|
||||
int got = 0;
|
||||
int tries = 0;
|
||||
bool skip_to_next_socket = false;
|
||||
while (got < expected_size) {
|
||||
if (want_exit_callback()) {
|
||||
lg::warn("[nREPL:{}] Terminating nREPL early", tcp_port);
|
||||
return std::nullopt;
|
||||
}
|
||||
tries++;
|
||||
if (tries > 100) {
|
||||
break;
|
||||
@@ -135,11 +147,25 @@ std::optional<std::string> ReplServer::get_msg() {
|
||||
tcp_port, got, expected_size, buffer.size());
|
||||
return std::nullopt;
|
||||
}
|
||||
auto x = read_from_socket(sock, buffer.data() + got, expected_size - got);
|
||||
if (want_exit_callback()) {
|
||||
return std::nullopt;
|
||||
auto bytes_read = read_from_socket(sock, buffer.data() + got, expected_size - got);
|
||||
if (bytes_read <= 0) {
|
||||
if (bytes_read == 0) {
|
||||
lg::warn("[nREPL:{}] Client Disconnected: {}", tcp_port, address_to_string(addr));
|
||||
} else {
|
||||
lg::warn("[nREPL:{}] Error reading from socket on {}: {}", tcp_port,
|
||||
address_to_string(addr), strerror(errno));
|
||||
}
|
||||
close_socket(sock);
|
||||
it = client_sockets.erase(it); // Erase and move to the next element
|
||||
skip_to_next_socket = true;
|
||||
break;
|
||||
}
|
||||
got += x > 0 ? x : 0;
|
||||
got += bytes_read;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
if (skip_to_next_socket) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (header->type) {
|
||||
@@ -153,6 +179,7 @@ std::optional<std::string> ReplServer::get_msg() {
|
||||
}
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -27,5 +27,6 @@ class ReplServer : public XSocketServer {
|
||||
fd_set read_sockets;
|
||||
std::set<int> client_sockets = {};
|
||||
|
||||
void error_response(int socket, const std::string& error);
|
||||
void ping_response(int socket);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "util.h"
|
||||
#include "repl_wrapper.h"
|
||||
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "common/util/json_util.h"
|
||||
@@ -8,36 +8,66 @@
|
||||
#include "fmt/color.h"
|
||||
#include "fmt/core.h"
|
||||
#include "third-party/replxx/include/replxx.hxx"
|
||||
// TODO - expand a list of hints (ie. a hint for defun to show at a glance how to write a function,
|
||||
// or perhaps, show the docstring for the current function being used?)
|
||||
|
||||
namespace REPL {
|
||||
void Wrapper::clear_screen() {
|
||||
repl.clear_screen();
|
||||
}
|
||||
|
||||
void Wrapper::print_welcome_message() {
|
||||
// TODO - dont print on std-out
|
||||
// Welcome message / brief intro for documentation
|
||||
std::string ascii;
|
||||
ascii += " _____ _____ _____ _____ __ \n";
|
||||
ascii += "| |___ ___ ___| __| | _ | | \n";
|
||||
ascii += "| | | . | -_| | | | | | | |__ \n";
|
||||
ascii += "|_____| _|___|_|_|_____|_____|__|__|_____|\n";
|
||||
ascii += " |_| \n";
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::orange), ascii);
|
||||
|
||||
fmt::print("Welcome to OpenGOAL {}.{}!\n", versions::GOAL_VERSION_MAJOR,
|
||||
versions::GOAL_VERSION_MINOR);
|
||||
fmt::print("Run {} or {} for help with common commands and REPL usage.\n",
|
||||
fmt::styled("(repl-help)", fmt::emphasis::bold | fg(fmt::color::cyan)),
|
||||
fmt::styled("(repl-keybinds)", fmt::emphasis::bold | fg(fmt::color::cyan)));
|
||||
fmt::print("Run ");
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::cyan), "(lt)");
|
||||
fmt::print(" to connect to the local target.\n");
|
||||
fmt::print("Run ");
|
||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::cyan), "(mi)");
|
||||
fmt::print(" to rebuild the entire game.\n\n");
|
||||
void Wrapper::print_welcome_message(const std::vector<std::string>& loaded_projects) {
|
||||
std::string message;
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " ..:::::..\n");
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .:-----------:.\n");
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-----.");
|
||||
message += fmt::format(fmt::emphasis::bold, " Welcome to OpenGOAL {}.{} [{}]",
|
||||
versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR,
|
||||
fmt::format(fg(fmt::color::gray), "{}", build_revision()));
|
||||
if (!username.empty() && username != "#f" && username != "unknown") {
|
||||
message += fmt::format(fg(fmt::color::light_green), " {}", username);
|
||||
}
|
||||
message += "!\n";
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .---.");
|
||||
if (repl_config.game_version == GameVersion::Jak1) {
|
||||
message += fmt::format(" [{}]: ", fmt::format(fg(fmt::color::orange), "jak1"));
|
||||
} else if (repl_config.game_version == GameVersion::Jak2) {
|
||||
message += fmt::format(" [{}]: ", fmt::format(fg(fmt::color::purple), "jak2"));
|
||||
} else if (repl_config.game_version == GameVersion::Jak3) {
|
||||
message += fmt::format(" [{}]: ", fmt::format(fg(fmt::color::gold), "jak3"));
|
||||
} else {
|
||||
message += fmt::format(" [{}]: ", fmt::format(fg(fmt::color::magenta), "jakx"));
|
||||
}
|
||||
const auto loaded_projects_str = fmt::format("{}", fmt::join(loaded_projects, ","));
|
||||
message += fmt::format(fg(fmt::color::gray), "{}\n", loaded_projects_str);
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " . --- .");
|
||||
message +=
|
||||
fmt::format(" Project Path: {}\n",
|
||||
fmt::format(fg(fmt::color::gray), file_util::get_jak_project_dir().string()));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " - :===: -");
|
||||
message += " nREPL:";
|
||||
if (!nrepl_alive) {
|
||||
message += fmt::format(fg(fmt::color::red), "DISABLED\n");
|
||||
} else {
|
||||
message += fmt::format(fg(fmt::color::light_green), " Listening on {}\n",
|
||||
repl_config.get_nrepl_port());
|
||||
}
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " --. .--: :--. .--");
|
||||
message += " Source File Search Dirs: ";
|
||||
const auto search_dir_string =
|
||||
fmt::format("{}", fmt::join(repl_config.asm_file_search_dirs, ","));
|
||||
message += fmt::format("[{}]\n", fmt::format(fg(fmt::color::gray), search_dir_string));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .=======. =======.");
|
||||
message += fmt::format(" {} or {} for basic help and usage\n",
|
||||
fmt::format(fg(fmt::color::cyan), "(repl-help)"),
|
||||
fmt::format(fg(fmt::color::cyan), "(repl-keybinds)"));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-=====-. .-=====-");
|
||||
message +=
|
||||
fmt::format(" {} to connect to the game\n", fmt::format(fg(fmt::color::cyan), "(lt)"));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-===========-.");
|
||||
message += fmt::format(" {} to recompile the active project.\n",
|
||||
fmt::format(fg(fmt::color::cyan), "(mi)"));
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-===-.\n");
|
||||
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .\n");
|
||||
fmt::print("{}", message);
|
||||
}
|
||||
|
||||
void Wrapper::print_to_repl(const std::string& str) {
|
||||
@@ -242,20 +272,24 @@ StartupFile load_user_startup_file(const std::string& username, const GameVersio
|
||||
return startup_file;
|
||||
}
|
||||
|
||||
REPL::Config load_repl_config(const std::string& username, const GameVersion game_version) {
|
||||
REPL::Config load_repl_config(const std::string& username,
|
||||
const GameVersion game_version,
|
||||
const int nrepl_port) {
|
||||
auto repl_config_path =
|
||||
file_util::get_jak_project_dir() / "goal_src" / "user" / username / "repl-config.json";
|
||||
REPL::Config loaded_config(game_version);
|
||||
if (file_util::file_exists(repl_config_path.string())) {
|
||||
try {
|
||||
REPL::Config config(game_version);
|
||||
auto repl_config_data =
|
||||
parse_commented_json(file_util::read_text_file(repl_config_path), "repl-config.json");
|
||||
from_json(repl_config_data, config);
|
||||
return config;
|
||||
from_json(repl_config_data, loaded_config);
|
||||
loaded_config.temp_nrepl_port = nrepl_port;
|
||||
return loaded_config;
|
||||
} catch (std::exception& e) {
|
||||
REPL::Config config(game_version);
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
return REPL::Config(game_version);
|
||||
loaded_config.temp_nrepl_port = nrepl_port;
|
||||
return loaded_config;
|
||||
}
|
||||
} // namespace REPL
|
||||
@@ -17,18 +17,23 @@ struct StartupFile {
|
||||
};
|
||||
|
||||
class Wrapper {
|
||||
replxx::Replxx repl;
|
||||
|
||||
public:
|
||||
std::string username;
|
||||
Config repl_config;
|
||||
StartupFile startup_file;
|
||||
bool nrepl_alive = false;
|
||||
std::vector<std::string> examples{};
|
||||
std::vector<std::pair<std::string, replxx::Replxx::Color>> regex_colors{};
|
||||
|
||||
Wrapper(GameVersion version) : repl_config(version) {}
|
||||
Wrapper(const std::string& _username, const Config& config, const StartupFile& startup)
|
||||
: username(_username), repl_config(config), startup_file(startup) {}
|
||||
Wrapper(const std::string& _username,
|
||||
const Config& config,
|
||||
const StartupFile& startup,
|
||||
bool _nrepl_alive)
|
||||
: username(_username),
|
||||
repl_config(config),
|
||||
startup_file(startup),
|
||||
nrepl_alive(_nrepl_alive) {}
|
||||
replxx::Replxx& get_repl() { return repl; }
|
||||
void init_settings();
|
||||
void reload_startup_file();
|
||||
@@ -36,7 +41,7 @@ class Wrapper {
|
||||
// Functionality / Commands
|
||||
void clear_screen();
|
||||
void print_to_repl(const std::string& str);
|
||||
void print_welcome_message();
|
||||
void print_welcome_message(const std::vector<std::string>& loaded_projects);
|
||||
void set_history_max_size(size_t len);
|
||||
const char* readline(const std::string& prompt);
|
||||
void add_to_history(const std::string& line);
|
||||
@@ -47,11 +52,14 @@ class Wrapper {
|
||||
std::pair<std::string, bool> get_current_repl_token(std::string const& context);
|
||||
|
||||
private:
|
||||
replxx::Replxx repl;
|
||||
replxx::Replxx::key_press_handler_t commit_text_action(std::string text_to_commit);
|
||||
std::vector<REPL::KeyBind> keybindings = {};
|
||||
};
|
||||
|
||||
std::string find_repl_username();
|
||||
StartupFile load_user_startup_file(const std::string& username, const GameVersion game_version);
|
||||
REPL::Config load_repl_config(const std::string& username, const GameVersion game_version);
|
||||
REPL::Config load_repl_config(const std::string& username,
|
||||
const GameVersion game_version,
|
||||
const int nrepl_port);
|
||||
} // namespace REPL
|
||||
@@ -89,7 +89,9 @@ const std::unordered_map<std::string, u16> jak2_speaker_name_to_enum_val = {
|
||||
{"citizen-male", 31},
|
||||
{"citizen-female", 32},
|
||||
{"oracle", 33},
|
||||
{"precursor", 34}};
|
||||
{"precursor", 34},
|
||||
{"metalkor-before-consite", 35},
|
||||
{"metalkor-intro", 36}};
|
||||
|
||||
GameSubtitlePackage read_json_files_v2(const GameSubtitleDefinitionFile& file_info) {
|
||||
GameSubtitlePackage package;
|
||||
|
||||
@@ -42,7 +42,153 @@ std::vector<std::string> jak2_slots = {
|
||||
"cas-toxic-slime-scroll-dest",
|
||||
};
|
||||
|
||||
std::vector<std::string> jak3_slots = {};
|
||||
std::vector<std::string> jak3_slots = {
|
||||
"skull-gem-dest",
|
||||
"jakc-arm",
|
||||
"jakc-eyebrow",
|
||||
"jakc-face",
|
||||
"jakc-finger",
|
||||
"jakc-hair",
|
||||
"jakchires-arm",
|
||||
"jakchires-eye",
|
||||
"jakchires-eyebrow",
|
||||
"jakchires-eyelid",
|
||||
"jakchires-facelft",
|
||||
"jakchires-facert",
|
||||
"jakchires-hair",
|
||||
// default-water
|
||||
"bomb-gradient",
|
||||
"blue-beam-dest",
|
||||
"lightjak-wings",
|
||||
"mushroom-dest",
|
||||
// default-warp
|
||||
"shield-env-rim-dest",
|
||||
// templea-water
|
||||
"templea-waterfall-dest",
|
||||
// templea-warp
|
||||
"holograph-env-rim-dest",
|
||||
// hanga-sprite
|
||||
"glider-ring-dest2",
|
||||
"glider-ring-dest",
|
||||
// foresta-water
|
||||
"fora-water-dest",
|
||||
"fora-waterfall-01-dest",
|
||||
"fora-water-wave-01-dest",
|
||||
// forestb-water
|
||||
"forb-water-dest",
|
||||
"forb-waterfall-01-dest",
|
||||
"forb-water-wave-01-dest",
|
||||
// lforplnt-pris
|
||||
"mh-gem-dest",
|
||||
// lmhcitya-tfrag
|
||||
"mhcitya-base-goo-01-dest",
|
||||
// lmhcityb-tfrag
|
||||
"mhcityb-base-goo-01-dest",
|
||||
// mhcitya-pris
|
||||
// "mhcity-de-door-skin-01-dest",
|
||||
// templec-water
|
||||
"tplc-water-dest",
|
||||
// sewc-water
|
||||
"sewer-water-01-c-dest",
|
||||
"sewer-waterfall-01-c-dest",
|
||||
"sewer-waterfall-02-c-dest",
|
||||
"sewer-water-wave-01-c-dest",
|
||||
"sewer-water-highlight-01-c-dest",
|
||||
// sewd-water
|
||||
"sewer-water-01-d-dest",
|
||||
"sewer-waterfall-02-d-dest",
|
||||
"sewer-water-highlight-01-d-dest",
|
||||
"sewer-water-wave-01-d-dest",
|
||||
"sewer-water-wave-02-d-dest",
|
||||
"sewer-water-still-01-d-dest",
|
||||
// sewe-water
|
||||
"sewer-water-01-e-dest",
|
||||
"sewer-waterfall-01-e-dest",
|
||||
"sewer-waterfall-02-e-dest",
|
||||
"sewer-water-highlight-01-e-dest",
|
||||
// sewg-water
|
||||
"sewer-water-01-g-dest",
|
||||
"sewer-waterfall-02-g-dest",
|
||||
"sewer-water-wave-01-g-dest",
|
||||
// sewh-water
|
||||
"sewer-water-01-h-dest",
|
||||
"sewer-waterfall-02-h-dest",
|
||||
"sewer-water-wave-02-h-dest",
|
||||
"sewer-watefall-froth-01-h-dest",
|
||||
// sewi-water
|
||||
"sewer-water-still-01-i-dest",
|
||||
"sewer-waterfall-02-i-dest",
|
||||
"sewer-water-wave-01-i-dest",
|
||||
// sewj-water
|
||||
"sewer-waterfall-02-j-dest",
|
||||
"sewer-watefall-froth-01-j-dest",
|
||||
// sewl-water
|
||||
"sewer-waterfall-02-l-dest",
|
||||
"sewer-watefall-froth-01-l-dest",
|
||||
// sewm-water
|
||||
"sewer-water-01-m-dest",
|
||||
"sewer-waterfall-01-m-dest",
|
||||
"sewer-waterfall-02-m-dest",
|
||||
"sewer-water-highlight-01-m-dest",
|
||||
"sewer-water-wave-01-m-dest",
|
||||
"sewer-water-still-01-m-dest",
|
||||
"sewer-watefall-froth-01-m-dest",
|
||||
// sewn-water
|
||||
"sewer-waterfall-01-n-dest",
|
||||
"sewer-waterfall-02-n-dest",
|
||||
// "sewer-water-highlight-01-n-dest",
|
||||
"sewer-water-wave-01-n-dest",
|
||||
"sewer-water-still-01-n-dest",
|
||||
// hanga-water
|
||||
// "des-thermal-01-dest",
|
||||
// desresc-warp
|
||||
"sat-shield-dest",
|
||||
// security
|
||||
"security-env-dest",
|
||||
"security-dot-dest",
|
||||
// lgunnorm-water
|
||||
"kg-target-c-forcefield-01-dest",
|
||||
// templex-water
|
||||
"temple-waterfall-dest",
|
||||
// desertd-water
|
||||
"des-waterfall-dest",
|
||||
// towerb-water
|
||||
"tow-energy-bridge-dest",
|
||||
// factoryb-water
|
||||
"hemi-gradient-dest",
|
||||
"hemi-gradient-flames-dest",
|
||||
// factoryc-alpha
|
||||
"facc-convey-dest",
|
||||
"facc-convey-02-dest",
|
||||
// waspal-water
|
||||
"waspala-water-dest",
|
||||
"waspala-waterfall-dest",
|
||||
// rubblea-water
|
||||
"rub-water-dest",
|
||||
// rubblea2-water
|
||||
"rub-water-desta2",
|
||||
// rubbleb-water
|
||||
"rub-water-destb",
|
||||
// rubblec-water
|
||||
"rub-water-destc",
|
||||
// nstb-quicksand
|
||||
"nstb-quicksand-dest",
|
||||
// ctyslumb-water
|
||||
"ctyslumb-water-dest",
|
||||
"ctyslumb-fountain-fall-dest",
|
||||
// ctyslumc-water
|
||||
"ctyslumc-water-dest",
|
||||
"ctyslumc-fountain-fall-dest",
|
||||
// mined-tfrag
|
||||
"mined-pillar-side-dest",
|
||||
"mined-pillar-top2side-dest",
|
||||
"mined-pillar-top-dest",
|
||||
// volcanoa-alpha
|
||||
"vola-lava-01-dest",
|
||||
"vola-lava-fall-dest",
|
||||
// wasstada-alpha
|
||||
"wstd-lava-base-dest",
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@@ -28,8 +28,12 @@ struct MethodInfo {
|
||||
std::string name;
|
||||
TypeSpec type;
|
||||
std::string defined_in_type;
|
||||
// TODO - this might be redundant, but preventing an unknown breaking change, clean it up later
|
||||
std::string type_name;
|
||||
bool no_virtual = false;
|
||||
// TODO - this is no longer used anymore...but was not removed from th4e struct?
|
||||
bool overrides_parent = false;
|
||||
// TODO - this is no longer used anymore...but was not removed from th4e struct?
|
||||
bool only_overrides_docstring = false;
|
||||
std::optional<std::string> docstring;
|
||||
std::optional<std::string> overlay_name;
|
||||
|
||||
@@ -124,10 +124,12 @@ class TypeSpec {
|
||||
ASSERT(m_arguments);
|
||||
return m_arguments->at(idx);
|
||||
}
|
||||
|
||||
TypeSpec& get_arg(int idx) {
|
||||
ASSERT(m_arguments);
|
||||
return m_arguments->at(idx);
|
||||
}
|
||||
|
||||
const TypeSpec& last_arg() const {
|
||||
ASSERT(m_arguments);
|
||||
ASSERT(!m_arguments->empty());
|
||||
|
||||
@@ -548,6 +548,7 @@ MethodInfo TypeSystem::override_method(Type* type,
|
||||
existing_info.name,
|
||||
existing_info.type,
|
||||
type->get_name(),
|
||||
type->get_name(),
|
||||
existing_info.no_virtual,
|
||||
false,
|
||||
true,
|
||||
@@ -607,6 +608,7 @@ MethodInfo TypeSystem::declare_method(Type* type,
|
||||
method_name,
|
||||
ts,
|
||||
type->get_name(),
|
||||
type->get_name(),
|
||||
no_virtual,
|
||||
true,
|
||||
false,
|
||||
@@ -645,6 +647,7 @@ MethodInfo TypeSystem::declare_method(Type* type,
|
||||
method_name,
|
||||
ts,
|
||||
type->get_name(),
|
||||
type->get_name(),
|
||||
no_virtual,
|
||||
false,
|
||||
false,
|
||||
@@ -678,8 +681,8 @@ MethodInfo TypeSystem::overlay_method(Type* type,
|
||||
}
|
||||
|
||||
// use the existing ID.
|
||||
return type->add_method({existing_info.id, method_name, ts, type->get_name(), false, true, false,
|
||||
docstring, std::make_optional(method_overlay_name)});
|
||||
return type->add_method({existing_info.id, method_name, ts, type->get_name(), type->get_name(),
|
||||
false, true, false, docstring, std::make_optional(method_overlay_name)});
|
||||
}
|
||||
|
||||
MethodInfo TypeSystem::define_method(const std::string& type_name,
|
||||
@@ -709,8 +712,10 @@ MethodInfo TypeSystem::define_method(Type* type,
|
||||
// look up the method
|
||||
MethodInfo existing_info;
|
||||
bool got_existing = try_lookup_method(type, method_name, &existing_info);
|
||||
|
||||
if (got_existing) {
|
||||
// The lookup will return a parents method, but the type should be equal
|
||||
// to the type in question (it's a child)
|
||||
existing_info.type_name = type->get_name();
|
||||
// Update the docstring
|
||||
existing_info.docstring = docstring;
|
||||
int bad_arg_idx = -99;
|
||||
@@ -758,7 +763,7 @@ MethodInfo TypeSystem::add_new_method(Type* type,
|
||||
return existing;
|
||||
} else {
|
||||
return type->add_new_method(
|
||||
{0, "new", ts, type->get_name(), false, false, false, docstring, {}});
|
||||
{0, "new", ts, type->get_name(), type->get_name(), false, false, false, docstring, {}});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,10 +58,11 @@ EnumType* parse_defenum(const goos::Object& defenum,
|
||||
auto& enum_name_obj = car(iter);
|
||||
iter = cdr(iter);
|
||||
// check for docstring
|
||||
std::optional<std::string> maybe_docstring;
|
||||
if (iter->is_pair() && car(iter).is_string()) {
|
||||
// TODO - docstring - store and use docstring if coming from the compiler
|
||||
if (symbol_metadata) {
|
||||
symbol_metadata->docstring = str_util::trim_newline_indents(car(iter).as_string()->data);
|
||||
maybe_docstring = str_util::trim_newline_indents(car(iter).as_string()->data);
|
||||
symbol_metadata->docstring = maybe_docstring.value();
|
||||
}
|
||||
iter = cdr(iter);
|
||||
}
|
||||
@@ -157,6 +158,7 @@ EnumType* parse_defenum(const goos::Object& defenum,
|
||||
if (is_type("integer", base_type, ts)) {
|
||||
auto parent = ts->get_type_of_type<ValueType>(base_type.base_type());
|
||||
auto new_type = std::make_unique<EnumType>(parent, name, is_bitfield, entries);
|
||||
new_type->m_metadata.docstring = maybe_docstring;
|
||||
new_type->set_runtime_type(parent->get_runtime_name());
|
||||
return dynamic_cast<EnumType*>(ts->add_type(name, std::move(new_type)));
|
||||
} else {
|
||||
|
||||
@@ -84,12 +84,10 @@ double get_float(const goos::Object& obj) {
|
||||
throw std::runtime_error(obj.print() + " was supposed to be an number, but isn't");
|
||||
}
|
||||
|
||||
void add_field(
|
||||
StructureType* structure,
|
||||
TypeSystem* ts,
|
||||
const goos::Object& def,
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>&
|
||||
constants) {
|
||||
void add_field(StructureType* structure,
|
||||
TypeSystem* ts,
|
||||
const goos::Object& def,
|
||||
goos::EnvironmentMap* constants) {
|
||||
auto rest = &def;
|
||||
|
||||
auto name = symbol_string(car(rest));
|
||||
@@ -113,9 +111,8 @@ void add_field(
|
||||
if (car(rest).is_int()) {
|
||||
array_size = car(rest).integer_obj.value;
|
||||
rest = cdr(rest);
|
||||
} else if (car(rest).is_symbol() &&
|
||||
constants.find((car(rest)).as_symbol()) != constants.end()) {
|
||||
array_size = get_int(constants[(car(rest)).as_symbol()]);
|
||||
} else if (car(rest).is_symbol() && constants && constants->lookup((car(rest)).as_symbol())) {
|
||||
array_size = get_int(*constants->lookup((car(rest)).as_symbol()));
|
||||
rest = cdr(rest);
|
||||
}
|
||||
|
||||
@@ -543,13 +540,11 @@ void declare_state(Type* type,
|
||||
});
|
||||
}
|
||||
|
||||
StructureDefResult parse_structure_def(
|
||||
StructureType* type,
|
||||
TypeSystem* ts,
|
||||
const goos::Object& fields,
|
||||
const goos::Object& options,
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>&
|
||||
constants) {
|
||||
StructureDefResult parse_structure_def(StructureType* type,
|
||||
TypeSystem* ts,
|
||||
const goos::Object& fields,
|
||||
const goos::Object& options,
|
||||
goos::EnvironmentMap* constants) {
|
||||
StructureDefResult result;
|
||||
for_each_in_list(fields, [&](const goos::Object& o) { add_field(type, ts, o, constants); });
|
||||
TypeFlags flags;
|
||||
@@ -811,18 +806,11 @@ TypeSpec parse_typespec(const TypeSystem* type_system, const goos::Object& src)
|
||||
return {};
|
||||
}
|
||||
|
||||
DeftypeResult parse_deftype(
|
||||
const goos::Object& deftype,
|
||||
TypeSystem* ts,
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>*
|
||||
constants) {
|
||||
DeftypeResult parse_deftype(const goos::Object& deftype,
|
||||
TypeSystem* ts,
|
||||
goos::EnvironmentMap* constants) {
|
||||
DefinitionMetadata symbol_metadata;
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>
|
||||
no_consts;
|
||||
auto& constants_to_use = no_consts;
|
||||
if (constants != nullptr) {
|
||||
constants_to_use = *constants;
|
||||
}
|
||||
goos::EnvironmentMap no_consts;
|
||||
|
||||
auto iter = &deftype;
|
||||
|
||||
@@ -861,8 +849,7 @@ DeftypeResult parse_deftype(
|
||||
}
|
||||
new_type->inherit(pto);
|
||||
ts->forward_declare_type_as(name, pto->get_name());
|
||||
auto sr =
|
||||
parse_structure_def(new_type.get(), ts, field_list_obj, options_obj, constants_to_use);
|
||||
auto sr = parse_structure_def(new_type.get(), ts, field_list_obj, options_obj, constants);
|
||||
result.flags = sr.flags;
|
||||
result.create_runtime_type = sr.generate_runtime_type;
|
||||
structure_result = sr;
|
||||
@@ -891,8 +878,7 @@ DeftypeResult parse_deftype(
|
||||
ASSERT(pto);
|
||||
new_type->inherit(pto);
|
||||
ts->forward_declare_type_as(name, pto->get_name());
|
||||
auto sr =
|
||||
parse_structure_def(new_type.get(), ts, field_list_obj, options_obj, constants_to_use);
|
||||
auto sr = parse_structure_def(new_type.get(), ts, field_list_obj, options_obj, constants);
|
||||
result.flags = sr.flags;
|
||||
result.create_runtime_type = sr.generate_runtime_type;
|
||||
structure_result = sr;
|
||||
|
||||
@@ -17,9 +17,7 @@ struct DeftypeResult {
|
||||
bool create_runtime_type = true;
|
||||
};
|
||||
|
||||
DeftypeResult parse_deftype(
|
||||
const goos::Object& deftype,
|
||||
TypeSystem* ts,
|
||||
std::unordered_map<goos::InternedSymbolPtr, goos::Object, goos::InternedSymbolPtr::hash>*
|
||||
constants = nullptr);
|
||||
DeftypeResult parse_deftype(const goos::Object& deftype,
|
||||
TypeSystem* ts,
|
||||
goos::EnvironmentMap* constants = nullptr);
|
||||
TypeSpec parse_typespec(const TypeSystem* type_system, const goos::Object& src);
|
||||
@@ -36,6 +36,9 @@
|
||||
|
||||
#define ASSERT_NOT_REACHED_MSG(STR) \
|
||||
(void)((private_assert_failed("not reached", __FILE__, __LINE__, __PRETTY_FUNCTION__, STR), 0))
|
||||
|
||||
#define ASSERT_EQ_IMM(EXPR, EXPECTED) \
|
||||
ASSERT_MSG((EXPR) == (EXPECTED), fmt::format("result was {}, expected {}", (EXPR), (EXPECTED)))
|
||||
#else
|
||||
|
||||
#define ASSERT(EX) ((void)0)
|
||||
|
||||
+93
-25
@@ -57,6 +57,14 @@ fs::path get_user_home_dir() {
|
||||
#endif
|
||||
}
|
||||
|
||||
struct {
|
||||
bool initialized = false;
|
||||
fs::path path_to_data_folder;
|
||||
fs::path user_config_dir_override = "";
|
||||
// by default - if the config dir is overridden, we don't use the default save location
|
||||
bool use_overridden_config_dir_for_saves = true;
|
||||
} g_file_path_info;
|
||||
|
||||
fs::path get_user_config_dir() {
|
||||
fs::path config_base_path;
|
||||
#ifdef _WIN32
|
||||
@@ -80,35 +88,53 @@ fs::path get_user_config_dir() {
|
||||
|
||||
fs::path get_user_settings_dir(GameVersion game_version) {
|
||||
auto game_version_name = game_version_names[game_version];
|
||||
return get_user_config_dir() / game_version_name / "settings";
|
||||
auto config_dir = get_user_config_dir();
|
||||
if (!g_file_path_info.user_config_dir_override.empty()) {
|
||||
config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL";
|
||||
}
|
||||
return config_dir / game_version_name / "settings";
|
||||
}
|
||||
|
||||
fs::path get_user_memcard_dir(GameVersion game_version) {
|
||||
auto game_version_name = game_version_names[game_version];
|
||||
return get_user_config_dir() / game_version_name / "saves";
|
||||
auto config_dir = get_user_config_dir();
|
||||
if (!g_file_path_info.user_config_dir_override.empty() &&
|
||||
g_file_path_info.use_overridden_config_dir_for_saves) {
|
||||
config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL";
|
||||
}
|
||||
return config_dir / game_version_name / "saves";
|
||||
}
|
||||
|
||||
fs::path get_user_screenshots_dir(GameVersion game_version) {
|
||||
auto game_version_name = game_version_names[game_version];
|
||||
return get_user_config_dir() / game_version_name / "screenshots";
|
||||
auto config_dir = get_user_config_dir();
|
||||
if (!g_file_path_info.user_config_dir_override.empty()) {
|
||||
config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL";
|
||||
}
|
||||
return config_dir / game_version_name / "screenshots";
|
||||
}
|
||||
|
||||
fs::path get_user_misc_dir(GameVersion game_version) {
|
||||
auto game_version_name = game_version_names[game_version];
|
||||
return get_user_config_dir() / game_version_name / "misc";
|
||||
auto config_dir = get_user_config_dir();
|
||||
if (!g_file_path_info.user_config_dir_override.empty()) {
|
||||
config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL";
|
||||
}
|
||||
return config_dir / game_version_name / "misc";
|
||||
}
|
||||
|
||||
fs::path get_user_features_dir(GameVersion game_version) {
|
||||
auto game_version_name = game_version_names[game_version];
|
||||
auto path = get_user_config_dir() / game_version_name / "features";
|
||||
auto config_dir = get_user_config_dir();
|
||||
if (!g_file_path_info.user_config_dir_override.empty()) {
|
||||
config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL";
|
||||
}
|
||||
auto path = config_dir / game_version_name / "features";
|
||||
file_util::create_dir_if_needed(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
struct {
|
||||
bool initialized = false;
|
||||
fs::path path_to_data;
|
||||
} gFilePathInfo;
|
||||
fs::path g_iso_data_directory = "";
|
||||
|
||||
/*!
|
||||
* Get the path to the current executable.
|
||||
@@ -159,9 +185,11 @@ std::optional<std::string> try_get_jak_project_path() {
|
||||
return try_get_project_path_from_path(get_current_executable_path());
|
||||
}
|
||||
|
||||
std::optional<fs::path> try_get_data_dir() {
|
||||
std::optional<fs::path> try_get_data_dir(bool skip_logs) {
|
||||
fs::path my_path = get_current_executable_path();
|
||||
lg::info("Current executable directory - {}", my_path.string());
|
||||
if (!skip_logs) {
|
||||
lg::debug("Current executable directory - {}", my_path.string());
|
||||
}
|
||||
auto data_dir = my_path.parent_path() / "data";
|
||||
if (fs::exists(data_dir) && fs::is_directory(data_dir)) {
|
||||
return std::make_optional(data_dir);
|
||||
@@ -170,31 +198,38 @@ std::optional<fs::path> try_get_data_dir() {
|
||||
}
|
||||
}
|
||||
|
||||
bool setup_project_path(std::optional<fs::path> project_path_override) {
|
||||
if (gFilePathInfo.initialized) {
|
||||
bool setup_project_path(std::optional<fs::path> project_path_override, bool skip_logs) {
|
||||
if (g_file_path_info.initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (project_path_override) {
|
||||
gFilePathInfo.path_to_data = fs::absolute(project_path_override.value());
|
||||
gFilePathInfo.initialized = true;
|
||||
lg::info("Using explicitly set project path: {}", gFilePathInfo.path_to_data.string());
|
||||
g_file_path_info.path_to_data_folder = fs::absolute(project_path_override.value());
|
||||
g_file_path_info.initialized = true;
|
||||
if (!skip_logs) {
|
||||
lg::debug("Using explicitly set project path: {}",
|
||||
g_file_path_info.path_to_data_folder.string());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
auto data_path = try_get_data_dir();
|
||||
auto data_path = try_get_data_dir(skip_logs);
|
||||
if (data_path) {
|
||||
gFilePathInfo.path_to_data = *data_path;
|
||||
gFilePathInfo.initialized = true;
|
||||
lg::info("Using data path: {}", data_path->string());
|
||||
g_file_path_info.path_to_data_folder = *data_path;
|
||||
g_file_path_info.initialized = true;
|
||||
if (!skip_logs) {
|
||||
lg::debug("Using data path: {}", data_path->string());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
auto development_repo_path = try_get_jak_project_path();
|
||||
if (development_repo_path) {
|
||||
gFilePathInfo.path_to_data = *development_repo_path;
|
||||
gFilePathInfo.initialized = true;
|
||||
lg::info("Using development repo path: {}", *development_repo_path);
|
||||
g_file_path_info.path_to_data_folder = *development_repo_path;
|
||||
g_file_path_info.initialized = true;
|
||||
if (!skip_logs) {
|
||||
lg::debug("Using development repo path: {}", *development_repo_path);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -202,9 +237,37 @@ bool setup_project_path(std::optional<fs::path> project_path_override) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void override_user_config_dir(fs::path user_config_dir_override,
|
||||
bool use_overridden_config_dir_for_saves) {
|
||||
g_file_path_info.user_config_dir_override = user_config_dir_override;
|
||||
g_file_path_info.use_overridden_config_dir_for_saves = use_overridden_config_dir_for_saves;
|
||||
}
|
||||
|
||||
fs::path get_jak_project_dir() {
|
||||
ASSERT(gFilePathInfo.initialized);
|
||||
return gFilePathInfo.path_to_data;
|
||||
ASSERT(g_file_path_info.initialized);
|
||||
return g_file_path_info.path_to_data_folder;
|
||||
}
|
||||
|
||||
fs::path get_iso_dir_for_game(GameVersion game_version) {
|
||||
if (!g_iso_data_directory.empty()) {
|
||||
return g_iso_data_directory;
|
||||
}
|
||||
// Find the location based on the game version
|
||||
std::string expected_subdir = "jak1";
|
||||
if (game_version == GameVersion::Jak2) {
|
||||
expected_subdir = "jak2";
|
||||
} else if (game_version == GameVersion::Jak3) {
|
||||
expected_subdir = "jak3";
|
||||
}
|
||||
const auto temp_dir = get_jak_project_dir() / "iso_data" / expected_subdir;
|
||||
if (fs::exists(temp_dir)) {
|
||||
g_iso_data_directory = temp_dir;
|
||||
}
|
||||
return g_iso_data_directory;
|
||||
}
|
||||
|
||||
void set_iso_data_dir(const fs::path& directory) {
|
||||
g_iso_data_directory = directory;
|
||||
}
|
||||
|
||||
std::string get_file_path(const std::vector<std::string>& input) {
|
||||
@@ -757,4 +820,9 @@ std::pair<int, std::string> get_majority_file_line_endings_and_count(
|
||||
return {lf_count + crlf_count, "\n"};
|
||||
}
|
||||
|
||||
bool is_dir_in_dir(const fs::path& parent, const fs::path& child) {
|
||||
// Check if the parent path is a prefix of the child path
|
||||
return child.has_parent_path() && child.parent_path().lexically_relative(parent) == fs::path(".");
|
||||
}
|
||||
|
||||
} // namespace file_util
|
||||
@@ -35,12 +35,17 @@ fs::path get_user_screenshots_dir(GameVersion game_version);
|
||||
fs::path get_user_misc_dir(GameVersion game_version);
|
||||
fs::path get_user_features_dir(GameVersion game_version);
|
||||
fs::path get_jak_project_dir();
|
||||
fs::path get_iso_dir_for_game(GameVersion game_version);
|
||||
void set_iso_data_dir(const fs::path& directory);
|
||||
|
||||
bool create_dir_if_needed(const fs::path& path);
|
||||
bool create_dir_if_needed_for_file(const std::string& path);
|
||||
bool create_dir_if_needed_for_file(const fs::path& path);
|
||||
std::string get_current_executable_path();
|
||||
std::optional<std::string> try_get_project_path_from_path(const std::string& path);
|
||||
bool setup_project_path(std::optional<fs::path> project_path_override);
|
||||
bool setup_project_path(std::optional<fs::path> project_path_override, bool skip_logs = false);
|
||||
void override_user_config_dir(fs::path user_config_dir_override,
|
||||
bool use_overridden_config_dir_for_saves);
|
||||
std::string get_file_path(const std::vector<std::string>& path);
|
||||
void write_binary_file(const std::string& name, const void* data, size_t size);
|
||||
void write_binary_file(const fs::path& name, const void* data, size_t size);
|
||||
@@ -74,4 +79,5 @@ std::string make_screenshot_filepath(const GameVersion game_version, const std::
|
||||
std::string get_majority_file_line_endings(const std::string& file_contents);
|
||||
std::pair<int, std::string> get_majority_file_line_endings_and_count(
|
||||
const std::string& file_contents);
|
||||
bool is_dir_in_dir(const fs::path& parent, const fs::path& child);
|
||||
} // namespace file_util
|
||||
@@ -985,6 +985,8 @@ static std::vector<ReplaceInfo> s_replace_info_jak2 = {
|
||||
{"o~Y~-26H~-4V'~Z", "ó"},
|
||||
{"U~Y~-24H~-3V'~Z", "Ú"},
|
||||
{"u~Y~-24H~-3V'~Z", "ú"},
|
||||
{"Z~Y~-24H~-3V'~Z", "Ź"},
|
||||
{"z~Y~-24H~-3V'~Z", "ź"},
|
||||
|
||||
// circumflex
|
||||
{"A~Y~-20H~-4V^~Z", "Â"},
|
||||
@@ -1015,6 +1017,7 @@ static std::vector<ReplaceInfo> s_replace_info_jak2 = {
|
||||
{"a~Y~-25H~-5V¨~Z", "ä"},
|
||||
{"E~Y~-20H~-5V¨~Z", "Ë"},
|
||||
{"I~Y~-19H~-5V¨~Z", "Ï"},
|
||||
{"i~Y~-26H~-4V¨~Z", "ï"},
|
||||
{"O~Y~-26H~-8V¨~Z", "Ö"},
|
||||
{"o~Y~-26H~-4V¨~Z", "ö"},
|
||||
{"U~Y~-25H~-8V¨~Z", "Ü"},
|
||||
|
||||
@@ -46,4 +46,17 @@ std::vector<u8> decompress_zstd(const void* data, size_t size) {
|
||||
ASSERT(decomp_size == decompressed_size);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<u8> compress_zstd_no_header(const void* data, size_t size) {
|
||||
size_t max_compressed = ZSTD_compressBound(size);
|
||||
std::vector<u8> result(max_compressed);
|
||||
|
||||
size_t compressed_size = ZSTD_compress(result.data(), max_compressed, data, size, 1);
|
||||
if (ZSTD_isError(compressed_size)) {
|
||||
ASSERT_MSG(false, fmt::format("ZSTD error: {}", ZSTD_getErrorName(compressed_size)));
|
||||
}
|
||||
|
||||
result.resize(compressed_size);
|
||||
return result;
|
||||
}
|
||||
} // namespace compression
|
||||
@@ -8,4 +8,5 @@ namespace compression {
|
||||
// compress and decompress data with zstd
|
||||
std::vector<u8> compress_zstd(const void* data, size_t size);
|
||||
std::vector<u8> decompress_zstd(const void* data, size_t size);
|
||||
} // namespace compression
|
||||
std::vector<u8> compress_zstd_no_header(const void* data, size_t size);
|
||||
} // namespace compression
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
inline u64 fnv64(const void* data, u64 len) {
|
||||
u64 ret = 0xcbf29ce484222325;
|
||||
const auto* ptr = (const u8*)data;
|
||||
for (u64 i = 0; i < len; i++) {
|
||||
ret = 1099511628211 * (((u64)*ptr) ^ ret);
|
||||
ptr++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline u64 fnv64(const std::string& str) {
|
||||
return fnv64(str.data(), str.length());
|
||||
}
|
||||
@@ -0,0 +1,467 @@
|
||||
#include "gltf_util.h"
|
||||
|
||||
#include "common/log/log.h"
|
||||
|
||||
namespace gltf_util {
|
||||
|
||||
/*!
|
||||
* Convert a GLTF position buffer or similar to std::vector<Vec3f>
|
||||
*/
|
||||
std::vector<math::Vector3f> extract_vec3f(const u8* data, u32 count, u32 stride) {
|
||||
std::vector<math::Vector3f> result;
|
||||
result.reserve(count);
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
memcpy(&result.emplace_back(), data, sizeof(math::Vector3f));
|
||||
data += stride;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<math::Vector2f> extract_vec2f(const u8* data, u32 count, u32 stride) {
|
||||
std::vector<math::Vector2f> result;
|
||||
result.reserve(count);
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
memcpy(&result.emplace_back(), data, sizeof(math::Vector2f));
|
||||
data += stride;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Convert a GLTF color buffer (float format) to u8 colors.
|
||||
*/
|
||||
std::vector<math::Vector<u8, 4>> extract_color_from_vec4_float(const u8* data,
|
||||
u32 count,
|
||||
u32 stride) {
|
||||
std::vector<math::Vector<u8, 4>> result;
|
||||
result.reserve(count);
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
math::Vector<float, 4> temp;
|
||||
memcpy(&temp, data, sizeof(math::Vector<float, 4>));
|
||||
data += stride;
|
||||
result.emplace_back(temp.x() * 255, temp.y() * 255, temp.z() * 255, temp.w() * 255);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Convert a GLTF color buffer (u16 format) to u8 colors.
|
||||
*/
|
||||
std::vector<math::Vector<u8, 4>> extract_color_from_vec4_u16(const u8* data,
|
||||
u32 count,
|
||||
u32 stride) {
|
||||
std::vector<math::Vector<u8, 4>> result;
|
||||
result.reserve(count);
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
math::Vector<u16, 4> temp;
|
||||
memcpy(&temp, data, sizeof(math::Vector<u16, 4>));
|
||||
data += stride;
|
||||
result.emplace_back(temp.x() >> 8, temp.y() >> 8, temp.z() >> 8, temp.w() >> 8);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Convert a GLTF index buffer
|
||||
*/
|
||||
std::vector<u32> gltf_index_buffer(const tinygltf::Model& model,
|
||||
int indices_idx,
|
||||
u32 index_offset) {
|
||||
const auto& indices_accessor = model.accessors[indices_idx];
|
||||
const auto& buffer_view = model.bufferViews[indices_accessor.bufferView];
|
||||
const auto& buffer = model.buffers[buffer_view.buffer];
|
||||
const auto data_ptr = buffer.data.data() + buffer_view.byteOffset + indices_accessor.byteOffset;
|
||||
const auto stride = indices_accessor.ByteStride(buffer_view);
|
||||
const auto count = indices_accessor.count;
|
||||
|
||||
switch (indices_accessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_BYTE:
|
||||
return index_list_to_u32<s8>(data_ptr, count, index_offset, stride);
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
|
||||
return index_list_to_u32<u8>(data_ptr, count, index_offset, stride);
|
||||
case TINYGLTF_COMPONENT_TYPE_SHORT:
|
||||
return index_list_to_u32<s16>(data_ptr, count, index_offset, stride);
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
return index_list_to_u32<u16>(data_ptr, count, index_offset, stride);
|
||||
case TINYGLTF_COMPONENT_TYPE_INT:
|
||||
return index_list_to_u32<s32>(data_ptr, count, index_offset, stride);
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
|
||||
return index_list_to_u32<u32>(data_ptr, count, index_offset, stride);
|
||||
default:
|
||||
ASSERT_MSG(false, "unsupported component type");
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Extract positions, colors, and normals from a mesh.
|
||||
*/
|
||||
ExtractedVertices gltf_vertices(const tinygltf::Model& model,
|
||||
const std::map<std::string, int>& attributes,
|
||||
const math::Matrix4f& w_T_local,
|
||||
bool get_colors,
|
||||
bool get_normals,
|
||||
const std::string& debug_name) {
|
||||
std::vector<tfrag3::PreloadedVertex> result;
|
||||
std::vector<math::Vector<u8, 4>> vtx_colors;
|
||||
|
||||
{
|
||||
const auto& position_attrib = attributes.find("POSITION");
|
||||
ASSERT_MSG(position_attrib != attributes.end(), "Did not find position attribute.");
|
||||
|
||||
const auto attrib_accessor = model.accessors[position_attrib->second];
|
||||
const auto& buffer_view = model.bufferViews[attrib_accessor.bufferView];
|
||||
const auto& buffer = model.buffers[buffer_view.buffer];
|
||||
const auto data_ptr = buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset;
|
||||
const auto byte_stride = attrib_accessor.ByteStride(buffer_view);
|
||||
const auto count = attrib_accessor.count;
|
||||
|
||||
ASSERT_MSG(attrib_accessor.type == TINYGLTF_TYPE_VEC3, "POSITION wasn't vec3");
|
||||
ASSERT_MSG(attrib_accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT,
|
||||
"POSITION wasn't float");
|
||||
// for (auto& attrib : attributes) {
|
||||
// lg::print("attrib: {}\n", attrib.first);
|
||||
//}
|
||||
auto mesh_verts = extract_vec3f(data_ptr, count, byte_stride);
|
||||
result.reserve(mesh_verts.size());
|
||||
for (auto& vert : mesh_verts) {
|
||||
auto& new_vert = result.emplace_back();
|
||||
math::Vector4f v_in(vert.x(), vert.y(), vert.z(), 1);
|
||||
math::Vector4f v_w = w_T_local * v_in;
|
||||
new_vert.x = v_w.x() * 4096;
|
||||
new_vert.y = v_w.y() * 4096;
|
||||
new_vert.z = v_w.z() * 4096;
|
||||
}
|
||||
}
|
||||
|
||||
if (get_colors) {
|
||||
const auto& color_attrib = attributes.find("COLOR_0");
|
||||
if (color_attrib == attributes.end()) {
|
||||
lg::error("Mesh {} didn't have any colors, using white", debug_name);
|
||||
for (size_t i = 0; i < result.size(); i++) {
|
||||
vtx_colors.emplace_back(0x80, 0x80, 0x80, 0xff);
|
||||
}
|
||||
} else {
|
||||
const auto attrib_accessor = model.accessors[color_attrib->second];
|
||||
const auto& buffer_view = model.bufferViews[attrib_accessor.bufferView];
|
||||
const auto& buffer = model.buffers[buffer_view.buffer];
|
||||
const auto data_ptr =
|
||||
buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset;
|
||||
const auto byte_stride = attrib_accessor.ByteStride(buffer_view);
|
||||
const auto count = attrib_accessor.count;
|
||||
|
||||
ASSERT_MSG(attrib_accessor.type == TINYGLTF_TYPE_VEC4, "COLOR_0 wasn't vec4");
|
||||
std::vector<math::Vector<u8, 4>> colors;
|
||||
switch (attrib_accessor.componentType) {
|
||||
case TINYGLTF_COMPONENT_TYPE_FLOAT:
|
||||
colors = extract_color_from_vec4_float(data_ptr, count, byte_stride);
|
||||
break;
|
||||
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
|
||||
colors = extract_color_from_vec4_u16(data_ptr, count, byte_stride);
|
||||
break;
|
||||
default:
|
||||
lg::die("Unknown component type for COLOR_0: {}", attrib_accessor.componentType);
|
||||
}
|
||||
vtx_colors.insert(vtx_colors.end(), colors.begin(), colors.end());
|
||||
}
|
||||
}
|
||||
|
||||
bool got_texture = false;
|
||||
{
|
||||
const auto& texcoord_attrib = attributes.find("TEXCOORD_0");
|
||||
if (texcoord_attrib != attributes.end()) {
|
||||
const auto attrib_accessor = model.accessors[texcoord_attrib->second];
|
||||
const auto& buffer_view = model.bufferViews[attrib_accessor.bufferView];
|
||||
const auto& buffer = model.buffers[buffer_view.buffer];
|
||||
const auto data_ptr =
|
||||
buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset;
|
||||
const auto byte_stride = attrib_accessor.ByteStride(buffer_view);
|
||||
const auto count = attrib_accessor.count;
|
||||
|
||||
ASSERT_MSG(attrib_accessor.type == TINYGLTF_TYPE_VEC2, "TEXCOORD wasn't vec2");
|
||||
ASSERT_MSG(attrib_accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT,
|
||||
"TEXCOORD wasn't float");
|
||||
auto mesh_verts = extract_vec2f(data_ptr, count, byte_stride);
|
||||
ASSERT(mesh_verts.size() == result.size());
|
||||
got_texture = true;
|
||||
for (size_t i = 0; i < mesh_verts.size(); i++) {
|
||||
result[i].s = mesh_verts[i].x();
|
||||
result[i].t = mesh_verts[i].y();
|
||||
}
|
||||
} else {
|
||||
if (!get_normals) {
|
||||
// don't warn if we're just getting collision
|
||||
lg::warn("No texcoord attribute for mesh: {}", debug_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<math::Vector3f> normals;
|
||||
if (get_normals) {
|
||||
const auto& normal_attrib = attributes.find("NORMAL");
|
||||
if (normal_attrib != attributes.end()) {
|
||||
const auto attrib_accessor = model.accessors[normal_attrib->second];
|
||||
const auto& buffer_view = model.bufferViews[attrib_accessor.bufferView];
|
||||
const auto& buffer = model.buffers[buffer_view.buffer];
|
||||
const auto data_ptr =
|
||||
buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset;
|
||||
const auto byte_stride = attrib_accessor.ByteStride(buffer_view);
|
||||
const auto count = attrib_accessor.count;
|
||||
|
||||
ASSERT_MSG(attrib_accessor.type == TINYGLTF_TYPE_VEC3, "NORMAL wasn't vec3");
|
||||
ASSERT_MSG(attrib_accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT,
|
||||
"NORMAL wasn't float");
|
||||
normals = extract_vec3f(data_ptr, count, byte_stride);
|
||||
for (auto& nrm : normals) {
|
||||
math::Vector4f nrm4(nrm.x(), nrm.y(), nrm.z(), 0.f);
|
||||
nrm = (w_T_local * nrm4).xyz();
|
||||
}
|
||||
ASSERT(normals.size() == result.size());
|
||||
} else {
|
||||
lg::error("No NORMAL attribute for mesh: {}", debug_name);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& v : result) {
|
||||
v.color_index = 0;
|
||||
if (!got_texture) {
|
||||
v.s = 0;
|
||||
v.t = 0;
|
||||
}
|
||||
}
|
||||
// TODO: other properties
|
||||
return {result, vtx_colors, normals};
|
||||
}
|
||||
|
||||
DrawMode make_default_draw_mode() {
|
||||
DrawMode mode;
|
||||
mode.set_depth_write_enable(true);
|
||||
mode.set_depth_test(GsTest::ZTest::GEQUAL);
|
||||
mode.set_alpha_blend(DrawMode::AlphaBlend::DISABLED);
|
||||
mode.set_aref(0);
|
||||
mode.set_alpha_fail(GsTest::AlphaFail::KEEP);
|
||||
mode.set_clamp_s_enable(false);
|
||||
mode.set_clamp_t_enable(false);
|
||||
mode.disable_filt(); // for checkerboard...
|
||||
mode.enable_tcc(); // ?
|
||||
mode.disable_at();
|
||||
mode.enable_zt();
|
||||
mode.disable_ab();
|
||||
mode.disable_decal();
|
||||
mode.enable_fog();
|
||||
return mode;
|
||||
}
|
||||
|
||||
int texture_pool_debug_checker(TexturePool* pool) {
|
||||
const auto& existing = pool->textures_by_name.find("DEBUG_CHECKERBOARD");
|
||||
if (existing == pool->textures_by_name.end()) {
|
||||
size_t idx = pool->textures_by_idx.size();
|
||||
pool->textures_by_name["DEBUG_CHECKERBOARD"] = idx;
|
||||
auto& tex = pool->textures_by_idx.emplace_back();
|
||||
tex.w = 16;
|
||||
tex.h = 16;
|
||||
tex.debug_name = "DEBUG_CHECKERBOARD";
|
||||
tex.debug_tpage_name = "DEBUG";
|
||||
tex.load_to_pool = false;
|
||||
tex.combo_id = 0; // doesn't matter, not a pool tex
|
||||
tex.data.resize(16 * 16);
|
||||
u32 c0 = 0xa0303030;
|
||||
u32 c1 = 0xa0e0e0e0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
tex.data[i * 16 + j] = (((i / 4) & 1) ^ ((j / 4) & 1)) ? c1 : c0;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
} else {
|
||||
return existing->second;
|
||||
}
|
||||
}
|
||||
|
||||
int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex) {
|
||||
const auto& existing = pool->textures_by_name.find(tex.name);
|
||||
if (existing != pool->textures_by_name.end()) {
|
||||
lg::info("Reusing image: {}", tex.name);
|
||||
return existing->second;
|
||||
} else {
|
||||
lg::info("adding new texture: {}, size {} kB", tex.name, tex.width * tex.height * 4 / 1024);
|
||||
}
|
||||
|
||||
ASSERT(tex.bits == 8);
|
||||
ASSERT(tex.component == 4);
|
||||
ASSERT(tex.pixel_type == TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE);
|
||||
|
||||
size_t idx = pool->textures_by_idx.size();
|
||||
pool->textures_by_name[tex.name] = idx;
|
||||
auto& tt = pool->textures_by_idx.emplace_back();
|
||||
tt.w = tex.width;
|
||||
tt.h = tex.height;
|
||||
tt.debug_name = tex.name;
|
||||
tt.debug_tpage_name = "custom-level";
|
||||
tt.load_to_pool = false;
|
||||
tt.combo_id = 0; // doesn't matter, not a pool tex
|
||||
tt.data.resize(tt.w * tt.h);
|
||||
ASSERT(tex.image.size() >= tt.data.size());
|
||||
memcpy(tt.data.data(), tex.image.data(), tt.data.size() * 4);
|
||||
return idx;
|
||||
}
|
||||
|
||||
math::Matrix4f affine_translation(const math::Vector3f& translation) {
|
||||
math::Matrix4f result = math::Matrix4f::identity();
|
||||
result(0, 3) = translation[0];
|
||||
result(1, 3) = translation[1];
|
||||
result(2, 3) = translation[2];
|
||||
result(3, 3) = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
math::Matrix4f affine_scale(const math::Vector3f& scale) {
|
||||
math::Matrix4f result = math::Matrix4f::zero();
|
||||
result(0, 0) = scale[0];
|
||||
result(1, 1) = scale[1];
|
||||
result(2, 2) = scale[2];
|
||||
result(3, 3) = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
math::Matrix4f affine_rot_qxyzw(const math::Vector4f& quat) {
|
||||
math::Matrix4f result = math::Matrix4f::zero();
|
||||
result(3, 3) = 1;
|
||||
result(0, 0) = 1.0 - 2.0 * (quat.y() * quat.y() + quat.z() * quat.z());
|
||||
result(0, 1) = 2.0 * (quat.x() * quat.y() - quat.z() * quat.w());
|
||||
result(0, 2) = 2.0 * (quat.x() * quat.z() + quat.y() * quat.w());
|
||||
result(1, 0) = 2.0 * (quat.x() * quat.y() + quat.z() * quat.w());
|
||||
result(1, 1) = 1.0 - 2.0 * (quat.x() * quat.x() + quat.z() * quat.z());
|
||||
result(1, 2) = 2.0 * (quat.y() * quat.z() - quat.x() * quat.w());
|
||||
result(2, 0) = 2.0 * (quat.x() * quat.z() - quat.y() * quat.w());
|
||||
result(2, 1) = 2.0 * (quat.y() * quat.z() + quat.x() * quat.w());
|
||||
result(2, 2) = 1.0 - 2.0 * (quat.x() * quat.x() + quat.y() * quat.y());
|
||||
return result;
|
||||
}
|
||||
|
||||
math::Vector3f vector3f_from_gltf(const std::vector<double>& in) {
|
||||
ASSERT(in.size() == 3);
|
||||
return math::Vector3f{in[0], in[1], in[2]};
|
||||
}
|
||||
|
||||
math::Vector4f vector4f_from_gltf(const std::vector<double>& in) {
|
||||
ASSERT(in.size() == 4);
|
||||
return math::Vector4f{in[0], in[1], in[2], in[3]};
|
||||
}
|
||||
|
||||
math::Matrix4f matrix_from_node(const tinygltf::Node& node) {
|
||||
if (!node.matrix.empty()) {
|
||||
math::Matrix4f result;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
result.data()[i] = node.matrix[i];
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
// from trs
|
||||
math::Matrix4f t, r, s;
|
||||
if (!node.translation.empty()) {
|
||||
t = affine_translation(vector3f_from_gltf(node.translation));
|
||||
} else {
|
||||
t = math::Matrix4f::identity();
|
||||
}
|
||||
|
||||
if (!node.rotation.empty()) {
|
||||
r = affine_rot_qxyzw(vector4f_from_gltf(node.rotation));
|
||||
} else {
|
||||
r = math::Matrix4f::identity();
|
||||
}
|
||||
|
||||
if (!node.scale.empty()) {
|
||||
s = affine_scale(vector3f_from_gltf(node.scale));
|
||||
} else {
|
||||
s = math::Matrix4f::identity();
|
||||
}
|
||||
|
||||
return t * r * s;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Recursively walk the tree of nodes, flatten, and compute w_T_node for each.
|
||||
*/
|
||||
void node_find_helper(const tinygltf::Model& model,
|
||||
const math::Matrix4f& w_T_parent,
|
||||
int node_idx,
|
||||
std::vector<NodeWithTransform>* out) {
|
||||
const auto& node = model.nodes.at(node_idx);
|
||||
math::Matrix4f w_T_node = w_T_parent * matrix_from_node(node);
|
||||
out->push_back({node_idx, w_T_node});
|
||||
for (auto& child : node.children) {
|
||||
node_find_helper(model, w_T_node, child, out);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<NodeWithTransform> flatten_nodes_from_all_scenes(const tinygltf::Model& model) {
|
||||
std::vector<NodeWithTransform> out;
|
||||
for (auto& scene : model.scenes) {
|
||||
for (auto& nidx : scene.nodes) {
|
||||
math::Matrix4f identity = math::Matrix4f::identity();
|
||||
node_find_helper(model, identity, nidx, &out);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void dedup_vertices(const std::vector<tfrag3::PreloadedVertex>& vertices_in,
|
||||
std::vector<tfrag3::PreloadedVertex>& vertices_out,
|
||||
std::vector<u32>& old_to_new_out) {
|
||||
ASSERT(vertices_out.empty());
|
||||
ASSERT(old_to_new_out.empty());
|
||||
old_to_new_out.resize(vertices_in.size(), -1);
|
||||
|
||||
std::unordered_map<tfrag3::PreloadedVertex, u32, tfrag3::PreloadedVertex::hash> vtx_to_new;
|
||||
|
||||
for (size_t in_idx = 0; in_idx < vertices_in.size(); in_idx++) {
|
||||
auto& vtx = vertices_in[in_idx];
|
||||
const auto& lookup = vtx_to_new.find(vtx);
|
||||
if (lookup == vtx_to_new.end()) {
|
||||
// first time seeing this one
|
||||
size_t new_idx = vertices_out.size();
|
||||
vertices_out.push_back(vtx);
|
||||
old_to_new_out[in_idx] = new_idx;
|
||||
vtx_to_new[vtx] = new_idx;
|
||||
} else {
|
||||
old_to_new_out[in_idx] = lookup->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DrawMode draw_mode_from_sampler(const tinygltf::Sampler& sampler) {
|
||||
DrawMode mode = make_default_draw_mode();
|
||||
if (sampler.magFilter == TINYGLTF_TEXTURE_FILTER_NEAREST) {
|
||||
ASSERT(sampler.minFilter == TINYGLTF_TEXTURE_FILTER_NEAREST);
|
||||
mode.set_filt_enable(false);
|
||||
} else {
|
||||
ASSERT(sampler.minFilter != TINYGLTF_TEXTURE_FILTER_NEAREST);
|
||||
mode.set_filt_enable(true);
|
||||
}
|
||||
|
||||
switch (sampler.wrapS) {
|
||||
case TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE:
|
||||
mode.set_clamp_s_enable(true);
|
||||
break;
|
||||
case TINYGLTF_TEXTURE_WRAP_REPEAT:
|
||||
mode.set_clamp_s_enable(false);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
switch (sampler.wrapT) {
|
||||
case TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE:
|
||||
mode.set_clamp_t_enable(true);
|
||||
break;
|
||||
case TINYGLTF_TEXTURE_WRAP_REPEAT:
|
||||
mode.set_clamp_t_enable(false);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
} // namespace gltf_util
|
||||
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/custom_data/Tfrag3Data.h"
|
||||
#include "common/math/Vector.h"
|
||||
|
||||
#include "third-party/tiny_gltf/tiny_gltf.h"
|
||||
|
||||
namespace gltf_util {
|
||||
|
||||
/*!
|
||||
* Convert a GLTF index buffer to std::vector<u32>
|
||||
*/
|
||||
template <typename T>
|
||||
std::vector<u32> index_list_to_u32(const u8* data, u32 num_verts, u32 offset, u32 stride) {
|
||||
std::vector<u32> result;
|
||||
result.reserve(num_verts);
|
||||
for (u32 i = 0; i < num_verts; i++) {
|
||||
T val;
|
||||
memcpy(&val, data, sizeof(T));
|
||||
result.push_back(offset + val);
|
||||
data += stride;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<math::Vector3f> extract_vec3f(const u8* data, u32 count, u32 stride);
|
||||
std::vector<math::Vector2f> extract_vec2f(const u8* data, u32 count, u32 stride);
|
||||
std::vector<math::Vector<u8, 4>> extract_color_from_vec4_u16(const u8* data, u32 count, u32 stride);
|
||||
std::vector<u32> gltf_index_buffer(const tinygltf::Model& model, int indices_idx, u32 index_offset);
|
||||
|
||||
struct ExtractedVertices {
|
||||
std::vector<tfrag3::PreloadedVertex> vtx;
|
||||
std::vector<math::Vector<u8, 4>> vtx_colors;
|
||||
std::vector<math::Vector3f> normals;
|
||||
};
|
||||
|
||||
ExtractedVertices gltf_vertices(const tinygltf::Model& model,
|
||||
const std::map<std::string, int>& attributes,
|
||||
const math::Matrix4f& w_T_local,
|
||||
bool get_colors,
|
||||
bool get_normals,
|
||||
const std::string& debug_name);
|
||||
DrawMode make_default_draw_mode();
|
||||
|
||||
struct TexturePool {
|
||||
std::unordered_map<std::string, int> textures_by_name;
|
||||
std::vector<tfrag3::Texture> textures_by_idx;
|
||||
};
|
||||
|
||||
int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex);
|
||||
int texture_pool_debug_checker(TexturePool* pool);
|
||||
|
||||
struct NodeWithTransform {
|
||||
int node_idx;
|
||||
math::Matrix4f w_T_node;
|
||||
};
|
||||
|
||||
void dedup_vertices(const std::vector<tfrag3::PreloadedVertex>& vertices_in,
|
||||
std::vector<tfrag3::PreloadedVertex>& vertices_out,
|
||||
std::vector<u32>& old_to_new_out);
|
||||
|
||||
std::vector<NodeWithTransform> flatten_nodes_from_all_scenes(const tinygltf::Model& model);
|
||||
|
||||
DrawMode draw_mode_from_sampler(const tinygltf::Sampler& sampler);
|
||||
|
||||
} // namespace gltf_util
|
||||
@@ -27,11 +27,11 @@ Range<int> parse_json_optional_integer_range(const nlohmann::json& json);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void json_get_optional(const nlohmann::json& json,
|
||||
void json_get_optional(const nlohmann::json& j,
|
||||
const std::string& key,
|
||||
std::optional<T>& optionalValue) {
|
||||
if (json.contains(key) && !json[key].is_null()) {
|
||||
optionalValue = json[key].get<T>();
|
||||
if (j.contains(key) && !j[key].is_null()) {
|
||||
optionalValue = j[key].get<T>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
-8
@@ -3,20 +3,29 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/log/log.h"
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#ifdef _WIN32
|
||||
// clang-format off
|
||||
#define NOMINMAX
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <psapi.h>
|
||||
// clang-format on
|
||||
size_t get_peak_rss() {
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
PROCESS_MEMORY_COUNTERS pmc;
|
||||
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) {
|
||||
return pmc.PeakWorkingSetSize;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#include <sys/resource.h>
|
||||
|
||||
size_t get_peak_rss() {
|
||||
rusage x;
|
||||
getrusage(RUSAGE_SELF, &x);
|
||||
return x.ru_maxrss * 1024;
|
||||
}
|
||||
|
||||
#else
|
||||
size_t get_peak_rss() {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
// Note: these are not implemented on windows and will return zero.
|
||||
size_t get_peak_rss();
|
||||
void setup_cpu_info();
|
||||
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
|
||||
// A normal Trie does not allow for duplicate keys, however this one does
|
||||
// It allows for insertion and removal
|
||||
//
|
||||
// Note, keys assume only basic ASCII, which is _fine_ as OpenGOAL itself has this
|
||||
// limitation as well.
|
||||
template <typename T>
|
||||
class TrieWithDuplicates {
|
||||
private:
|
||||
@@ -37,10 +34,13 @@ class TrieWithDuplicates {
|
||||
return curr_node->elements.back().get();
|
||||
}
|
||||
|
||||
std::vector<T*> retrieve_with_prefix(const std::string& prefix) const {
|
||||
std::vector<T*> retrieve_with_prefix(const std::string& prefix, int max_count = -1) const {
|
||||
std::vector<T*> results;
|
||||
TrieNode* curr_node = root.get();
|
||||
for (const char character : prefix) {
|
||||
if (max_count >= 0 && (int)results.size() > max_count) {
|
||||
return results;
|
||||
}
|
||||
const auto& child = curr_node->children.at((uint8_t)character);
|
||||
if (child == nullptr) {
|
||||
return results; // tree ends, nothing found with that prefix
|
||||
@@ -48,7 +48,7 @@ class TrieWithDuplicates {
|
||||
curr_node = child.get();
|
||||
}
|
||||
}
|
||||
retrieve_elements(curr_node, results);
|
||||
retrieve_elements(curr_node, results, max_count);
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -107,13 +107,19 @@ class TrieWithDuplicates {
|
||||
}
|
||||
|
||||
private:
|
||||
void retrieve_elements(const TrieNode* node, std::vector<T*>& results) const {
|
||||
void retrieve_elements(const TrieNode* node, std::vector<T*>& results, int max_count = -1) const {
|
||||
for (const auto& element : node->elements) {
|
||||
if (max_count >= 0 && (int)results.size() > max_count) {
|
||||
return;
|
||||
}
|
||||
results.push_back(element.get());
|
||||
}
|
||||
for (const auto& child : node->children) {
|
||||
if (max_count >= 0 && (int)results.size() > max_count) {
|
||||
return;
|
||||
}
|
||||
if (child.get() != nullptr) {
|
||||
retrieve_elements(child.get(), results);
|
||||
retrieve_elements(child.get(), results, max_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@ Disclaimer: custom levels are still in development and are missing most features
|
||||
The first three steps are already done for "test zone", so this can be used as a starting point.
|
||||
|
||||
# 1: File Setup
|
||||
To create a custom level, copy the layout of `custom_levels/test-zone`. See `test-zone.jsonc` for information on how to name things. The `.gd` file also contains the level name.
|
||||
To create a custom level, copy the layout of `custom_assets/jak1/levels/test-zone`. See `test-zone.jsonc` for information on how to name things. The `.gd` file also contains the level name.
|
||||
|
||||
# 2: Modify the engine
|
||||
Modify `goal_src/engine/level/level-info.gc` to add level info for each custom level. There is level info for `test-zone` at the bottom that can be used as an example.
|
||||
Modify `goal_src/jak1/engine/level/level-info.gc` to add level info for each custom level. There is level info for `test-zone` at the bottom that can be used as an example.
|
||||
|
||||
# 3: Modify the build system
|
||||
Modify `goal_src/game.gp` and add a custom level target:
|
||||
Modify `goal_src/jak1/game.gp` and add a custom level target:
|
||||
```lisp
|
||||
(build-custom-level "test-zone")
|
||||
;; the DGO file
|
||||
@@ -21,7 +21,7 @@ Modify `goal_src/game.gp` and add a custom level target:
|
||||
# 4: Export the GLTF file from blender.
|
||||
For now, all meshes are displayed and treated as ground collision. This causes buggy collision because walls shouldn't use "floor" mode.
|
||||
|
||||
Blender will create a `.glb` file, which must have the name specified in the `.jsonc` file and should be located in `custom_level/your_level`
|
||||
Blender will create a `.glb` file, which must have the name specified in the `.jsonc` file and should be located in `custom_assets/jak1/levels/your_level`
|
||||
|
||||
# 5: Rebuild the game
|
||||
Any time the `.glb` file is changed, you must rebuild the game. Launch the compiler (`goalc`) and run `(mi)` to rebuild everything. It's recommended to leave the compiler open - it will remember files that haven't changed and skip rebuilding them.
|
||||
File renamed without changes.
File renamed without changes.
+22
-10
@@ -10,7 +10,7 @@
|
||||
// Must have vertex colors. Use the blender cycles renderer, bake, diffuse, uncheck color,
|
||||
// and bake to vertex colors. For now, only the first vertex color group is used, so make sure you
|
||||
// only have 1.
|
||||
"gltf_file": "custom_levels/jak1/test-zone/test-zone2.glb",
|
||||
"gltf_file": "custom_assets/jak1/levels/test-zone/test-zone2.glb",
|
||||
|
||||
// automatically set wall vs. ground based on angle. Useful if you don't want to assign this yourself
|
||||
"automatic_wall_detection": true,
|
||||
@@ -55,20 +55,22 @@
|
||||
// adds a 'symbol' tag (using the 'type' and 'string' lump types works the same way):
|
||||
// "symbol-list": ["symbol", "sym-1", "sym-2"]
|
||||
|
||||
// The base actor id for your custom level. If you have multiple levels this should be unique!
|
||||
"base_id": 100,
|
||||
// The base actor id for your custom level. If you have multiple levels, this should be unique!
|
||||
"base_id": 100,
|
||||
|
||||
// All art groups you want to use in your custom level. Will add their models and corresponding textures to the FR3 file.
|
||||
// Note: You will still have to add them to your level's .gd file.
|
||||
// Removed so that the release builds don't have to double-decompile the game
|
||||
// "art_groups": ["plat-ag"],
|
||||
"art_groups": [],
|
||||
|
||||
// Any textures you want to include in your custom level. This is mainly useful for things such as the zoomer HUD,
|
||||
// which is not in the common level files and has no art group associated with it.
|
||||
// To get a list of all the textures, you can extract all of the game's textures
|
||||
// by setting "save_texture_pngs" to true in the decompiler config.
|
||||
"textures": [
|
||||
// If you have any custom models in the "custom_assets/jak1/models/custom_levels" folder that you want to use in your level, add them to this list.
|
||||
// Note: Like with art groups, these should also be added to your level's .gd file.
|
||||
"custom_models": ["test-actor"],
|
||||
|
||||
// Any textures you want to include in your custom level. This is mainly useful for things such as the zoomer HUD,
|
||||
// which is not in the common level files and has no art group associated with it.
|
||||
// To get a list of all the textures, you can extract all of the game's textures
|
||||
// by setting "save_texture_pngs" to true in the decompiler config.
|
||||
"textures": [
|
||||
// all textures required for the zoomer HUD
|
||||
// "zoomerhud",
|
||||
// "zoomerhud-dial",
|
||||
@@ -130,6 +132,16 @@
|
||||
"lump": {
|
||||
"name": "test-eco"
|
||||
}
|
||||
},
|
||||
{
|
||||
"trans": [-5.41, 3.5, 28.42], // translation
|
||||
"etype": "test-actor", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-7.41, 3.5, 28.42, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-actor"
|
||||
}
|
||||
}
|
||||
// {
|
||||
// "trans": [-7.41, 3.5, 28.42], // translation
|
||||
File renamed without changes.
+3
-1
@@ -4,6 +4,8 @@
|
||||
;; the actual file name still needs to be 8.3
|
||||
("TSZ.DGO"
|
||||
("static-screen.o"
|
||||
"test-zone.go"
|
||||
"test-zone-obs.o"
|
||||
"plat-ag.go"
|
||||
"test-actor-ag.go"
|
||||
"test-zone.go"
|
||||
))
|
||||
Binary file not shown.
+1
-1
@@ -10,7 +10,7 @@
|
||||
// Must have vertex colors. Use the blender cycles renderer, bake, diffuse, uncheck color,
|
||||
// and bake to vertex colors. For now, only the first vertex color group is used, so make sure you
|
||||
// only have 1.
|
||||
"gltf_file": "custom_levels/jak2/test-zone/test-zone2.glb",
|
||||
"gltf_file": "custom_assets/jak2/levels/test-zone/test-zone2.glb",
|
||||
|
||||
// automatically set wall vs. ground based on angle. Useful if you don't want to assign this yourself
|
||||
"automatic_wall_detection": true,
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,90 @@
|
||||
{
|
||||
// The "in-game" name of the level. Should be lower case, with dashes (GOAL symbol name)
|
||||
// the name of this file, and the folder this file is in must have the same name.
|
||||
"long_name": "test-zone",
|
||||
// The file name, should be upper case and 8 characters or less.
|
||||
"iso_name": "TESTZONE",
|
||||
// The nickname, should be exactly 3 characters
|
||||
"nickname": "tsz", // 3 char name, all lowercase
|
||||
// Background mesh file.
|
||||
// Must have vertex colors. Use the blender cycles renderer, bake, diffuse, uncheck color,
|
||||
// and bake to vertex colors. For now, only the first vertex color group is used, so make sure you
|
||||
// only have 1.
|
||||
"gltf_file": "custom_assets/jak3/levels/test-zone/test-zone2.glb",
|
||||
|
||||
// automatically set wall vs. ground based on angle. Useful if you don't want to assign this yourself
|
||||
"automatic_wall_detection": true,
|
||||
"automatic_wall_angle": 45.0,
|
||||
|
||||
// if your mesh has triangles with incorrect orientation, set this to make all collision mesh triangles double sided
|
||||
// this makes collision 2x slower and bigger, so only use if really needed
|
||||
"double_sided_collide": false,
|
||||
|
||||
// available res-lump tag types:
|
||||
// integer types: int32, uint32, enum-int32, enum-uint32
|
||||
// float types: float, meters (1 meter = 4096.0 units), degrees (65536.0 = 360°)
|
||||
// vector types: vector (normal floats), vector4m (meters), vector3m (meters with w set to 1.0), vector-vol (normal floats with w in meters), movie-pos (meters with w in degrees)
|
||||
// special types: symbol, type, string, eco-info, cell-info, buzzer-info, water-height
|
||||
//
|
||||
// examples:
|
||||
//
|
||||
// adds a float tag 'spring-height' with value of 200 meters (1 meter = 4096.0 units):
|
||||
// "spring-height": ["meters", 200.0]
|
||||
//
|
||||
// adds a degrees tag 'rotoffset':
|
||||
// "rotoffset": ["degrees", -45.0]
|
||||
//
|
||||
// adds a movie-pos tag:
|
||||
// "movie-pos": ["movie-pos", [100.22, -25.3, 99.5, 180.0]]
|
||||
//
|
||||
// adds an enum tag 'options':
|
||||
// "options": ["enum-int32", "(fact-options large)"]
|
||||
//
|
||||
// adds a water-height tag:
|
||||
// "water-height": ["water-height", 25.0, 0.5, 2.0, "(water-flags can-swim can-wade)"]
|
||||
//
|
||||
// adds an eco-info tag:
|
||||
// "eco-info": ["eco-info", "(pickup-type health)", 2]
|
||||
//
|
||||
// adds a 'type' tag (using the "symbol" and "string" lump types works the same way):
|
||||
// "spawn-types": ["type", "spyder", "juicer"]
|
||||
|
||||
// The base actor id for your custom level. If you have multiple levels, this should be unique!
|
||||
"base_id": 100,
|
||||
|
||||
// All art groups you want to use in your custom level. Will add their models and corresponding textures to the FR3 file.
|
||||
// "art_groups": [],
|
||||
|
||||
// Any textures you want to include in your custom level.
|
||||
// This is mainly useful for textures which are not in the common level files and have no art group associated with them.
|
||||
// To get a list of all the textures, you can extract all of the game's textures
|
||||
// by setting "save_texture_pngs" to true in the decompiler config.
|
||||
// "textures": [],
|
||||
|
||||
"actors" : [
|
||||
{
|
||||
"trans": [-15.2818, 15.2461, 17.1360], // translation
|
||||
"etype": "crate", // actor type
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"kill_mask": 0,
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-crate",
|
||||
"eco-info": ["eco-info", "(pickup-type gem)", 1]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"trans": [-5.4630, 17.4553, 1.6169], // translation
|
||||
"etype": "eco-yellow", // actor type
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"kill_mask": 0,
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-eco"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
;; DGO definition file for Awful Village level
|
||||
;; We use the convention of having a longer DGO name for levels without precomputed visibility.
|
||||
|
||||
;; the actual file name still needs to be 8.3
|
||||
("TSZ.DGO"
|
||||
("test-zone.go"
|
||||
)
|
||||
)
|
||||
@@ -58,6 +58,7 @@ add_library(
|
||||
level_extractor/extract_actors.cpp
|
||||
level_extractor/extract_collide_frags.cpp
|
||||
level_extractor/extract_common.cpp
|
||||
level_extractor/extract_hfrag.cpp
|
||||
level_extractor/extract_joint_group.cpp
|
||||
level_extractor/extract_level.cpp
|
||||
level_extractor/extract_merc.cpp
|
||||
@@ -67,6 +68,7 @@ add_library(
|
||||
level_extractor/fr3_to_gltf.cpp
|
||||
level_extractor/MercData.cpp
|
||||
level_extractor/tfrag_tie_fixup.cpp
|
||||
level_extractor/merc_replacement.cpp
|
||||
|
||||
ObjectFile/LinkedObjectFile.cpp
|
||||
ObjectFile/LinkedObjectFileCreation.cpp
|
||||
@@ -88,7 +90,8 @@ add_library(
|
||||
VuDisasm/VuDisassembler.cpp
|
||||
VuDisasm/VuInstruction.cpp
|
||||
|
||||
config.cpp)
|
||||
config.cpp
|
||||
decompilation_process.cpp)
|
||||
|
||||
target_link_libraries(decomp
|
||||
lzokay
|
||||
|
||||
@@ -6586,6 +6586,10 @@ bool try_vector_reset_inline(const Env& env,
|
||||
RegisterAccess orig;
|
||||
store = repop_passthrough_arg(store, stack, env, &orig, &got_orig);
|
||||
|
||||
if (!store) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// create the actual form
|
||||
Form* new_thing = pool.form<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>("vector-reset!")),
|
||||
|
||||
@@ -760,6 +760,10 @@ bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out, const Env* cons
|
||||
break;
|
||||
}
|
||||
|
||||
if (entries_matched == m_entry_matchers.size()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_entry_matchers.at(entries_matched)
|
||||
.do_match(let_body->entries().at(0), maps_out, env)) {
|
||||
entries_matched++;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace decompiler {
|
||||
*/
|
||||
class LinkedObjectFile {
|
||||
public:
|
||||
LinkedObjectFile(GameVersion version) : version(version){};
|
||||
LinkedObjectFile(GameVersion _version) : version(_version) {}
|
||||
void set_segment_count(int n_segs);
|
||||
void push_back_word_to_segment(uint32_t word, int segment);
|
||||
int get_label_id_for(int seg, int offset);
|
||||
|
||||
@@ -120,6 +120,7 @@ ObjectFileDB::ObjectFileDB(const std::vector<fs::path>& _dgos,
|
||||
const std::vector<fs::path>& object_files,
|
||||
const std::vector<fs::path>& str_files,
|
||||
const std::vector<fs::path>& str_tex_files,
|
||||
const std::vector<fs::path>& str_art_files,
|
||||
const Config& config)
|
||||
: dts(config.game_version), m_version(config.game_version) {
|
||||
Timer timer;
|
||||
@@ -237,6 +238,18 @@ ObjectFileDB::ObjectFileDB(const std::vector<fs::path>& _dgos,
|
||||
}
|
||||
}
|
||||
|
||||
if (!str_art_files.empty()) {
|
||||
lg::info("-Loading {} streaming art files...", str_art_files.size());
|
||||
for (auto& obj : str_art_files) {
|
||||
StrFileReader reader(obj, version());
|
||||
for (int i = 0; i < reader.chunk_count(); i++) {
|
||||
auto name = reader.get_chunk_art_name(i);
|
||||
add_obj_from_dgo(name, name, reader.get_chunk(i).data(), reader.get_chunk(i).size(),
|
||||
"ARTSPOOL", config, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lg::info("ObjectFileDB Initialized");
|
||||
if (obj_files_by_name.empty()) {
|
||||
lg::error(
|
||||
|
||||
@@ -169,6 +169,7 @@ class ObjectFileDB {
|
||||
const std::vector<fs::path>& object_files,
|
||||
const std::vector<fs::path>& str_files,
|
||||
const std::vector<fs::path>& str_tex_files,
|
||||
const std::vector<fs::path>& str_art_files,
|
||||
const Config& config);
|
||||
std::string generate_dgo_listing();
|
||||
std::string generate_obj_listing(const std::unordered_set<std::string>& merged_objs);
|
||||
@@ -331,7 +332,7 @@ class ObjectFileDB {
|
||||
void for_each_function_def_order(Func f) {
|
||||
for_each_obj([&](ObjectFileData& data) {
|
||||
for (int i = 0; i < int(data.linked_data.segments); i++) {
|
||||
int fn = 0;
|
||||
[[maybe_unused]] int fn = 0;
|
||||
for (size_t j = data.linked_data.functions_by_seg.at(i).size(); j-- > 0;) {
|
||||
f(data.linked_data.functions_by_seg.at(i).at(j), i, data);
|
||||
fn++;
|
||||
@@ -354,7 +355,7 @@ class ObjectFileDB {
|
||||
template <typename Func>
|
||||
void for_each_function_in_seg(int seg, Func f) {
|
||||
for_each_obj([&](ObjectFileData& data) {
|
||||
int fn = 0;
|
||||
[[maybe_unused]] int fn = 0;
|
||||
if (data.linked_data.segments == 3) {
|
||||
for (size_t j = data.linked_data.functions_by_seg.at(seg).size(); j-- > 0;) {
|
||||
f(data.linked_data.functions_by_seg.at(seg).at(j), data);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "ObjectFileDB.h"
|
||||
|
||||
#include "common/formatter/formatter.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
#include "common/link_types.h"
|
||||
#include "common/log/log.h"
|
||||
@@ -872,9 +873,22 @@ void ObjectFileDB::ir2_write_results(const fs::path& output_dir,
|
||||
auto file_name = output_dir / (obj.to_unique_name() + "_ir2.asm");
|
||||
file_util::write_text_file(file_name, file_text);
|
||||
|
||||
auto final = ir2_final_out(obj, imports, {});
|
||||
auto unformatted_code = ir2_final_out(obj, imports, {});
|
||||
auto final_name = output_dir / (obj.to_unique_name() + "_disasm.gc");
|
||||
file_util::write_text_file(final_name, final);
|
||||
if (config.format_code) {
|
||||
const auto formatted_code = formatter::format_code(unformatted_code);
|
||||
if (!formatted_code) {
|
||||
lg::error(
|
||||
"Was unable to format the decompiled result of {}, make a github issue. Writing "
|
||||
"unformatted code",
|
||||
obj.to_unique_name());
|
||||
file_util::write_text_file(final_name, unformatted_code);
|
||||
} else {
|
||||
file_util::write_text_file(final_name, formatted_code.value());
|
||||
}
|
||||
} else {
|
||||
file_util::write_text_file(final_name, unformatted_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,12 +54,8 @@ void append_body_to_function_definition(goos::Object* top_form,
|
||||
body_elements.insert(body_elements.end(), inline_body.begin(), inline_body.end());
|
||||
// If the first element in the body is a docstring, add it first
|
||||
if (body_elements.size() > 0 && body_elements.at(0).is_string()) {
|
||||
if (version > GameVersion::Jak2) {
|
||||
initial_top_level_forms.push_back(
|
||||
goos::StringObject::make_new(fix_docstring_indent(inline_body.at(0).as_string()->data)));
|
||||
} else {
|
||||
initial_top_level_forms.push_back(inline_body.at(0));
|
||||
}
|
||||
initial_top_level_forms.push_back(
|
||||
goos::StringObject::make_new(fix_docstring_indent(inline_body.at(0).as_string()->data)));
|
||||
body_elements.erase(body_elements.begin());
|
||||
}
|
||||
|
||||
|
||||
@@ -233,25 +233,30 @@ L460:
|
||||
.word 0x0 // jgeo // 36
|
||||
.word 0x0 // janim // 40
|
||||
.word 0x0 // ? (word 10) // 44
|
||||
.word 0x0 // bounds x // 48
|
||||
.word 0x0 // bounds y // 52
|
||||
.word 0x0 // bounds z // 56
|
||||
.word 0x464ccccd // bounds w/radius // 60
|
||||
.word 0x0 // mgeo 0/1 // 64
|
||||
.word 0x0 // mgeo 2/3 // 68
|
||||
.word 0x0 // mgeo 4/5 // 72
|
||||
.word 0x0 // max-lod // 76
|
||||
.word 0x0 // lod-dist 0 // 80
|
||||
.word 0x0 // lod-dist 1 // 84
|
||||
.word 0x0 // lod-dist 2 // 88
|
||||
.word 0x0 // lod-dist 3 // 92
|
||||
.word 0x0 // lod-dist 4 // 96
|
||||
.word 0x0 // lod-dist 5 // 100
|
||||
.word 0x45800000 // longest-edge // 104
|
||||
.word 0x80a // texture-level/version/shadow/sort // 108
|
||||
.word 0x10303 // origin-joint-index/shadow-joint-index/light-index/pad // 112
|
||||
.symbol #f // clothing // 116
|
||||
.word 0x0 // global-effects // 120
|
||||
.word 0x0 // bounds x // 48 11
|
||||
.word 0x0 // bounds y // 52 12
|
||||
.word 0x0 // bounds z // 56 13
|
||||
.word 0x464ccccd // bounds w/radius // 60 14
|
||||
.word 0x0 // mgeo 0/1 // 64 15
|
||||
.word 0x0 // mgeo 2/3 // 68 16
|
||||
.word 0x0 // mgeo 4/5 // 72 17
|
||||
.word 0x0 // max-lod // 76 18
|
||||
.word 0x0 // lod-dist 0 // 80 19
|
||||
.word 0x0 // lod-dist 1 // 84 20
|
||||
.word 0x0 // lod-dist 2 // 88 21
|
||||
.word 0x0 // lod-dist 3 // 92 22
|
||||
.word 0x0 // lod-dist 4 // 96 23
|
||||
.word 0x0 // lod-dist 5 // 100 24
|
||||
.word 0x45800000 // longest-edge // 104 25
|
||||
(texture-level int8 :offset-assert 108) ;; word 26
|
||||
(version int8 :offset-assert 109)
|
||||
(shadow int16 :offset-assert 110)
|
||||
(shadow-joint-index int8 :offset-assert 112) ;; word 27
|
||||
(origin-joint-index int8 :offset-assert 113)
|
||||
(sort int8 :offset-assert 114)
|
||||
(light-index uint8 :offset-assert 115)
|
||||
(clothing (array cloth-params) :offset-assert 116) ;; word 28
|
||||
(global-effects uint8 :offset-assert 120) ;; word 29
|
||||
.word 0x0 // pad
|
||||
*/
|
||||
|
||||
@@ -297,15 +302,16 @@ L460:
|
||||
}
|
||||
result.tex_level = other_word.get_byte(0);
|
||||
result.version = other_word.get_byte(1);
|
||||
result.shadow = other_word.get_byte(2);
|
||||
result.sort = other_word.get_byte(3);
|
||||
result.shadow = ((u32)other_word.get_byte(2)) | (((u32)other_word.get_byte(3)) << 8);
|
||||
|
||||
auto& index_word = words.at(start_word_idx + 27);
|
||||
if (index_word.kind() != LinkedWord::PLAIN_DATA) {
|
||||
env.func->warnings.error_and_throw("Reference to skelgroup bad: invalid index data");
|
||||
}
|
||||
result.origin_joint_index = index_word.get_byte(0);
|
||||
result.shadow_joint_index = index_word.get_byte(1);
|
||||
result.light_index = index_word.get_byte(2);
|
||||
result.shadow_joint_index = index_word.get_byte(0);
|
||||
result.origin_joint_index = index_word.get_byte(1);
|
||||
result.sort = index_word.get_byte(2);
|
||||
result.light_index = index_word.get_byte(3);
|
||||
|
||||
auto& clothing = words.at(start_word_idx + 28);
|
||||
if (clothing.kind() != LinkedWord::SYM_PTR && clothing.symbol_name() != "#f") {
|
||||
|
||||
+11
-1
@@ -59,7 +59,11 @@ Config make_config_via_json(nlohmann::json& json) {
|
||||
inputs_json.at("str_texture_file_names").get<std::vector<std::string>>();
|
||||
}
|
||||
|
||||
config.audio_dir_file_name = inputs_json.at("audio_dir_file_name").get<std::string>();
|
||||
if (inputs_json.contains("str_art_file_names")) {
|
||||
config.str_art_file_names =
|
||||
inputs_json.at("str_art_file_names").get<std::vector<std::string>>();
|
||||
}
|
||||
|
||||
config.streamed_audio_file_names =
|
||||
inputs_json.at("streamed_audio_file_names").get<std::vector<std::string>>();
|
||||
|
||||
@@ -91,6 +95,9 @@ Config make_config_via_json(nlohmann::json& json) {
|
||||
}
|
||||
config.disassemble_code = json.at("disassemble_code").get<bool>();
|
||||
config.decompile_code = json.at("decompile_code").get<bool>();
|
||||
if (json.contains("format_code")) {
|
||||
config.format_code = json.at("format_code").get<bool>();
|
||||
}
|
||||
config.write_hex_near_instructions = json.at("write_hex_near_instructions").get<bool>();
|
||||
config.write_scripts = json.at("write_scripts").get<bool>();
|
||||
config.disassemble_data = json.at("disassemble_data").get<bool>();
|
||||
@@ -313,6 +320,9 @@ Config make_config_via_json(nlohmann::json& json) {
|
||||
if (json.contains("save_texture_pngs")) {
|
||||
config.save_texture_pngs = json.at("save_texture_pngs").get<bool>();
|
||||
}
|
||||
if (json.contains("rip_streamed_audio")) {
|
||||
config.rip_streamed_audio = json.at("rip_streamed_audio").get<bool>();
|
||||
}
|
||||
|
||||
if (inputs_json.contains("animated_textures")) {
|
||||
config.animated_textures =
|
||||
|
||||
+3
-2
@@ -101,8 +101,7 @@ struct Config {
|
||||
std::vector<std::string> object_file_names;
|
||||
std::vector<std::string> str_file_names;
|
||||
std::vector<std::string> str_texture_file_names;
|
||||
|
||||
std::string audio_dir_file_name;
|
||||
std::vector<std::string> str_art_file_names;
|
||||
std::vector<std::string> streamed_audio_file_names;
|
||||
|
||||
std::string obj_file_name_map_file;
|
||||
@@ -110,6 +109,7 @@ struct Config {
|
||||
|
||||
bool disassemble_code = false;
|
||||
bool decompile_code = false;
|
||||
bool format_code = false;
|
||||
bool write_scripts = false;
|
||||
bool disassemble_data = false;
|
||||
bool process_tpages = false;
|
||||
@@ -173,6 +173,7 @@ struct Config {
|
||||
std::vector<std::string> levels_to_extract;
|
||||
bool levels_extract;
|
||||
bool save_texture_pngs = false;
|
||||
bool rip_streamed_audio = false;
|
||||
|
||||
DecompileHacks hacks;
|
||||
|
||||
|
||||
@@ -21102,7 +21102,7 @@
|
||||
:size-assert #x94
|
||||
:flag-assert #xf00300094
|
||||
(:methods
|
||||
(dumb-15 (_type_) none))
|
||||
(spawn-particles! (_type_) none))
|
||||
(:states
|
||||
hud-normal
|
||||
hud-coming-in
|
||||
@@ -22303,20 +22303,20 @@
|
||||
|
||||
;; - Functions
|
||||
|
||||
(define-extern calculate-rotation-and-color-for-slice (function int float int int int hud-particle none))
|
||||
(define-extern part-hud-health-01-func (function basic basic hud-particle none)) ;; TODO - i figured this out on another branch...all these particle functions get called by the particle system with the same beginning types iirc
|
||||
(define-extern part-hud-health-02-func (function basic basic hud-particle none))
|
||||
(define-extern part-hud-health-03-func (function basic basic hud-particle none))
|
||||
(define-extern calculate-rotation-and-color-for-slice (function int float int int int matrix none))
|
||||
(define-extern part-hud-health-01-func (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern part-hud-health-02-func (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern part-hud-health-03-func (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern fuel-cell-hud-orbit-callback (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern fuel-cell-hud-starburst-3-callback (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern fuel-cell-hud-starburst-4-callback (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern fuel-cell-hud-center-callback (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern part-hud-buzzer-func (function basic basic hud-particle none))
|
||||
(define-extern part-hud-eco-timer-01-func (function basic basic hud-particle none))
|
||||
(define-extern part-hud-eco-timer-02-func (function basic basic hud-particle none))
|
||||
(define-extern part-hud-eco-timer-03-func (function basic basic hud-particle none))
|
||||
(define-extern part-hud-eco-timer-backing-func (function basic basic hud-particle none))
|
||||
(define-extern part-hud-eco-timer-func (function basic basic hud-particle none))
|
||||
(define-extern part-hud-buzzer-func (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern part-hud-eco-timer-01-func (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern part-hud-eco-timer-02-func (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern part-hud-eco-timer-03-func (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern part-hud-eco-timer-backing-func (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern part-hud-eco-timer-func (function sparticle-system sparticle-cpuinfo matrix none))
|
||||
(define-extern show-hud (function none))
|
||||
|
||||
;; - Unknowns
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
// run the first pass of the decompiler
|
||||
"find_functions": true,
|
||||
|
||||
// will attempt to run the decompiled output through the OpenGOAL formatter
|
||||
// this will be skipped in offline tests
|
||||
"format_code": true,
|
||||
|
||||
////////////////////////////
|
||||
// DATA ANALYSIS OPTIONS
|
||||
////////////////////////////
|
||||
@@ -118,6 +122,9 @@
|
||||
// save game textures as .png files to decompiler_out/<game>/textures
|
||||
"save_texture_pngs": false,
|
||||
|
||||
// whether or not to dump out streamed audio files to decompiler_out/<game>/audio
|
||||
"rip_streamed_audio": false,
|
||||
|
||||
////////////////////////////
|
||||
// PATCHING OPTIONS
|
||||
////////////////////////////
|
||||
|
||||
@@ -634,7 +634,7 @@
|
||||
|
||||
// there are some missing textures. I don't know what the game actually does here.
|
||||
// the format for entries is [level, tpage, index]
|
||||
"missing_textures": [["finalboss-vis", 1419, 3]],
|
||||
"missing_textures": [["finalboss", 1419, 3]],
|
||||
|
||||
// some object files have garbage pad data at the end which makes the decompiler
|
||||
// assume they must be different files, such as the art group for orb-cache-top.
|
||||
|
||||
@@ -258,10 +258,6 @@
|
||||
"TEXT/6COMMON.TXT"
|
||||
],
|
||||
|
||||
// uncomment the next line to extract audio to wave files.
|
||||
//"audio_dir_file_name": "jak1/VAG",
|
||||
"audio_dir_file_name": "",
|
||||
|
||||
"streamed_audio_file_names": [
|
||||
"VAGWAD.ENG",
|
||||
"VAGWAD.FRE",
|
||||
|
||||
@@ -228,9 +228,5 @@
|
||||
"TEXT/6COMMON.TXT"
|
||||
],
|
||||
|
||||
// uncomment the next line to extract audio to wave files.
|
||||
//"audio_dir_file_name": "jak1/VAG",
|
||||
"audio_dir_file_name": "",
|
||||
|
||||
"streamed_audio_file_names": ["VAGWAD.ENG", "VAGWAD.JAP"]
|
||||
}
|
||||
@@ -2515,6 +2515,7 @@
|
||||
(iop-mem 48)
|
||||
(cancel-dgo 49)
|
||||
(set-stereo-mode 50) ;; sound-rpc-set-stereo-mode
|
||||
(set-mirror 201)
|
||||
)
|
||||
|
||||
(defenum sound-group
|
||||
@@ -2829,6 +2830,17 @@
|
||||
:flag-assert #x900000004
|
||||
)
|
||||
|
||||
; added
|
||||
(defenum sound-mirror-mode
|
||||
:type uint8
|
||||
(normal)
|
||||
(mirrored)
|
||||
)
|
||||
|
||||
; added for mirror mode
|
||||
(deftype sound-rpc-set-mirror-mode (sound-rpc-cmd)
|
||||
((mirror sound-mirror-mode)))
|
||||
|
||||
(deftype sound-rpc-union (structure)
|
||||
((data uint32 20 :offset-assert 0)
|
||||
(load-bank sound-rpc-load-bank :offset 0)
|
||||
@@ -2852,6 +2864,7 @@
|
||||
(shutdown sound-rpc-shutdown :offset 0)
|
||||
(list-sounds sound-rpc-list-sounds :offset 0)
|
||||
(unload-music sound-rpc-unload-music :offset 0)
|
||||
(mirror-mode sound-rpc-set-mirror-mode :overlay-at (-> data 0))
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x50
|
||||
@@ -8774,6 +8787,7 @@ Unlike [[engine]], users can use [[engine-pers]] as a parent class."
|
||||
(progress-graphics-ps2-lod-dist #x1337)
|
||||
(progress-graphics-msaa-off #x1338)
|
||||
(progress-graphics-display #x1339)
|
||||
(language-name-finnish #x133a)
|
||||
)
|
||||
;; ---text-id-h:text-id
|
||||
|
||||
|
||||
@@ -127,6 +127,9 @@
|
||||
"rip_collision": false,
|
||||
// save game textures as .png files to decompiler_out/<game>/textures
|
||||
"save_texture_pngs": false,
|
||||
|
||||
// whether or not to dump out streamed audio files to decompiler_out/<game>/audio
|
||||
"rip_streamed_audio": false,
|
||||
|
||||
////////////////////////////
|
||||
// PATCHING OPTIONS
|
||||
|
||||
@@ -769,7 +769,7 @@
|
||||
// there are some missing textures. I don't know what the game actually does here.
|
||||
// the format for entries is [level, tpage, index]
|
||||
"missing_textures": [
|
||||
["vinroom-vis", 0, 0],
|
||||
["vinroom", 0, 0],
|
||||
["ctyfence", 0, 0]
|
||||
],
|
||||
|
||||
|
||||
@@ -441,10 +441,6 @@
|
||||
"TEXT/7COMMON.TXT"
|
||||
],
|
||||
|
||||
// uncomment the next line to extract audio to wave files.
|
||||
// "audio_dir_file_name": "jak2/VAG",
|
||||
"audio_dir_file_name": "",
|
||||
|
||||
"streamed_audio_file_names": [
|
||||
"VAGWAD.ENG",
|
||||
"VAGWAD.FRE",
|
||||
|
||||
+15417
-15350
File diff suppressed because it is too large.
Load diff
@@ -109,7 +109,7 @@
|
||||
|
||||
// optional: a predetermined object file name map from a file.
|
||||
// this will make decompilation naming consistent even if you only run on some objects.
|
||||
"obj_file_name_map_file": "goal_src/jak3/build/all_objs.json",
|
||||
// "obj_file_name_map_file": "goal_src/jak3/build/all_objs.json",
|
||||
|
||||
////////////////////////////
|
||||
// LEVEL EXTRACTION
|
||||
@@ -121,12 +121,15 @@
|
||||
"rip_levels": false,
|
||||
// should we also extract collision meshes to the .fr3 files?
|
||||
// these can be displayed in-game with the OpenGOAL collision renderer
|
||||
"extract_collision": false,
|
||||
"extract_collision": true,
|
||||
// turn this on if you want extracted level collision to be saved as .obj files in debug_out/<game>
|
||||
"rip_collision": false,
|
||||
// save game textures as .png files to decompiler_out/<game>/textures
|
||||
"save_texture_pngs": false,
|
||||
|
||||
// whether or not to dump out streamed audio files to decompiler_out/<game>/audio
|
||||
"rip_streamed_audio": false,
|
||||
|
||||
////////////////////////////
|
||||
// PATCHING OPTIONS
|
||||
////////////////////////////
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
[7, "(function none)"],
|
||||
[3, "(function symbol :behavior process)"]
|
||||
],
|
||||
"scene": [[4, "(function none :behavior scene-player)"]],
|
||||
"scene": [[4, "(function symbol :behavior scene-player)"]],
|
||||
"pov-camera": [
|
||||
[
|
||||
7,
|
||||
@@ -545,5 +545,460 @@
|
||||
[107, "(function script-context object)"],
|
||||
[108, "(function script-context object)"]
|
||||
],
|
||||
"relocate": [[7, "(function sparticle-system sparticle-cpuinfo none)"]]
|
||||
"relocate": [[7, "(function sparticle-system sparticle-cpuinfo none)"]],
|
||||
"target-mech": [
|
||||
[7, "(function object :behavior target)"],
|
||||
[8, "(function object :behavior target)"],
|
||||
[9, "(function object :behavior target)"],
|
||||
[18, "(function surface surface surface int object :behavior target)"],
|
||||
[19, "(function surface surface surface int object :behavior target)"]
|
||||
],
|
||||
"mech-states": [[57, "(function object :behavior target)"]],
|
||||
"target-flut": [
|
||||
[14, "(function surface surface surface int object :behavior target)"],
|
||||
[20, "(function object :behavior target)"],
|
||||
[21, "(function object :behavior target)"],
|
||||
[33, "(function process-focusable object)"],
|
||||
[72, "(function object)"],
|
||||
[73, "(function object :behavior target)"],
|
||||
[74, "(function object :behavior target)"]
|
||||
],
|
||||
"nav-control": [
|
||||
[0, "(function object nav-control none)"],
|
||||
[1, "(function object nav-control none)"],
|
||||
[2, "(function object nav-control none)"],
|
||||
[3, "(function object nav-control none)"],
|
||||
[4, "(function object nav-control none)"],
|
||||
[5, "(function object nav-control none)"],
|
||||
[6, "(function object nav-control none)"],
|
||||
[7, "(function object nav-control none)"],
|
||||
[8, "(function object nav-control none)"],
|
||||
[9, "(function object nav-control none)"]
|
||||
],
|
||||
"nav-enemy": [[7, "(function enemy-jump-info none :behavior nav-enemy)"]],
|
||||
"task-control": [
|
||||
[53, "(function game-task-node-info symbol object)"],
|
||||
[54, "(function game-task-node-info object)"],
|
||||
[67, "(function pair symbol)"]
|
||||
],
|
||||
"merc-death": [[3, "(function time-frame :behavior process-drawable)"]],
|
||||
"vehicle-states": [
|
||||
[10, "(function collide-shape-prim none)"],
|
||||
[12, "(function collide-shape-prim none)"]
|
||||
],
|
||||
"prebot-states": [[21, "(function vector :behavior prebot)"]],
|
||||
"wasall-obs": [
|
||||
[0, "(function object)"],
|
||||
[1, "(function object)"],
|
||||
[2, "(function object)"],
|
||||
[3, "(function object)"]
|
||||
],
|
||||
"roboguard": [
|
||||
[1, "(function cspace transformq none)"],
|
||||
[2, "(function cspace transformq none)"],
|
||||
[25, "(function int int float object :behavior roboguard)"],
|
||||
[45, "(function roboguard symbol object)"]
|
||||
],
|
||||
"vehicle": [
|
||||
[6, "(function collide-shape-prim none)"],
|
||||
[7, "(function collide-shape-prim none)"]
|
||||
],
|
||||
"wvehicle-wheel": [
|
||||
[7, "(function collide-shape-prim none)"],
|
||||
[11, "(function collide-shape-prim none)"],
|
||||
[17, "(function collide-shape-prim none)"]
|
||||
],
|
||||
"wvehicle-states": [
|
||||
[20, "(function collide-shape-prim none)"],
|
||||
[22, "(function collide-shape-prim none)"]
|
||||
],
|
||||
"wvehicle": [[6, "(function collide-shape-prim none)"]],
|
||||
"pilot-states": [
|
||||
[15, "(function surface surface surface int object :behavior target)"]
|
||||
],
|
||||
"was-squad-control": [[16, "(function object object)"]],
|
||||
"des-cactus": [[13, "(function collide-shape-prim none)"]],
|
||||
"desertg-obs": [
|
||||
[4, "(function collide-shape-prim none)"],
|
||||
[7, "(function collide-shape-prim none)"]
|
||||
],
|
||||
"desertf-obs": [[7, "(function none)"]],
|
||||
"temple-obs2": [
|
||||
[43, "(function symbol)"],
|
||||
[46, "(function object :behavior tpl-watcher)"]
|
||||
],
|
||||
"temple-scenes": [
|
||||
[0, "(function none)"],
|
||||
[1, "(function none)"],
|
||||
[2, "(function none)"],
|
||||
[3, "(function none :behavior scene-player)"],
|
||||
[4, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"des-beast-2": [
|
||||
[1, "(function cspace transformq none)"],
|
||||
[2, "(function cspace transformq none)"],
|
||||
[23, "(function projectile none)"]
|
||||
],
|
||||
"scorpion-gun": [
|
||||
[33, "(function cspace transformq none)"],
|
||||
[34, "(function cspace transformq none)"]
|
||||
],
|
||||
"hover-formation": [
|
||||
[10, "(function form-search-info float)"],
|
||||
[11, "(function int int form-search-info uint)"],
|
||||
[14, "(function vector object)"],
|
||||
[15, "(function int int (pointer object) int)"]
|
||||
],
|
||||
"robo-hover": [
|
||||
[14, "(function robo-hover cspace float float vector vector int object)"]
|
||||
],
|
||||
"tower-scenes": [
|
||||
[0, "(function none :behavior scene-player)"],
|
||||
[1, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"forest-kill-plants": [
|
||||
[5, "(function engine-pers connection-pers object object symbol)"],
|
||||
[7, "(function engine-pers connection-pers object object symbol)"]
|
||||
],
|
||||
"forest-tasks": [
|
||||
[0, "(function none :behavior scene-player)"],
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"],
|
||||
[3, "(function none :behavior scene-player)"],
|
||||
[4, "(function none :behavior scene-player)"],
|
||||
[5, "(function none :behavior scene-player)"],
|
||||
[6, "(function none :behavior scene-player)"],
|
||||
[7, "(function none :behavior scene-player)"],
|
||||
[8, "(function none :behavior scene-player)"],
|
||||
[9, "(function none :behavior scene-player)"],
|
||||
[10, "(function none :behavior scene-player)"],
|
||||
[11, "(function none :behavior scene-player)"],
|
||||
[12, "(function none :behavior scene-player)"],
|
||||
[13, "(function none :behavior scene-player)"],
|
||||
[14, "(function none :behavior scene-player)"],
|
||||
[15, "(function none :behavior scene-player)"],
|
||||
[16, "(function none :behavior scene-player)"],
|
||||
[17, "(function none :behavior scene-player)"],
|
||||
[18, "(function none :behavior scene-player)"],
|
||||
[19, "(function none :behavior scene-player)"],
|
||||
[20, "(function none :behavior scene-player)"],
|
||||
[21, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"neo-wasp": [[15, "(function neo-wasp cspace transformq float float none)"]],
|
||||
"for-turret": [
|
||||
[1, "(function cspace transformq none)"],
|
||||
[2, "(function cspace transformq none)"],
|
||||
[3, "(function cspace transformq none)"],
|
||||
[4, "(function cspace transformq none)"]
|
||||
],
|
||||
"volcano-obs": [[38, "(function cspace transformq none)"]],
|
||||
"spiky-frog": [[9, "(function cspace transformq none)"]],
|
||||
"volcano-scenes": [
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"mantis": [
|
||||
[8, "(function mantis vector float int vector vector)"],
|
||||
[15, "(function mantis collide-shape-moving vector symbol)"]
|
||||
],
|
||||
"wcar-faccar": [[9, "(function handle object :behavior process)"]],
|
||||
"wasstadb-obs": [[5, "(function object)"]],
|
||||
"arena-scenes": [
|
||||
[0, "(function none :behavior scene-player)"],
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"],
|
||||
[3, "(function none :behavior scene-player)"],
|
||||
[4, "(function none :behavior scene-player)"],
|
||||
[5, "(function none :behavior scene-player)"],
|
||||
[6, "(function none :behavior scene-player)"],
|
||||
[7, "(function none :behavior scene-player)"],
|
||||
[8, "(function none :behavior scene-player)"],
|
||||
[9, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"traffic-engine": [
|
||||
[24, "(function traffic-find-segment-struct nav-segment none)"]
|
||||
],
|
||||
"desert-scenes": [
|
||||
[5, "(function none :behavior scene-player)"],
|
||||
[6, "(function none :behavior scene-player)"],
|
||||
[7, "(function none :behavior scene-player)"],
|
||||
[8, "(function none :behavior scene-player)"],
|
||||
[9, "(function none :behavior scene-player)"],
|
||||
[10, "(function none :behavior scene-player)"],
|
||||
[11, "(function none :behavior scene-player)"],
|
||||
[12, "(function none :behavior scene-player)"],
|
||||
[13, "(function none :behavior scene-player)"],
|
||||
[14, "(function none :behavior scene-player)"],
|
||||
[15, "(function none :behavior scene-player)"],
|
||||
[16, "(function none :behavior scene-player)"],
|
||||
[17, "(function none :behavior scene-player)"],
|
||||
[18, "(function none :behavior scene-player)"],
|
||||
[19, "(function none :behavior scene-player)"],
|
||||
[20, "(function none :behavior scene-player)"],
|
||||
[21, "(function none :behavior scene-player)"],
|
||||
[22, "(function none :behavior scene-player)"],
|
||||
[23, "(function none :behavior scene-player)"],
|
||||
[24, "(function none :behavior scene-player)"],
|
||||
[25, "(function none :behavior scene-player)"],
|
||||
[26, "(function none :behavior scene-player)"],
|
||||
[27, "(function none :behavior scene-player)"],
|
||||
[28, "(function none :behavior scene-player)"],
|
||||
[29, "(function none :behavior scene-player)"],
|
||||
[30, "(function none :behavior scene-player)"],
|
||||
[31, "(function none :behavior scene-player)"],
|
||||
[32, "(function none :behavior scene-player)"],
|
||||
[33, "(function none :behavior scene-player)"],
|
||||
[34, "(function none :behavior scene-player)"],
|
||||
[35, "(function none :behavior scene-player)"],
|
||||
[36, "(function symbol :behavior scene-player)"]
|
||||
],
|
||||
"throne-scenes": [[0, "(function none :behavior scene-player)"]],
|
||||
"terraformer-setup": [[38, "(function object :behavior manipy)"]],
|
||||
"mined-scenes": [
|
||||
[6, "(function none :behavior scene-player)"],
|
||||
[7, "(function process-drawable vector none :behavior scene-player)"],
|
||||
[8, "(function process-drawable vector none :behavior scene-player)"]
|
||||
],
|
||||
"wasteland-scenes": [
|
||||
[0, "(function none :behavior scene-player)"],
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"],
|
||||
[3, "(function none :behavior scene-player)"],
|
||||
[4, "(function none :behavior scene-player)"],
|
||||
[5, "(function none :behavior scene-player)"],
|
||||
[6, "(function none :behavior scene-player)"],
|
||||
[7, "(function none :behavior scene-player)"],
|
||||
[8, "(function none :behavior scene-player)"],
|
||||
[9, "(function none :behavior scene-player)"],
|
||||
[10, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"wasdoors-scenes": [[2, "(function none :behavior scene-player)"]],
|
||||
"wasdef-manager": [
|
||||
[7, "(function process-tree object)"],
|
||||
[8, "(function process-tree object)"],
|
||||
[9, "(function process-tree object)"]
|
||||
],
|
||||
"des-burning-bush": [[37, "(function symbol)"]],
|
||||
"mh-wasp": [
|
||||
[9, "(function mh-wasp cspace float float vector vector int none)"]
|
||||
],
|
||||
"mh-bat": [
|
||||
[1, "(function cspace transformq none)"],
|
||||
[21, "(function object :behavior mh-bat)"],
|
||||
[26, "(function object :behavior mh-bat)"],
|
||||
[30, "(function object :behavior mh-bat)"],
|
||||
[34, "(function object :behavior mh-bat)"],
|
||||
[39, "(function object :behavior mh-bat)"]
|
||||
],
|
||||
"factoryc-obs2": [
|
||||
[67, "(function (pointer joint-exploder) :behavior fac-break-floor)"]
|
||||
],
|
||||
"factory-scenes": [
|
||||
[0, "(function none :behavior scene-player)"],
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"],
|
||||
[3, "(function none :behavior scene-player)"],
|
||||
[4, "(function none :behavior scene-player)"],
|
||||
[5, "(function none :behavior scene-player)"],
|
||||
[6, "(function none :behavior scene-player)"],
|
||||
[7, "(function none :behavior scene-player)"],
|
||||
[8, "(function none :behavior scene-player)"],
|
||||
[9, "(function none :behavior scene-player)"],
|
||||
[10, "(function process-drawable none :behavior scene-player)"],
|
||||
[11, "(function none :behavior scene-player)"],
|
||||
[12, "(function none :behavior scene-player)"],
|
||||
[13, "(function none :behavior scene-player)"],
|
||||
[14, "(function none :behavior scene-player)"],
|
||||
[15, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"factory-boss-setup": [[37, "(function object :behavior manipy)"]],
|
||||
"factory-boss-scenes": [
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"bot": [[25, "(function gui-connection symbol :behavior bot)"]],
|
||||
"oasis-defense": [
|
||||
[4, "(function collide-shape-prim none)"],
|
||||
[11, "(function collide-shape-prim none)"]
|
||||
],
|
||||
"ash-oasis-course": [
|
||||
[0, "(function ashelin-oasis object)"],
|
||||
[1, "(function ashelin-oasis object)"],
|
||||
[2, "(function asht-wait-spot ashelin-oasis object)"],
|
||||
[3, "(function ashelin-oasis symbol)"]
|
||||
],
|
||||
"comb-obs": [
|
||||
[16, "(function collide-shape-prim none)"],
|
||||
[33, "(function collide-shape-prim none)"],
|
||||
[49, "(function collide-shape-prim none)"]
|
||||
],
|
||||
"comb-sentry": [[19, "(function collide-shape-prim none)"]],
|
||||
"comb-field": [[5, "(function symbol)"]],
|
||||
"comb-scenes": [
|
||||
[0, "(function none :behavior scene-player)"],
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"],
|
||||
[3, "(function none :behavior scene-player)"],
|
||||
[4, "(function none :behavior scene-player)"],
|
||||
[5, "(function none :behavior scene-player)"],
|
||||
[6, "(function none :behavior scene-player)"],
|
||||
[7, "(function none :behavior scene-player)"],
|
||||
[8, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"railx-scenes": [
|
||||
[0, "(function none :behavior scene-player)"],
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"],
|
||||
[3, "(function none :behavior scene-player)"],
|
||||
[4, "(function none :behavior scene-player)"],
|
||||
[5, "(function none :behavior scene-player)"],
|
||||
[6, "(function none :behavior scene-player)"],
|
||||
[7, "(function none :behavior scene-player)"],
|
||||
[8, "(function none :behavior scene-player)"],
|
||||
[9, "(function none :behavior scene-player)"],
|
||||
[10, "(function none :behavior scene-player)"],
|
||||
[11, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"title-obs": [
|
||||
[20, "(function external-art-buffer int)"],
|
||||
[22, "(function game-task object)"],
|
||||
[26, "(function vector :behavior manipy)"],
|
||||
[30, "(function object :behavior manipy)"]
|
||||
],
|
||||
"ff-squad-control": [
|
||||
[6, "(function process-focusable traffic-object-type-info none)"],
|
||||
[7, "(function process-focusable traffic-object-type-info none)"],
|
||||
[8, "(function process-focusable traffic-object-type-info none)"],
|
||||
[9, "(function crimson-guard traffic-object-type-info none)"]
|
||||
],
|
||||
"guard": [
|
||||
[31, "(function crimson-guard collide-shape vector symbol)"],
|
||||
[49, "(function process city-attacker-info int)"]
|
||||
],
|
||||
"guard-tazer": [
|
||||
[7, "(function collide-shape-prim none)"],
|
||||
[13, "(function collide-shape-prim none)"]
|
||||
],
|
||||
"roboguard-city": [
|
||||
[13, "(function cspace transformq none)"],
|
||||
[78, "(function roboguard-city symbol quaternion :behavior process)"]
|
||||
],
|
||||
"ctywide-obs": [[93, "(function symbol)"]],
|
||||
"ctywide-scenes": [
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"],
|
||||
[3, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"ctyport-obs": [[5, "(function collide-shape-prim none)"]],
|
||||
"ctyport-scenes": [
|
||||
[3, "(function none :behavior scene-player)"],
|
||||
[4, "(function none :behavior scene-player)"],
|
||||
[5, "(function none :behavior scene-player)"],
|
||||
[6, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"ctyport-attack": [[45, "(function object :behavior process)"]],
|
||||
"intro-scenes": [
|
||||
[0, "(function none :behavior scene-player)"],
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"],
|
||||
[3, "(function none :behavior scene-player)"],
|
||||
[4, "(function none :behavior scene-player)"],
|
||||
[5, "(function none :behavior scene-player)"],
|
||||
[6, "(function none :behavior scene-player)"],
|
||||
[7, "(function none :behavior scene-player)"],
|
||||
[8, "(function none :behavior scene-player)"],
|
||||
[9, "(function none :behavior scene-player)"],
|
||||
[10, "(function none :behavior scene-player)"],
|
||||
[11, "(function none :behavior scene-player)"],
|
||||
[12, "(function none :behavior scene-player)"],
|
||||
[13, "(function none :behavior scene-player)"],
|
||||
[14, "(function none :behavior scene-player)"],
|
||||
[15, "(function none :behavior scene-player)"],
|
||||
[16, "(function none :behavior scene-player)"],
|
||||
[17, "(function none :behavior scene-player)"],
|
||||
[18, "(function none :behavior scene-player)"],
|
||||
[19, "(function none :behavior scene-player)"],
|
||||
[20, "(function none :behavior scene-player)"],
|
||||
[21, "(function none :behavior scene-player)"],
|
||||
[22, "(function none :behavior scene-player)"],
|
||||
[23, "(function none :behavior scene-player)"],
|
||||
[24, "(function none :behavior scene-player)"],
|
||||
[25, "(function none :behavior scene-player)"],
|
||||
[26, "(function none :behavior scene-player)"],
|
||||
[27, "(function none :behavior scene-player)"],
|
||||
[28, "(function none :behavior scene-player)"],
|
||||
[29, "(function none :behavior scene-player)"],
|
||||
[30, "(function none :behavior scene-player)"],
|
||||
[31, "(function none :behavior scene-player)"],
|
||||
[32, "(function none :behavior scene-player)"],
|
||||
[33, "(function none :behavior scene-player)"],
|
||||
[34, "(function none :behavior scene-player)"],
|
||||
[35, "(function none :behavior scene-player)"],
|
||||
[36, "(function none :behavior scene-player)"],
|
||||
[37, "(function none :behavior scene-player)"],
|
||||
[38, "(function none :behavior scene-player)"],
|
||||
[39, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"freehq-scenes": [[0, "(function none :behavior scene-player)"]],
|
||||
"hiphog-scenes": [
|
||||
[0, "(function none :behavior scene-player)"],
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"],
|
||||
[3, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"rubble-attack": [[7, "(function int)"]],
|
||||
"rublcst-scenes": [
|
||||
[0, "(function none :behavior scene-player)"],
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"],
|
||||
[3, "(function none :behavior scene-player)"],
|
||||
[4, "(function none :behavior scene-player)"],
|
||||
[5, "(function none :behavior scene-player)"],
|
||||
[6, "(function none :behavior scene-player)"],
|
||||
[7, "(function none :behavior scene-player)"],
|
||||
[8, "(function none :behavior scene-player)"],
|
||||
[9, "(function none :behavior scene-player)"],
|
||||
[10, "(function none :behavior scene-player)"],
|
||||
[11, "(function none :behavior scene-player)"],
|
||||
[12, "(function none :behavior scene-player)"],
|
||||
[13, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"vinroom-scenes": [
|
||||
[0, "(function none :behavior scene-player)"],
|
||||
[1, "(function none :behavior scene-player)"]
|
||||
],
|
||||
"gungame-manager": [[6, "(function process symbol)"]],
|
||||
"blow-tower-obs2": [
|
||||
[16, "(function bt-mh-flyer cspace float float vector vector int none)"],
|
||||
[117, "(function bt-roboguard symbol quaternion)"],
|
||||
[124, "(function cspace transformq none)"]
|
||||
],
|
||||
"cty-blow-tower": [
|
||||
[39, "(function collide-shape-prim none)"],
|
||||
[27, "(function process symbol)"],
|
||||
[46, "(function collide-shape-prim none)"],
|
||||
[69, "(function process object)"]
|
||||
],
|
||||
"assault-enemies": [
|
||||
[36, "(function assault-crimson-guard city-attacker-info int)"]
|
||||
],
|
||||
"assault-task": [[11, "(function symbol :behavior process)"]],
|
||||
"precura-obs": [[98, "(function symbol :behavior process)"]],
|
||||
"precurd-scenes": [
|
||||
[0, "(function none :behavior scene-player)"],
|
||||
[1, "(function none :behavior scene-player)"],
|
||||
[2, "(function none :behavior scene-player)"],
|
||||
[3, "(function none :behavior scene-player)"],
|
||||
[4, "(function none :behavior scene-player)"],
|
||||
[5, "(function none :behavior scene-player)"],
|
||||
[6, "(function none :behavior scene-player)"],
|
||||
[7, "(function none :behavior scene-player)"],
|
||||
[8, "(function none :behavior scene-player)"],
|
||||
[9, "(function none :behavior scene-player)"],
|
||||
[10, "(function none :behavior scene-player)"],
|
||||
[11, "(function none :behavior scene-player)"],
|
||||
[12, "(function none :behavior scene-player)"],
|
||||
[13, "(function none :behavior scene-player)"],
|
||||
[14, "(function none :behavior scene-player)"]
|
||||
]
|
||||
}
|
||||
@@ -15,7 +15,31 @@
|
||||
"lightjak-shield": "jakb-ag",
|
||||
"freeze-screen": "collectables-ag",
|
||||
"red-3-sphere": "gun-ag",
|
||||
"gun-dark-3-sphere": "gun-ag"
|
||||
"gun-dark-3-sphere": "gun-ag",
|
||||
"marauder": "marauder-male-ag",
|
||||
"glider-ring": "des-glider-ring-ag",
|
||||
"flut-racer": "flut-wild-ag",
|
||||
"was-pre-heart": "neo-satellite-heart-ag",
|
||||
"was-pre-beam": "neo-satellite-game-ring-ag",
|
||||
"was-pre-bubble": "neo-satellite-ps-symbols-ag",
|
||||
"maker": "dm-robot-ag",
|
||||
"mh-wasp": "neo-wasp-ag",
|
||||
"factory-boss": "errol-lowres-ag",
|
||||
"fac-robotank-turret": "fac-robotank-ag",
|
||||
"neo-sat-shield": "neo-satellite-shield-ag",
|
||||
"neo-sat": "neo-satellite-ag",
|
||||
"power-game-switcher": "switcher-ag",
|
||||
"power-game-player": "daxter-pac-man-ag",
|
||||
"power-game-glyph": "cipher-ag",
|
||||
"power-game-rings": "pow-rings-ag",
|
||||
"power-game-chaser": "flitter-ag",
|
||||
"power-game-zapper": "grunt-head-ag",
|
||||
"gungame-door": "fort-entry-gate-ag",
|
||||
"bt-mh-flyer": "bt-wasp-ag",
|
||||
"gunship-exploder": "kg-robot-transport-break",
|
||||
"gunship-engine": "kg-robot-transport-bomb",
|
||||
"protect-gunship": "kg-robot-transport",
|
||||
"gunship-missile": "cty-homing-missile"
|
||||
},
|
||||
|
||||
// remap names for types in an entire file (higher priority)
|
||||
|
||||
@@ -78,10 +78,6 @@
|
||||
"blerc-execute",
|
||||
"foreground-check-longest-edge-asm",
|
||||
"generic-light-proc",
|
||||
"shadow-add-single-edges",
|
||||
"shadow-add-facing-single-tris",
|
||||
"shadow-add-double-tris",
|
||||
"shadow-add-double-edges",
|
||||
"(method 17 collide-edge-work)",
|
||||
"(method 10 collide-cache-prim)",
|
||||
"(method 17 collide-cache)",
|
||||
@@ -107,12 +103,6 @@
|
||||
// jak 3
|
||||
"(method 10 manipulator)",
|
||||
"(method 46 ff-squad-control)",
|
||||
"(anon-function 65 temple-obs)",
|
||||
"(method 33 task-manager-nest-cocoons)",
|
||||
"(method 33 rub-tower)",
|
||||
"(method 261 crimson-guard)",
|
||||
"(anon-function 25 volcanox-obs)",
|
||||
"foreground-draw-hud",
|
||||
"memcpy"
|
||||
],
|
||||
|
||||
@@ -220,7 +210,19 @@
|
||||
"borrow-city-expansion",
|
||||
"add-want-level",
|
||||
"level-find-borrow-slot",
|
||||
"(method 18 level)"
|
||||
"(method 18 level)",
|
||||
"(method 11 tow-tentacle)",
|
||||
"city-sound-expand-want-list",
|
||||
"(method 12 cty-borrow-manager)",
|
||||
"(method 16 cty-borrow-manager)",
|
||||
"mark-permanent-holds",
|
||||
"update-sound-info",
|
||||
"insert-into-sound-list",
|
||||
// title-obs
|
||||
"(anon-function 22 title-obs)",
|
||||
"cty-faction-evaluate-commands",
|
||||
"traffic-manager-event-handler",
|
||||
"(method 20 cty-faction-manager)"
|
||||
],
|
||||
|
||||
// If format is used with the wrong number of arguments,
|
||||
@@ -266,7 +268,8 @@
|
||||
"~10Hfg-wa: ~8,,0m": 1,
|
||||
"~140Hfg-sh: ~8,,0m": 1,
|
||||
"~267Hfg-p2: ~8,,0m~%": 1,
|
||||
"~30Hp2: ~8D~131Hhf: ~8D~%~1K": 2
|
||||
"~30Hp2: ~8D~131Hhf: ~8D~%~1K": 2,
|
||||
"Current time (~d:~d) [mission-percentage ~f~%": 2
|
||||
},
|
||||
|
||||
"blocks_ending_in_asm_branch": {
|
||||
@@ -385,7 +388,81 @@
|
||||
],
|
||||
"(method 16 sparticle-launch-control)": [25, 35, 36, 48, 62, 65, 100, 102],
|
||||
"(anon-function 17 target-ladder)": [0, 1],
|
||||
"command-get-process": [46]
|
||||
"command-get-process": [46],
|
||||
"foreground-draw-hud": [0, 7, 8, 9, 16, 22],
|
||||
"target-flut-falling-anim-trans": [8, 9],
|
||||
"(method 12 nav-mesh)": [0, 1, 2, 9],
|
||||
"(method 20 nav-mesh)": [9],
|
||||
"(method 21 nav-mesh)": [7],
|
||||
"(method 29 nav-mesh)": [0, 1, 2, 4],
|
||||
"(method 33 nav-mesh)": [10, 11, 12, 13],
|
||||
"(method 34 nav-mesh)": [0, 1, 2, 4],
|
||||
"(method 35 nav-mesh)": [0, 1, 2, 4],
|
||||
"(method 36 nav-mesh)": [1, 2],
|
||||
"(method 37 nav-mesh)": [4],
|
||||
"(method 45 nav-mesh)": [1, 2],
|
||||
"(method 46 nav-mesh)": [1, 2, 19, 20],
|
||||
"(method 48 nav-mesh)": [4, 5, 6, 8],
|
||||
"(method 49 nav-mesh)": [0, 1, 2, 3, 5],
|
||||
"(method 18 nav-control)": [11, 12, 19, 20, 31, 34],
|
||||
"(method 19 nav-control)": [9, 10],
|
||||
"(method 40 nav-state)": [1, 2],
|
||||
"point-poly-distance-min": [0, 1, 2, 3, 4, 5, 6, 7, 10],
|
||||
"find-closest-circle-ray-intersection": [0, 4, 15, 16, 17, 18],
|
||||
"(method 39 vehicle)": [0, 10, 12, 15],
|
||||
"(anon-function 7 vehicle-states)": [0, 2],
|
||||
"(method 11 vehicle-hud-requests)": [0, 6, 7, 10],
|
||||
"(anon-function 12 neo-juicer)": [29, 30],
|
||||
"(method 160 neo-grenadier)": [1, 2, 3],
|
||||
"(method 82 spydroid-orig)": [13],
|
||||
"(method 118 vehicle)": [3, 4, 7, 8, 9, 10, 17, 26, 30, 31, 33],
|
||||
"(method 25 squad-control)": [0, 4, 5, 7],
|
||||
"target-pilot-post": [0, 29],
|
||||
"(method 36 was-squad-control)": [0, 8, 14, 16],
|
||||
"(anon-function 6 nst-tasks)": [4, 9, 10, 16, 23, 30],
|
||||
"(method 33 task-manager-nest-cocoons)": [3, 7, 13, 28],
|
||||
"(method 90 wvehicle)": [29, 37, 38, 44],
|
||||
"(anon-function 2 artifact-race)": [40, 55, 56, 57, 65, 66],
|
||||
"(anon-function 27 course-race)": [6],
|
||||
"(anon-function 65 temple-obs)": [5, 6],
|
||||
"(anon-function 5 target-turret)": [0, 1, 2, 3],
|
||||
"dp-bipedal-consider-attacks": [15, 19],
|
||||
"(anon-function 25 volcanox-obs)": [3, 5, 6],
|
||||
"(method 36 task-manager-arena-fight-base)": [11],
|
||||
"(method 28 hud-wasgun)": [0, 1, 2, 4],
|
||||
"(method 15 hud-wasgun)": [8, 28, 29, 30, 54],
|
||||
"(method 15 vehicle-controller)": [0, 3, 5, 6, 7, 10],
|
||||
"(method 51 hvehicle)": [5],
|
||||
"(method 159 hvehicle)": [0, 1, 10, 19, 21, 23, 26],
|
||||
"(method 18 vehicle-controller)": [0, 1, 74, 75],
|
||||
"glider-too-low?": [2, 19, 21],
|
||||
"(method 39 task-manager-desert-glide)": [0, 3, 4, 9],
|
||||
"(method 36 task-manager-desert-glide)": [20, 50, 60],
|
||||
"(method 37 task-manager-desert-glide)": [11, 12, 23, 29, 31],
|
||||
"(method 34 task-manager-desert-glide)": [3],
|
||||
"(anon-function 20 target-flut)": [0, 38, 39],
|
||||
"(anon-function 14 flut-racer)": [7, 17, 19],
|
||||
"(method 28 conveyor)": [22],
|
||||
"generic-merc-execute-all": [7, 15],
|
||||
"check-enemy": [0, 1],
|
||||
"(method 91 h-warf)": [0],
|
||||
"(method 51 h-warf)": [5],
|
||||
"(method 44 nav-graph)": [0, 7, 8, 26, 34],
|
||||
"(method 15 city-level-info)": [0, 1, 2, 6, 7, 9, 11, 13],
|
||||
"(method 10 traffic-suppressor)": [0, 1, 2, 4],
|
||||
"(method 18 traffic-tracker)": [5, 6, 7, 8],
|
||||
"(method 21 traffic-tracker)": [0],
|
||||
"(method 9 cty-faction-manager)": [8],
|
||||
"(method 46 traffic-engine)": [0, 1, 2, 4],
|
||||
"(method 42 traffic-engine)": [6],
|
||||
"(method 17 traffic-manager)": [7, 19, 27, 28, 29, 30, 41],
|
||||
"(anon-function 10 guard-rifle)": [9],
|
||||
"(method 261 crimson-guard)": [52, 64],
|
||||
"(anon-function 13 metalhead-predator)": [24, 25],
|
||||
"(anon-function 90 ctywide-obs)": [4],
|
||||
"(anon-function 10 cty-sniper-turret)": [44],
|
||||
"(method 33 rub-tower)": [9, 10],
|
||||
"(method 30 gungame-manager)": [0, 4, 5, 7]
|
||||
},
|
||||
|
||||
// Sometimes the game might use format strings that are fetched dynamically,
|
||||
@@ -414,7 +491,94 @@
|
||||
"(method 10 menu-loading-option)": [[113, 1]],
|
||||
"(method 10 menu-icon-info-option)": [[150, 1]],
|
||||
"(method 17 hud-goal)": [[71, 0]],
|
||||
"(method 17 hud-miss)": [[71, 0]]
|
||||
"(method 17 hud-miss)": [[71, 0]],
|
||||
"(method 16 resetter)": [
|
||||
[68, 1],
|
||||
[101, 1],
|
||||
[130, 1]
|
||||
],
|
||||
"(method 32 task-manager-desert-turtle-training)": [[59, 1]],
|
||||
"(method 24 race-manager)": [[97, 1]],
|
||||
"(method 25 race-manager)": [
|
||||
[97, 1],
|
||||
[126, 1]
|
||||
],
|
||||
"(method 15 hud-race-final-stats)": [[131, 0]],
|
||||
"(method 15 hud-wasbbv-goal-time)": [[74, 0]],
|
||||
"(method 32 task-manager-lightjak-training)": [[53, 0]],
|
||||
"(method 18 hover-training-manager)": [[69, 0]],
|
||||
"(method 37 task-manager-arena-training)": [[67, 1]],
|
||||
"(method 15 hud-arena-final-stats)": [
|
||||
[103, 0],
|
||||
[147, 0]
|
||||
],
|
||||
"(method 35 task-manager-arena-fight-base)": [[53, 0]],
|
||||
"(method 32 task-manager-arena-gun-training)": [[53, 0]],
|
||||
"(method 26 task-manager-arena-fight-2)": [
|
||||
[72, 0],
|
||||
[186, 0]
|
||||
],
|
||||
"(method 37 task-manager-wascity-gungame)": [
|
||||
[48, 0],
|
||||
[78, 0],
|
||||
[119, 0],
|
||||
[157, 0],
|
||||
[195, 0],
|
||||
[227, 0],
|
||||
[268, 0],
|
||||
[306, 0],
|
||||
[338, 0],
|
||||
[379, 0],
|
||||
[411, 0],
|
||||
[446, 0]
|
||||
],
|
||||
"(method 30 was-pre-game)": [
|
||||
[184, 0],
|
||||
[276, 0]
|
||||
],
|
||||
"(method 32 task-manager-throne-gun-training)": [[53, 0]],
|
||||
"(method 17 hud-spider-killed)": [[71, 0]],
|
||||
"(trans idle des-burning-bush)": [
|
||||
[226, 1],
|
||||
[257, 0]
|
||||
],
|
||||
"(method 37 des-burning-bush)": [
|
||||
[278, 0],
|
||||
[336, 0]
|
||||
],
|
||||
"(method 38 des-burning-bush)": [
|
||||
[109, 0],
|
||||
[153, 0],
|
||||
[196, 0]
|
||||
],
|
||||
"(method 15 freeze-time-hud)": [[108, 0]],
|
||||
"(method 17 freeze-time-hud)": [[97, 0]],
|
||||
"(method 15 hud-wasbbv-score)": [[61, 0]],
|
||||
"(method 15 hud-wasbbv-goal)": [[64, 0]],
|
||||
"(method 32 task-manager-dark-punch-training)": [[53, 0]],
|
||||
"(method 32 task-manager-lightjak-training-shield)": [[53, 0]],
|
||||
"(trans credits highres-viewer-manager)": [[185, 0]],
|
||||
"(trans idle hirez-viewer)": [[356, 0]],
|
||||
"(trans idle burning-bush)": [
|
||||
[171, 1],
|
||||
[202, 0]
|
||||
],
|
||||
"(method 33 task-manager-bbush-board)": [[86, 0]],
|
||||
"(method 17 board-score-hud)": [[71, 0]],
|
||||
"(method 23 gungame-manager)": [
|
||||
[52, 0],
|
||||
[90, 0],
|
||||
[128, 0],
|
||||
[164, 0],
|
||||
[194, 0],
|
||||
[235, 0],
|
||||
[273, 0],
|
||||
[305, 0],
|
||||
[346, 0],
|
||||
[378, 0],
|
||||
[413, 0]
|
||||
],
|
||||
"(trans carry precur-bomb)": [[60, 0]]
|
||||
},
|
||||
|
||||
"mips2c_functions_by_name": [
|
||||
@@ -441,13 +605,14 @@
|
||||
"draw-large-polygon",
|
||||
"render-sky-quad",
|
||||
"render-sky-tri",
|
||||
"(method 16 sky-work)",
|
||||
"(method 17 sky-work)",
|
||||
"(method 18 sky-work)",
|
||||
"(method 32 sky-work)",
|
||||
"(method 33 sky-work)",
|
||||
// "(method 28 sky-work)",
|
||||
"(method 31 sky-work)",
|
||||
"(method 34 sky-work)",
|
||||
"(method 29 sky-work)",
|
||||
"(method 30 sky-work)",
|
||||
"(method 35 sky-work)",
|
||||
"(method 11 collide-hash)",
|
||||
"(method 12 collide-hash)",
|
||||
"fill-bg-using-box-new",
|
||||
@@ -543,9 +708,26 @@
|
||||
"(method 21 cloth-system)",
|
||||
"debug-line-clip?",
|
||||
"(method 9 font-work)",
|
||||
"(method 9 prim-strip)",
|
||||
"live-func-curve",
|
||||
"birth-func-curve"
|
||||
"birth-func-curve",
|
||||
"sparticle-motion-blur-dirt",
|
||||
"foreground-draw-hud",
|
||||
"shadow-execute",
|
||||
"shadow-add-double-edges",
|
||||
"shadow-add-single-edges",
|
||||
"shadow-add-facing-single-tris",
|
||||
"shadow-add-double-tris",
|
||||
"shadow-xform-verts",
|
||||
"shadow-calc-dual-verts",
|
||||
"shadow-scissor-edges",
|
||||
"shadow-scissor-top",
|
||||
"shadow-init-vars",
|
||||
"shadow-find-facing-single-tris",
|
||||
"shadow-find-single-edges",
|
||||
"shadow-find-facing-double-tris",
|
||||
"shadow-find-double-edges",
|
||||
"shadow-add-verts",
|
||||
"shadow-add-single-tris"
|
||||
],
|
||||
|
||||
"mips2c_jump_table_functions": {},
|
||||
@@ -562,7 +744,8 @@
|
||||
["intpfall", 0, 0],
|
||||
["lfaccity", 0, 0],
|
||||
["ltowcity", 0, 0],
|
||||
["powergd", 0, 0]
|
||||
["powergd", 0, 0],
|
||||
["lcitysml", 0, 0]
|
||||
],
|
||||
|
||||
// some object files have garbage pad data at the end which makes the decompiler
|
||||
|
||||
Loaded 100 of 2793 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user