mirror of
https://github.com/open-goal/jak-project.git
synced 2026-11-07 09:26:09 -10:00
Compare commits
75
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1979f94e45 | ||
|
|
ba8d4c2903 | ||
|
|
bfe0a72ae7 | ||
|
|
8d0d05717f | ||
|
|
398d2ee5e1 | ||
|
|
5fe4d12f70 | ||
|
|
4bd5111280 | ||
|
|
f045e6cef1 | ||
|
|
17f5f74238 | ||
|
|
9aa291313b | ||
|
|
6f0d0fa417 | ||
|
|
7ef2c2fac3 | ||
|
|
3eb6cfcb17 | ||
|
|
0236e36a53 | ||
|
|
0ea718a5ee | ||
|
|
3a2c57c091 | ||
|
|
b130c2f439 | ||
|
|
3dc27e37e5 | ||
|
|
d4c21c784f | ||
|
|
01d5fc2bbb | ||
|
|
638bf1d3d9 | ||
|
|
5ddf1e4b4d | ||
|
|
2bb1d53752 | ||
|
|
076f8aa6dd | ||
|
|
1c0038294f | ||
|
|
9a4929ac0c | ||
|
|
25c74f1740 | ||
|
|
272cb32a45 | ||
|
|
c3e4baf697 | ||
|
|
85039fe2d6 | ||
|
|
b06d63ba83 | ||
|
|
13f1aa1785 | ||
|
|
ba7b0397b1 | ||
|
|
4f537d4a71 | ||
|
|
ed6639ee60 | ||
|
|
1dba36c614 | ||
|
|
4101d5d80e | ||
|
|
07427799a6 | ||
|
|
637b043293 | ||
|
|
46db6a36da | ||
|
|
619f39d3b7 | ||
|
|
2071c98b55 | ||
|
|
7a8aa71204 | ||
|
|
a80cff9a4c | ||
|
|
4cccaf2645 | ||
|
|
9d680a0aba | ||
|
|
b0713641e7 | ||
|
|
aa68b80da2 | ||
|
|
6901e80e7f | ||
|
|
12118e57cb | ||
|
|
349919f788 | ||
|
|
a01d78c7d4 | ||
|
|
708c15788b | ||
|
|
6cfb89a78a | ||
|
|
99da5da441 | ||
|
|
c7af284c6b | ||
|
|
3e568cb95d | ||
|
|
4b9c1dde70 | ||
|
|
35daebcce7 | ||
|
|
897e9c588b | ||
|
|
f17427bc26 | ||
|
|
168afa0e2e | ||
|
|
9b6f16f561 | ||
|
|
1808596679 | ||
|
|
94b984326f | ||
|
|
2795d3aa67 | ||
|
|
be6a6dead4 | ||
|
|
974f5931de | ||
|
|
e119a66788 | ||
|
|
37069e2f8e | ||
|
|
dfa6622544 | ||
|
|
a3af37989b | ||
|
|
a01182315b | ||
|
|
e38fe70ac4 | ||
|
|
956645bdb9 |
No files matched your search
@@ -63,7 +63,7 @@ jobs:
|
||||
python ./scripts/docs/append-file-docs.py
|
||||
|
||||
- name: Upload Docs Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: opengoal-docs
|
||||
if-no-files-found: error
|
||||
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
strip ./build/lsp/lsp
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.uploadArtifacts }}
|
||||
with:
|
||||
name: opengoal-linux-${{ inputs.cachePrefix }}
|
||||
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
run: ./test.sh
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: opengoal-macos-${{ inputs.cachePrefix }}
|
||||
if-no-files-found: error
|
||||
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
strip ./build/lsp/lsp
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.uploadArtifacts }}
|
||||
with:
|
||||
name: opengoal-macos-${{ inputs.cachePrefix }}
|
||||
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
- name: Prepare Artifact Folder
|
||||
run: mkdir -p ./ci-artifacts/final
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
name: Download all Artifacts
|
||||
with:
|
||||
path: ./ci-artifacts/
|
||||
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
run: ./build/bin/goalc-test.exe --gtest_color=yes --gtest_brief=0 --gtest_filter="-*MANUAL_TEST*"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ inputs.uploadArtifacts }}
|
||||
with:
|
||||
name: opengoal-windows-${{ inputs.cachePrefix }}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
endOfLine: "auto"
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"endOfLine": "auto",
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/*.jsonc"],
|
||||
"options": {
|
||||
"parser": "json"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -68,6 +68,18 @@
|
||||
"jak2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "offline-test.exe (bin\\offline-test.exe)",
|
||||
"name": "Tests - Offline Tests - Jak 3",
|
||||
"args": [
|
||||
"--iso_data_path",
|
||||
"${workspaceRoot}/iso_data/jak3",
|
||||
"--game",
|
||||
"jak3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
@@ -218,6 +230,19 @@
|
||||
"--config-override \"{\\\"decompile_code\\\": false, \\\"levels_extract\\\": true, \\\"allowed_objects\\\": []}\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
"projectTarget": "decompiler.exe (bin\\decompiler.exe)",
|
||||
"name": "Decompiler - Jak 3",
|
||||
"args": [
|
||||
"${workspaceRoot}/decompiler/config/jak3/jak3_config.jsonc",
|
||||
"${workspaceRoot}/iso_data",
|
||||
"${workspaceRoot}/decompiler_out",
|
||||
"--version",
|
||||
"ntsc_v1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "default",
|
||||
"project": "CMakeLists.txt",
|
||||
|
||||
Vendored
+1
-1
@@ -5,7 +5,7 @@
|
||||
"comments": true,
|
||||
"strings": true
|
||||
},
|
||||
"editor.wordBasedSuggestions": true,
|
||||
"editor.wordBasedSuggestions": "matchingDocuments",
|
||||
"editor.snippetSuggestions": "top"
|
||||
},
|
||||
"python.formatting.provider": "black",
|
||||
|
||||
@@ -86,7 +86,6 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
-Wdisabled-optimization \
|
||||
-Wformat \
|
||||
-Wextra \
|
||||
-Wmissing-include-dirs \
|
||||
-Woverloaded-virtual \
|
||||
-Wredundant-decls \
|
||||
-Wshadow \
|
||||
@@ -113,7 +112,6 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
-Wdisabled-optimization \
|
||||
-Wformat \
|
||||
-Wextra \
|
||||
-Wmissing-include-dirs \
|
||||
-Woverloaded-virtual \
|
||||
-Wredundant-decls \
|
||||
-Wshadow \
|
||||
|
||||
@@ -108,6 +108,16 @@
|
||||
"description": "Build with Clang with Debug Symbols",
|
||||
"inherits": ["base-windows-debug", "base-clang"]
|
||||
},
|
||||
{
|
||||
"name": "Debug-windows-clang-static",
|
||||
"displayName": "Windows Static Debug (clang)",
|
||||
"description": "Build with Clang as Debug but statically linked",
|
||||
"inherits": ["base-windows-debug", "base-clang"],
|
||||
"cacheVariables": {
|
||||
"STATICALLY_LINK": "true",
|
||||
"ZYDIS_BUILD_SHARED_LIB": "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "RelWithDebInfo-windows-clang",
|
||||
"displayName": "Windows RelWithDebInfo (clang)",
|
||||
|
||||
+19
-14
@@ -74,16 +74,6 @@ tasks:
|
||||
msg: "Couldn't locate compiler executable in '{{.GOALC_BIN_RELEASE_DIR}}/goalc'"
|
||||
cmds:
|
||||
- "{{.GOALC_BIN_RELEASE_DIR}}/goalc --user-auto --game {{.GAME}}"
|
||||
format:
|
||||
desc: "Format code"
|
||||
cmds:
|
||||
- cmd: python ./scripts/cpp/format-includes.py
|
||||
- cmd: python ./third-party/run-clang-format/run-clang-format.py -r common decompiler game goalc test tools lsp -i
|
||||
# npm install -g prettier
|
||||
- cmd: npx prettier --write ./decompiler/config/jak1/**/*.jsonc
|
||||
ignore_error: true
|
||||
- cmd: npx prettier --write ./decompiler/config/jak2/**/*.jsonc
|
||||
ignore_error: true
|
||||
format-json:
|
||||
desc: "Format code"
|
||||
cmds:
|
||||
@@ -92,6 +82,14 @@ tasks:
|
||||
ignore_error: true
|
||||
- cmd: npx prettier --write ./decompiler/config/jak2/**/*.jsonc
|
||||
ignore_error: true
|
||||
- cmd: npx prettier --write ./decompiler/config/jak3/**/*.jsonc
|
||||
ignore_error: true
|
||||
format:
|
||||
desc: "Format code"
|
||||
cmds:
|
||||
- cmd: python ./scripts/cpp/format-includes.py
|
||||
- cmd: python ./third-party/run-clang-format/run-clang-format.py -r common decompiler game goalc test tools lsp -i
|
||||
- task: format-json
|
||||
# DECOMPILING
|
||||
decomp:
|
||||
cmds:
|
||||
@@ -116,6 +114,16 @@ tasks:
|
||||
- task: decomp-file
|
||||
- python ./scripts/gsrc/update-from-decomp.py --game "{{.GAME}}" --file {{.FILE}}
|
||||
- task: lint-gsrc-file
|
||||
# ASSET RIPPING
|
||||
rip-textures:
|
||||
cmds:
|
||||
- "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler \"./decompiler/config/{{.DECOMP_CONFIG}}\" \"./iso_data\" \"./decompiler_out\" --version \"{{.DECOMP_CONFIG_VERSION}}\" --config-override '{\"decompile_code\": false, \"levels_extract\": true, \"save_texture_pngs\": true}'"
|
||||
rip-levels:
|
||||
cmds:
|
||||
- "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler \"./decompiler/config/{{.DECOMP_CONFIG}}\" \"./iso_data\" \"./decompiler_out\" --version \"{{.DECOMP_CONFIG_VERSION}}\" --config-override '{\"decompile_code\": false, \"levels_extract\": true, \"rip_levels\": true}'"
|
||||
rip-collision:
|
||||
cmds:
|
||||
- "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler \"./decompiler/config/{{.DECOMP_CONFIG}}\" \"./iso_data\" \"./decompiler_out\" --version \"{{.DECOMP_CONFIG_VERSION}}\" --config-override '{\"decompile_code\": false, \"levels_extract\": true, \"extract_collision\": true, \"rip_collision\": true}'"
|
||||
# TOOLS
|
||||
analyze-ee-memory:
|
||||
cmds:
|
||||
@@ -166,9 +174,6 @@ tasks:
|
||||
ignore_error: true
|
||||
- python ./scripts/update_decomp_reference.py ./failures ./test/decompiler/reference/ --game {{.GAME}}
|
||||
- task: offline-test-file
|
||||
type-test-jak1:
|
||||
cmds:
|
||||
- cmd: '{{.GOALCTEST_BIN_RELEASE_DIR}}/goalc-test --gtest_brief=0 --gtest_filter="*Jak1TypeConsistency*" --gtest_break_on_failure'
|
||||
type-test:
|
||||
cmds:
|
||||
- cmd: '{{.GOALCTEST_BIN_RELEASE_DIR}}/goalc-test --gtest_brief=0 --gtest_filter="*Jak2TypeConsistency*" --gtest_break_on_failure'
|
||||
- cmd: '{{.GOALCTEST_BIN_RELEASE_DIR}}/goalc-test --gtest_brief=0 --gtest_filter="*{{.TYPE_CONSISTENCY_TEST_FILTER}}*" --gtest_break_on_failure'
|
||||
@@ -56,11 +56,14 @@ void write_wave_file(const std::vector<s16>& left_samples,
|
||||
writer.write_to_file(name);
|
||||
}
|
||||
|
||||
std::pair<std::vector<s16>, std::vector<s16>> decode_adpcm(BinaryReader& reader, const bool mono) {
|
||||
std::pair<std::vector<s16>, std::vector<s16>> decode_adpcm(BinaryReader& reader,
|
||||
const bool stereo) {
|
||||
std::vector<s16> left_samples;
|
||||
std::vector<s16> right_samples;
|
||||
s32 left_sample_prev[2] = {0, 0};
|
||||
s32 right_sample_prev[2] = {0, 0};
|
||||
bool first_left = true;
|
||||
bool first_right = true;
|
||||
constexpr s32 f1[5] = {0, 60, 115, 98, 122};
|
||||
constexpr s32 f2[5] = {0, 0, -52, -55, -60};
|
||||
|
||||
@@ -71,15 +74,29 @@ std::pair<std::vector<s16>, std::vector<s16>> decode_adpcm(BinaryReader& reader,
|
||||
// instead they are partitioned into contiguous 8kb (thats 8192 bytes) chunks
|
||||
// alternating left/right
|
||||
bool processing_left_chunk = true;
|
||||
// We need to skip the vag header for each channel
|
||||
if (first_left) {
|
||||
reader.ffwd(48);
|
||||
bytes_read += 48;
|
||||
first_left = false;
|
||||
}
|
||||
while (true) {
|
||||
if (!reader.bytes_left()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytes_read == 0x2000) {
|
||||
if (stereo && bytes_read == 0x2000) {
|
||||
// switch streams
|
||||
processing_left_chunk = !processing_left_chunk;
|
||||
bytes_read = 0;
|
||||
|
||||
// We need to skip the vag header for each channel
|
||||
if (first_right) {
|
||||
// skip the header
|
||||
reader.ffwd(48);
|
||||
bytes_read += 48;
|
||||
first_right = false;
|
||||
}
|
||||
}
|
||||
|
||||
u8 shift_filter = reader.read<u8>();
|
||||
@@ -107,7 +124,7 @@ std::pair<std::vector<s16>, std::vector<s16>> decode_adpcm(BinaryReader& reader,
|
||||
s32 sample = (s32)(s16)(nibble << 12);
|
||||
sample >>= shift;
|
||||
|
||||
if (mono || processing_left_chunk) {
|
||||
if (!stereo || processing_left_chunk) {
|
||||
sample += (left_sample_prev[0] * f1[filter] + left_sample_prev[1] * f2[filter] + 32) / 64;
|
||||
|
||||
if (sample > 0x7fff) {
|
||||
|
||||
@@ -42,6 +42,7 @@ void ShrubDraw::serialize(Serializer& ser) {
|
||||
ser.from_ptr(&num_triangles);
|
||||
ser.from_ptr(&first_index_index);
|
||||
ser.from_ptr(&num_indices);
|
||||
ser.from_ptr(&proto_idx);
|
||||
}
|
||||
|
||||
void InstancedStripDraw::serialize(Serializer& ser) {
|
||||
@@ -416,6 +417,9 @@ void ShrubTree::serialize(Serializer& ser) {
|
||||
for (auto& draw : static_draws) {
|
||||
draw.serialize(ser);
|
||||
}
|
||||
|
||||
ser.from_ptr(&has_per_proto_visibility_toggle);
|
||||
ser.from_string_vector(&proto_names);
|
||||
}
|
||||
|
||||
void BVH::serialize(Serializer& ser) {
|
||||
|
||||
@@ -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 = 38;
|
||||
constexpr int TFRAG3_VERSION = 39;
|
||||
|
||||
enum MemoryUsageCategory {
|
||||
TEXTURE,
|
||||
@@ -219,6 +219,8 @@ struct ShrubDraw {
|
||||
|
||||
// for debug counting.
|
||||
u32 num_triangles = 0;
|
||||
|
||||
u16 proto_idx = 0;
|
||||
void serialize(Serializer& ser);
|
||||
};
|
||||
|
||||
@@ -430,6 +432,10 @@ struct ShrubTree {
|
||||
std::vector<ShrubGpuVertex> vertices; // mesh vertices
|
||||
} unpacked;
|
||||
|
||||
// jak 2 and later can toggle on and off visibility per proto by name
|
||||
bool has_per_proto_visibility_toggle = false;
|
||||
std::vector<std::string> proto_names;
|
||||
|
||||
void serialize(Serializer& ser);
|
||||
void memory_usage(MemoryUsageTracker* tracker) const;
|
||||
void unpack();
|
||||
|
||||
@@ -67,8 +67,8 @@ void apply_formatting_config(
|
||||
//
|
||||
// Otherwise, we always default to a hang.
|
||||
//
|
||||
// NOTE - any modifications here to child elements could be superseeded later in the recursion
|
||||
// in order to maintain your sanity, only modify things here that _arent_ touched by default
|
||||
// NOTE - any modifications here to child elements could be superseeded later in the recursion!
|
||||
// In order to maintain your sanity, only modify things here that _arent_ touched by default
|
||||
// configurations. These are explicitly prepended with `parent_mutable_`
|
||||
if (!predefined_config) {
|
||||
if (curr_node.metadata.is_top_level) {
|
||||
@@ -104,6 +104,8 @@ void apply_formatting_config(
|
||||
}
|
||||
// If we are hanging, lets determine the indentation width since it is based on the form itself
|
||||
if (curr_node.formatting_config.hang_forms) {
|
||||
// TODO - this isn't being calculated for a pre-defined config
|
||||
// TODO - another idea is to do this during consolidation
|
||||
curr_node.formatting_config.indentation_width = hang_indentation_width(curr_node);
|
||||
}
|
||||
// iterate through the refs
|
||||
@@ -123,6 +125,7 @@ void apply_formatting_config(
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
@@ -191,17 +194,20 @@ bool can_node_be_inlined(const FormatterTreeNode& curr_node, int cursor_pos) {
|
||||
}
|
||||
|
||||
std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
|
||||
std::vector<std::string> output = {},
|
||||
std::vector<std::string> /*output*/ = {},
|
||||
int cursor_pos = 0) {
|
||||
using namespace formatter_rules;
|
||||
if (!curr_node.token && curr_node.refs.empty()) {
|
||||
// special case to handle an empty list
|
||||
if (curr_node.node_prefix) {
|
||||
return {fmt::format("{}()", curr_node.node_prefix.value())};
|
||||
}
|
||||
return {"()"};
|
||||
}
|
||||
|
||||
// If its a token, just print the token and move on
|
||||
if (curr_node.token) {
|
||||
return {curr_node.token.value()};
|
||||
return {curr_node.token_str()};
|
||||
}
|
||||
|
||||
bool inline_form = can_node_be_inlined(curr_node, cursor_pos);
|
||||
@@ -220,13 +226,19 @@ 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.value();
|
||||
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.value());
|
||||
val = comments::format_block_comment(ref.token_str());
|
||||
}
|
||||
form_lines.push_back(val);
|
||||
if (!curr_node.metadata.is_top_level && i == 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
|
||||
// line and do a new-line paren this is ugly, but we have no choice!
|
||||
form_lines.push_back("");
|
||||
}
|
||||
} else {
|
||||
// If it's not a token, we have to recursively build up the form
|
||||
// TODO - add the cursor_pos here
|
||||
@@ -250,6 +262,9 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
|
||||
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))) {
|
||||
// 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());
|
||||
i++;
|
||||
@@ -260,6 +275,10 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!curr_node.metadata.is_top_level && next_ref.metadata.node_type == "comment" &&
|
||||
(i + 1) == (int)curr_node.refs.size()) {
|
||||
form_lines.push_back("");
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we are at the top level, potential separate with a new line
|
||||
@@ -269,8 +288,12 @@ 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)) {
|
||||
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;
|
||||
for (int i = 0; i < (int)form_lines.size(); i++) {
|
||||
if (i < curr_node.formatting_config.inline_until_index(form_lines)) {
|
||||
if (new_form_lines.empty()) {
|
||||
@@ -279,7 +302,13 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
|
||||
new_form_lines.at(0) += fmt::format(" {}", form_lines.at(i));
|
||||
}
|
||||
} else {
|
||||
new_form_lines.push_back(form_lines.at(i));
|
||||
if (str_util::starts_with(form_lines.at(i), " ") && consolidating_lines) {
|
||||
new_form_lines.push_back(fmt::format(
|
||||
"{}{}", str_util::repeat(original_form_head_width, " "), form_lines.at(i)));
|
||||
} else {
|
||||
consolidating_lines = false;
|
||||
new_form_lines.push_back(form_lines.at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
form_lines = new_form_lines;
|
||||
@@ -288,6 +317,9 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
|
||||
// Apply necessary indentation to each line and add parens
|
||||
if (!curr_node.metadata.is_top_level) {
|
||||
std::string form_surround_start = "(";
|
||||
if (curr_node.node_prefix) {
|
||||
form_surround_start = fmt::format("{}(", curr_node.node_prefix.value());
|
||||
}
|
||||
std::string form_surround_end = ")";
|
||||
form_lines[0] = fmt::format("{}{}", form_surround_start, form_lines[0]);
|
||||
form_lines[form_lines.size() - 1] =
|
||||
|
||||
@@ -78,16 +78,24 @@ FormatterTree::FormatterTree(const std::string& source, const TSNode& root_node)
|
||||
construct_formatter_tree_recursive(source, root_node, root);
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, std::vector<std::string>> node_type_ignorable_contents = {
|
||||
{"list_lit", {"(", ")"}},
|
||||
{"quoting_lit", {"'"}},
|
||||
{"unquoting_lit", {","}},
|
||||
{"quasi_quoting_lit", {"`"}}};
|
||||
|
||||
// TODO make an imperative version eventually
|
||||
void FormatterTree::construct_formatter_tree_recursive(const std::string& source,
|
||||
TSNode curr_node,
|
||||
FormatterTreeNode& tree_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));
|
||||
return;
|
||||
}
|
||||
const std::string curr_node_type = ts_node_type(curr_node);
|
||||
FormatterTreeNode list_node;
|
||||
std::optional<std::string> next_node_prefix;
|
||||
if (curr_node_type == "list_lit") {
|
||||
list_node = FormatterTreeNode();
|
||||
} else if (curr_node_type == "str_lit") {
|
||||
@@ -97,22 +105,40 @@ 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") {
|
||||
// same story for quoted symbols
|
||||
// TODO - expect to have to add more here
|
||||
tree_node.refs.push_back(FormatterTreeNode(source, curr_node));
|
||||
return;
|
||||
next_node_prefix = "'";
|
||||
} else if (curr_node_type == "unquoting_lit") {
|
||||
next_node_prefix = ",";
|
||||
} else if (curr_node_type == "quasi_quoting_lit") {
|
||||
next_node_prefix = "`";
|
||||
}
|
||||
std::vector<std::string> skippable_nodes = {};
|
||||
if (node_type_ignorable_contents.find(curr_node_type) != node_type_ignorable_contents.end()) {
|
||||
skippable_nodes = node_type_ignorable_contents.at(curr_node_type);
|
||||
}
|
||||
for (size_t i = 0; i < ts_node_child_count(curr_node); i++) {
|
||||
const auto child_node = ts_node_child(curr_node, i);
|
||||
// We skip parens
|
||||
const auto contents = get_source_code(source, child_node);
|
||||
if (contents == "(" || contents == ")") {
|
||||
bool skip_node = false;
|
||||
for (const auto& skippable_content : skippable_nodes) {
|
||||
if (skippable_content == contents) {
|
||||
skip_node = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip_node) {
|
||||
continue;
|
||||
}
|
||||
if (curr_node_type == "list_lit") {
|
||||
construct_formatter_tree_recursive(source, child_node, list_node);
|
||||
construct_formatter_tree_recursive(source, child_node, list_node, next_node_prefix);
|
||||
if (node_prefix) {
|
||||
list_node.node_prefix = node_prefix;
|
||||
}
|
||||
} else {
|
||||
construct_formatter_tree_recursive(source, child_node, tree_node);
|
||||
construct_formatter_tree_recursive(source, child_node, tree_node, next_node_prefix);
|
||||
// TODO - im not sure if this is correct
|
||||
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") {
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
// we really care about is:
|
||||
// - getting all the text tokens for the source code
|
||||
// - having them in a proper, nested format
|
||||
// The treesitter format is complicated and highly nested, leading to some very hard to understand
|
||||
// code. So my solution is a 2-pass format.
|
||||
//
|
||||
// TLDR - The treesitter format is complicated and highly nested, leading to some very hard to
|
||||
// understand code. So my solution is atleast a 2-pass format.
|
||||
//
|
||||
// Pass 1 - convert the AST into a simplified FormatterTree
|
||||
// Pass 2 - use the simplified tree to output the final code
|
||||
@@ -37,8 +38,9 @@ class FormatterTreeNode {
|
||||
std::vector<FormatterTreeNode> refs;
|
||||
Metadata metadata;
|
||||
// The token is optional because list nodes do not contain a token, they just contain a bunch of
|
||||
// eventually token node refs
|
||||
// eventually-containing token node refs
|
||||
std::optional<std::string> token;
|
||||
std::optional<std::string> node_prefix;
|
||||
|
||||
formatter_rules::config::FormFormattingConfig formatting_config;
|
||||
|
||||
@@ -47,6 +49,15 @@ class FormatterTreeNode {
|
||||
FormatterTreeNode(const Metadata& _metadata) : metadata(_metadata){};
|
||||
|
||||
bool is_list() const { return !token.has_value(); }
|
||||
std::string token_str() const {
|
||||
if (node_prefix && token) {
|
||||
return node_prefix.value() + token.value();
|
||||
}
|
||||
if (token) {
|
||||
return token.value();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
// A FormatterTree has a very simple and crude tree structure where:
|
||||
@@ -62,5 +73,6 @@ class FormatterTree {
|
||||
private:
|
||||
void construct_formatter_tree_recursive(const std::string& source,
|
||||
TSNode curr_node,
|
||||
FormatterTreeNode& tree_node);
|
||||
FormatterTreeNode& tree_node,
|
||||
std::optional<std::string> node_prefix = {});
|
||||
};
|
||||
@@ -6,10 +6,17 @@ namespace formatter_rules {
|
||||
namespace config {
|
||||
|
||||
// TODO - this could be greatly simplified with C++20's designated initialization
|
||||
FormFormattingConfig new_permissive_flow_rule() {
|
||||
FormFormattingConfig cfg;
|
||||
cfg.hang_forms = false;
|
||||
cfg.combine_first_two_lines = true;
|
||||
return cfg;
|
||||
}
|
||||
|
||||
FormFormattingConfig new_flow_rule(int start_index) {
|
||||
FormFormattingConfig cfg;
|
||||
cfg.hang_forms = false;
|
||||
cfg.inline_until_index = [start_index](const std::vector<std::string>& curr_lines) {
|
||||
cfg.inline_until_index = [start_index](const std::vector<std::string>& /*curr_lines*/) {
|
||||
return start_index;
|
||||
};
|
||||
return cfg;
|
||||
@@ -80,6 +87,11 @@ const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config
|
||||
{"defmethod", new_flow_rule(3)},
|
||||
{"deftype", new_flow_rule_prevent_inlining_indexes(3, {3, 4, 5})},
|
||||
{"defun", new_flow_rule(3)},
|
||||
{"defbehavior", new_flow_rule(4)},
|
||||
{"if", new_permissive_flow_rule()},
|
||||
{"define", new_permissive_flow_rule()},
|
||||
{"define-extern", new_permissive_flow_rule()},
|
||||
{"defmacro", new_flow_rule(3)},
|
||||
{"dotimes", new_flow_rule(2)},
|
||||
{"let", new_binding_rule()},
|
||||
{"when", new_flow_rule(2)},
|
||||
|
||||
@@ -21,8 +21,8 @@ struct FormFormattingConfig {
|
||||
bool combine_first_two_lines =
|
||||
false; // NOTE - basically hang, but will probably stick around after hang is gone, may be
|
||||
// redundant (inline_until_index!)
|
||||
std::function<std::optional<int>(const std::vector<std::string>& curr_lines)> inline_until_index =
|
||||
[](std::vector<std::string> curr_lines) { return std::nullopt; };
|
||||
std::function<std::optional<int>(const std::vector<std::string>& /*curr_lines*/)>
|
||||
inline_until_index = [](std::vector<std::string> /*curr_lines*/) { return std::nullopt; };
|
||||
bool has_constant_pairs = false;
|
||||
bool prevent_inlining = false; // TODO - duplicate of below
|
||||
std::function<bool(FormFormattingConfig, int num_refs)> should_prevent_inlining =
|
||||
|
||||
@@ -62,15 +62,9 @@ constexpr int LEVEL_MAX = 6;
|
||||
constexpr int LEVEL_TOTAL = LEVEL_MAX + 1;
|
||||
} // namespace jak2
|
||||
|
||||
// TODO copypaste from jak 2 for now
|
||||
namespace jak3 {
|
||||
// for now, we don't have the ability to extend the size of the symbol table
|
||||
constexpr s32 GOAL_MAX_SYMBOLS = 0x4000;
|
||||
constexpr s32 SYM_TABLE_MEM_SIZE = 0x30000;
|
||||
// from the "off-by-one" symbol pointer
|
||||
constexpr int SYM_TO_STRING_OFFSET = 0xff37;
|
||||
constexpr int SYM_TO_HASH_OFFSET = 0x1fe6f;
|
||||
|
||||
// amount of levels in level heap
|
||||
constexpr int LEVEL_MAX = 10;
|
||||
// total amount of levels, including ones outside level heap (default-level)
|
||||
@@ -84,7 +78,7 @@ constexpr s32 max_symbols(GameVersion version) {
|
||||
case GameVersion::Jak2:
|
||||
return jak2::GOAL_MAX_SYMBOLS;
|
||||
case GameVersion::Jak3:
|
||||
return jak2::GOAL_MAX_SYMBOLS;
|
||||
return jak3::GOAL_MAX_SYMBOLS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1888,7 +1888,7 @@ Object Interpreter::eval_format(const Object& form,
|
||||
fmt::format_args(args2.data(), static_cast<unsigned>(args2.size())));
|
||||
|
||||
if (truthy(dest)) {
|
||||
lg::print(formatted.c_str());
|
||||
lg::print("{}", formatted.c_str());
|
||||
}
|
||||
|
||||
return StringObject::make_new(formatted);
|
||||
|
||||
@@ -238,9 +238,14 @@ Object Reader::read_from_string(const std::string& str,
|
||||
* Read a file
|
||||
*/
|
||||
Object Reader::read_from_file(const std::vector<std::string>& file_path, bool check_encoding) {
|
||||
std::string joined_path = fmt::format("{}", fmt::join(file_path, "/"));
|
||||
std::string file_descriptor = fmt::format("{}", fmt::join(file_path, "/"));
|
||||
const auto joined_file_path = file_util::get_file_path(file_path);
|
||||
|
||||
auto textFrag = std::make_shared<FileText>(file_util::get_file_path(file_path), joined_path);
|
||||
if (!fs::exists(joined_file_path)) {
|
||||
throw std::runtime_error(fmt::format("Cannot read {}, file doesn't exist", joined_file_path));
|
||||
}
|
||||
|
||||
auto textFrag = std::make_shared<FileText>(joined_file_path, file_descriptor);
|
||||
db.insert(textFrag);
|
||||
|
||||
auto result = internal_read(textFrag, check_encoding);
|
||||
|
||||
@@ -85,9 +85,9 @@ std::pair<int, int> SourceText::get_containing_line(int offset) {
|
||||
/*!
|
||||
* Read text from a file.
|
||||
*/
|
||||
FileText::FileText(const std::string& filename, const std::string& description_name)
|
||||
: m_filename(filename), m_desc_name(description_name) {
|
||||
m_text = file_util::read_text_file(m_filename);
|
||||
FileText::FileText(const std::string& file_path, const std::string& description_name)
|
||||
: m_filepath(file_path), m_desc_name(description_name) {
|
||||
m_text = file_util::read_text_file(m_filepath);
|
||||
build_offsets();
|
||||
}
|
||||
|
||||
|
||||
@@ -80,13 +80,13 @@ class ProgramString : public SourceText {
|
||||
*/
|
||||
class FileText : public SourceText {
|
||||
public:
|
||||
FileText(const std::string& filename, const std::string& description_name);
|
||||
FileText(const std::string& file_path, const std::string& description_name);
|
||||
|
||||
std::string get_description() { return m_desc_name; }
|
||||
~FileText() = default;
|
||||
|
||||
private:
|
||||
std::string m_filename;
|
||||
std::string m_filepath;
|
||||
std::string m_desc_name;
|
||||
};
|
||||
|
||||
|
||||
@@ -54,6 +54,21 @@ struct LinkHeaderV4 {
|
||||
uint32_t code_size; // length of object data before link data starts
|
||||
};
|
||||
|
||||
struct LinkHeaderV5Core {
|
||||
uint32_t length_to_get_to_code; // 4 length.. of link data?
|
||||
uint16_t version; // 8
|
||||
uint16_t unknown; // 10
|
||||
uint32_t length_to_get_to_link; // 12
|
||||
uint32_t link_length; // 16
|
||||
uint8_t n_segments; // 20
|
||||
char name[59]; // 21 (really??)
|
||||
};
|
||||
|
||||
struct LinkHeaderV5 {
|
||||
uint32_t type_tag; // 0 always 0?
|
||||
LinkHeaderV5Core core;
|
||||
};
|
||||
|
||||
// when a u32/s32 symbol link contains this value, (s7 + <val>) should be a 4-byte aligned address,
|
||||
// not including the 1 byte symbol offset. (no effect in jak 1).
|
||||
constexpr u32 LINK_SYM_NO_OFFSET_FLAG = 0xbadbeef;
|
||||
+1
-1
@@ -106,7 +106,7 @@ void log_print(const char* message) {
|
||||
}
|
||||
|
||||
if (gLogger.stdout_log_level < lg::level::off_unless_die) {
|
||||
fmt::print(message);
|
||||
fmt::print("{}", message);
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
@@ -373,7 +373,7 @@ bool GameSubtitleDB::write_subtitle_db_to_files(const GameVersion game_version)
|
||||
file_util::write_text_file(dump_path, lines_file.dump(2));
|
||||
}
|
||||
} catch (std::exception& ex) {
|
||||
lg::error(ex.what());
|
||||
lg::error("{}", ex.what());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -150,6 +150,180 @@ constexpr int FIX_FIXED_SYM_END_OFFSET = 0xec;
|
||||
|
||||
} // namespace jak2_symbols
|
||||
|
||||
namespace jak3_symbols {
|
||||
|
||||
constexpr int FIX_SYM_EMPTY_CAR = -0x8;
|
||||
constexpr int S7_OFF_FIX_SYM_EMPTY_PAIR = -0x6 - 1;
|
||||
constexpr int FIX_SYM_EMPTY_CDR = -0x4;
|
||||
constexpr int FIX_SYM_FALSE = 0x0; // GOAL boolean #f (note that this is equal to the $s7 register)
|
||||
constexpr int FIX_SYM_TRUE = 0x4; // GOAL boolean #t
|
||||
constexpr int FIX_SYM_FUNCTION_TYPE = 0x8;
|
||||
constexpr int FIX_SYM_BASIC = 0xc;
|
||||
constexpr int FIX_SYM_STRING_TYPE = 0x10;
|
||||
constexpr int FIX_SYM_SYMBOL_TYPE = 0x14;
|
||||
constexpr int FIX_SYM_TYPE_TYPE = 0x18;
|
||||
constexpr int FIX_SYM_OBJECT_TYPE = 0x1c;
|
||||
constexpr int FIX_SYM_LINK_BLOCK = 0x20;
|
||||
constexpr int FIX_SYM_INTEGER = 0x24;
|
||||
constexpr int FIX_SYM_SINTEGER = 0x28;
|
||||
constexpr int FIX_SYM_UINTEGER = 0x2c;
|
||||
constexpr int FIX_SYM_BINTEGER = 0x30;
|
||||
constexpr int FIX_SYM_INT8 = 0x34;
|
||||
constexpr int FIX_SYM_INT16 = 0x38;
|
||||
constexpr int FIX_SYM_INT32 = 0x3c;
|
||||
constexpr int FIX_SYM_INT64 = 0x40;
|
||||
constexpr int FIX_SYM_INT128 = 0x44;
|
||||
constexpr int FIX_SYM_UINT8 = 0x48;
|
||||
constexpr int FIX_SYM_UINT16 = 0x4c;
|
||||
constexpr int FIX_SYM_UINT32 = 0x50;
|
||||
constexpr int FIX_SYM_UINT64 = 0x54;
|
||||
constexpr int FIX_SYM_UINT128 = 0x58;
|
||||
constexpr int FIX_SYM_FLOAT = 0x5c;
|
||||
constexpr int FIX_SYM_PROCESS_TREE = 0x60;
|
||||
constexpr int FIX_SYM_PROCESS_TYPE = 0x64;
|
||||
constexpr int FIX_SYM_THREAD = 0x68;
|
||||
constexpr int FIX_SYM_STRUCTURE = 0x6c;
|
||||
constexpr int FIX_SYM_PAIR_TYPE = 0x70;
|
||||
constexpr int FIX_SYM_POINTER = 0x74;
|
||||
constexpr int FIX_SYM_NUMBER = 0x78;
|
||||
constexpr int FIX_SYM_ARRAY = 0x7c;
|
||||
constexpr int FIX_SYM_VU_FUNCTION = 0x80;
|
||||
constexpr int FIX_SYM_CONNECTABLE = 0x84;
|
||||
constexpr int FIX_SYM_STACK_FRAME = 0x88;
|
||||
constexpr int FIX_SYM_FILE_STREAM = 0x8c;
|
||||
constexpr int FIX_SYM_HEAP = 0x90;
|
||||
constexpr int FIX_SYM_NOTHING_FUNC = 0x94;
|
||||
constexpr int FIX_SYM_DELETE_BASIC = 0x98;
|
||||
constexpr int FIX_SYM_STATIC = 0x9c;
|
||||
constexpr int FIX_SYM_GLOBAL_HEAP = 0xa0;
|
||||
constexpr int FIX_SYM_DEBUG = 0xa4;
|
||||
constexpr int FIX_SYM_LOADING_LEVEL = 0xa8;
|
||||
constexpr int FIX_SYM_LOADING_PACKAGE = 0xac;
|
||||
constexpr int FIX_SYM_PROCESS_LEVEL_HEAP = 0xb0;
|
||||
constexpr int FIX_SYM_STACK = 0xb4;
|
||||
constexpr int FIX_SYM_SCRATCH = 0xb8;
|
||||
constexpr int FIX_SYM_SCRATCH_TOP = 0xbc;
|
||||
constexpr int FIX_SYM_ZERO_FUNC = 0xc0;
|
||||
constexpr int FIX_SYM_ASIZE_OF_BASIC_FUNC = 0xc4;
|
||||
constexpr int FIX_SYM_COPY_BASIC_FUNC = 0xc8; // bugged name
|
||||
constexpr int FIX_SYM_LEVEL = 0xcc;
|
||||
constexpr int FIX_SYM_ART_GROUP = 0xd0;
|
||||
constexpr int FIX_SYM_TEXTURE_PAGE_DIR = 0xd4;
|
||||
constexpr int FIX_SYM_TEXTURE_PAGE = 0xd8;
|
||||
constexpr int FIX_SYM_SOUND = 0xdc;
|
||||
constexpr int FIX_SYM_DGO = 0xe0;
|
||||
constexpr int FIX_SYM_TOP_LEVEL = 0xe4;
|
||||
constexpr int FIX_SYM_QUOTE = 0xe8;
|
||||
constexpr int FIX_SYM_LISTENER_LINK_BLOCK = 0xec;
|
||||
constexpr int FIX_SYM_LISTENER_FUNCTION = 0xf0;
|
||||
constexpr int FIX_SYM_STACK_TOP = 0xf4;
|
||||
constexpr int FIX_SYM_STACK_BASE = 0xf8;
|
||||
constexpr int FIX_SYM_STACK_SIZE = 0xfc;
|
||||
constexpr int FIX_SYM_KERNEL_FUNCTION = 0x100;
|
||||
constexpr int FIX_SYM_KERNEL_PACKAGES = 0x104;
|
||||
constexpr int FIX_SYM_KERNEL_BOOT_MESSAGE = 0x108;
|
||||
constexpr int FIX_SYM_KERNEL_BOOT_MODE = 0x10c;
|
||||
constexpr int FIX_SYM_KERNEL_BOOT_LEVEL = 0x110;
|
||||
constexpr int FIX_SYM_KERNEL_BOOT_ART_GROUP = 0x114;
|
||||
constexpr int FIX_SYM_KERNEL_DEBUG = 0x118;
|
||||
constexpr int FIX_SYM_KERNEL_VERSION = 0x11c;
|
||||
constexpr int FIX_SYM_KERNEL_DISPATCHER = 0x120;
|
||||
constexpr int FIX_SYM_SYNC_DISPATCHER = 0x124;
|
||||
constexpr int FIX_SYM_PRINT_COLLUMN = 0x128;
|
||||
constexpr int FIX_SYM_DEBUG_SEGMENT = 300;
|
||||
constexpr int FIX_SYM_ENABLE_METHOD_SET = 0x130;
|
||||
constexpr int FIX_SYM_SQL_RESULT = 0x134;
|
||||
constexpr int FIX_SYM_COLLAPSE_QUOTE = 0x138;
|
||||
constexpr int FIX_SYM_LEVEL_TYPE_LIST = 0x13C;
|
||||
constexpr int FIX_SYM_DECI_COUNT = 0x140;
|
||||
constexpr int FIX_SYM_USER = 0x144;
|
||||
constexpr int FIX_SYM_VIDEO_MODE = 0x148;
|
||||
constexpr int FIX_SYM_BOOT_VIDEO_MODE = 0x14C;
|
||||
constexpr int FIX_SYM_BOOT = 0x150;
|
||||
constexpr int FIX_SYM_DEMO = 0x154;
|
||||
constexpr int FIX_SYM_DEMO_SHARED = 0x158;
|
||||
constexpr int FIX_SYM_PREVIEW = 0x15C;
|
||||
constexpr int FIX_SYM_KIOSK = 0x160;
|
||||
constexpr int FIX_SYM_PLAY_BOOT = 0x164;
|
||||
constexpr int FIX_SYM_SIN = 0x168;
|
||||
constexpr int FIX_SYM_COS = 0x16C;
|
||||
constexpr int FIX_SYM_PUT_DISPLAY_ENV = 0x170;
|
||||
constexpr int FIX_SYM_SYNCV = 0x174;
|
||||
constexpr int FIX_SYM_SYNC_PATH = 0x178;
|
||||
constexpr int FIX_SYM_RESET_PATH = 0x17C;
|
||||
constexpr int FIX_SYM_RESET_GRAPH = 0x180;
|
||||
constexpr int FIX_SYM_DMA_SYNC = 0x184;
|
||||
constexpr int FIX_SYM_GS_PUT_IMR = 0x188;
|
||||
constexpr int FIX_SYM_GS_GET_IMR = 0x18C;
|
||||
constexpr int FIX_SYM_GS_STORE_IMAGE = 400;
|
||||
constexpr int FIX_SYM_FLUSH_CACHE = 0x194;
|
||||
constexpr int FIX_SYM_CPAD_OPEN = 0x198;
|
||||
constexpr int FIX_SYM_CPAD_GET_DATA = 0x19C;
|
||||
constexpr int FIX_SYM_MOUSE_GET_DATA = 0x1A0;
|
||||
constexpr int FIX_SYM_KEYBD_GET_DATA = 0x1A4;
|
||||
constexpr int FIX_SYM_INSTALL_HANDLER = 0x1A8;
|
||||
constexpr int FIX_SYM_INSTALL_DEBUG_HANDLER = 0x1AC;
|
||||
constexpr int FIX_SYM_FILE_STREAM_OPEN = 0x1B0;
|
||||
constexpr int FIX_SYM_FILE_STREAM_CLOSE = 0x1B4;
|
||||
constexpr int FIX_SYM_FILE_STREAM_LENGTH = 0x1B8;
|
||||
constexpr int FIX_SYM_FILE_STREAM_SEEK = 0x1BC;
|
||||
constexpr int FIX_SYM_FILE_STREAM_READ = 0x1C0;
|
||||
constexpr int FIX_SYM_FILE_STREAM_WRITE = 0x1C4;
|
||||
constexpr int FIX_SYM_SCF_GET_LANGUAGE = 0x1C8;
|
||||
constexpr int FIX_SYM_SCF_GET_TIME = 0x1CC;
|
||||
constexpr int FIX_SYM_SCF_GET_ASPECT = 0x1D0;
|
||||
constexpr int FIX_SYM_SCF_GET_VOLUME = 0x1D4;
|
||||
constexpr int FIX_SYM_SCF_GET_TERRITORY = 0x1D8;
|
||||
constexpr int FIX_SYM_SCF_GET_TIMEOUT = 0x1DC;
|
||||
constexpr int FIX_SYM_SCF_GET_INACTIVE_TIMEOUT = 0x1E0;
|
||||
constexpr int FIX_SYM_DMA_TO_IOP = 0x1E4;
|
||||
constexpr int FIX_SYM_KERNEL_SHUTDOWN = 0x1E8;
|
||||
constexpr int FIX_SYM_AYBABTU = 0x1EC;
|
||||
constexpr int FIX_SYM_STRING_TO_SYMBOL = 0x1F0;
|
||||
constexpr int FIX_SYM_SYMBOL_TO_STRING = 500;
|
||||
constexpr int FIX_SYM_PRINT = 0x1F8;
|
||||
constexpr int FIX_SYM_INSPECT = 0x1FC;
|
||||
constexpr int FIX_SYM_LOAD = 0x200;
|
||||
constexpr int FIX_SYM_LOADB = 0x204;
|
||||
constexpr int FIX_SYM_LOADO = 0x208;
|
||||
constexpr int FIX_SYM_UNLOAD = 0x20C;
|
||||
constexpr int FIX_SYM_FORMAT = 0x210;
|
||||
constexpr int FIX_SYM_MALLOC = 0x214;
|
||||
constexpr int FIX_SYM_KMALLOC = 0x218;
|
||||
constexpr int FIX_SYM_KMEMOPEN = 0x21C;
|
||||
constexpr int FIX_SYM_KMEMCLOSE = 0x220;
|
||||
constexpr int FIX_SYM_NEW_DYNAMIC_STRUCTURE = 0x224;
|
||||
constexpr int FIX_SYM_METHOD_SET = 0x228;
|
||||
constexpr int FIX_SYM_LINK = 0x22C;
|
||||
constexpr int FIX_SYM_LINK_BUSY = 0x230;
|
||||
constexpr int FIX_SYM_LINK_RESET = 0x234;
|
||||
constexpr int FIX_SYM_LINK_BEGIN = 0x238;
|
||||
constexpr int FIX_SYM_LINK_RESUME = 0x23C;
|
||||
constexpr int FIX_SYM_DGO_LOAD = 0x240;
|
||||
constexpr int FIX_SYM_SQL_QUERY = 0x244;
|
||||
constexpr int FIX_SYM_MC_RUN = 0x248;
|
||||
constexpr int FIX_SYM_MC_FORMAT = 0x24C;
|
||||
constexpr int FIX_SYM_MC_UNFORMAT = 0x250;
|
||||
constexpr int FIX_SYM_MC_CREATE_FILE = 0x254;
|
||||
constexpr int FIX_SYM_MC_SAVE = 600;
|
||||
constexpr int FIX_SYM_MC_LOAD = 0x25C;
|
||||
constexpr int FIX_SYM_MC_CHECK_RESULT = 0x260;
|
||||
constexpr int FIX_SYM_MC_GET_SLOT_INFO = 0x264;
|
||||
constexpr int FIX_SYM_MC_MAKEFILE = 0x268;
|
||||
constexpr int FIX_SYM_KSET_LANGUAGE = 0x26C;
|
||||
constexpr int FIX_SYM_RPC_CALL = 0x270;
|
||||
constexpr int FIX_SYM_RPC_BUSY = 0x274;
|
||||
constexpr int FIX_SYM_TEST_LOAD_DGO_C = 0x278;
|
||||
constexpr int FIX_SYM_SYMLINK2 = 0x27c;
|
||||
constexpr int FIX_SYM_SYMLINK3 = 0x280;
|
||||
constexpr int FIX_SYM_ULTIMATE_MEMCPY = 0x284;
|
||||
constexpr int FIX_SYM_PLAY = 0x288;
|
||||
constexpr int FIX_SYM_SYMBOL_STRING = 0x28c;
|
||||
constexpr int FIX_SYM_KERNEL_SYMBOL_WARNINGS = 0x290;
|
||||
constexpr int FIX_SYM_NETWORK_BOOTSTRAP = 0x294;
|
||||
|
||||
} // namespace jak3_symbols
|
||||
|
||||
constexpr int false_symbol_offset() {
|
||||
return jak1_symbols::FIX_SYM_FALSE;
|
||||
}
|
||||
|
||||
@@ -2113,7 +2113,7 @@ std::optional<std::string> find_best_field_in_structure(const TypeSystem& ts,
|
||||
}
|
||||
for (size_t i = start_field; i < (size_t)end_field; ++i) {
|
||||
const auto& field = st->fields().at(i);
|
||||
auto type = ts.lookup_type(field.type());
|
||||
auto type = ts.lookup_type_allow_partial_def(field.type());
|
||||
if (field.is_dynamic() || field.offset() > offset || field.user_placed() != want_fixed) {
|
||||
continue;
|
||||
}
|
||||
@@ -2147,6 +2147,12 @@ std::optional<std::string> find_best_field_in_structure(const TypeSystem& ts,
|
||||
} else {
|
||||
int rel_offset = offset - field.offset();
|
||||
// array case (and array encompasses what we want)
|
||||
ASSERT_MSG(
|
||||
type->get_size_in_memory() > 0,
|
||||
fmt::format(
|
||||
"In type {}, type size was 0 for array field {} of type {}, check that the type "
|
||||
"is fully defined.",
|
||||
st->get_name(), field.name(), field.type().print()));
|
||||
int array_idx = rel_offset / type->get_size_in_memory();
|
||||
if (!field.is_inline() &&
|
||||
field.offset() + field.array_size() * type->get_load_size() > offset) {
|
||||
|
||||
@@ -16,12 +16,12 @@ void private_assert_failed(const char* expr,
|
||||
if (!msg || msg[0] == '\0') {
|
||||
std::string log = fmt::format("Assertion failed: '{}'\n\tSource: {}:{}\n\tFunction: {}\n", expr,
|
||||
file, line, function);
|
||||
lg::die(log);
|
||||
lg::die("{}", log);
|
||||
} else {
|
||||
std::string log =
|
||||
fmt::format("Assertion failed: '{}'\n\tMessage: {}\n\tSource: {}:{}\n\tFunction: {}\n",
|
||||
expr, msg, file, line, function);
|
||||
lg::die(log);
|
||||
lg::die("{}", log);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
@@ -12,30 +12,33 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/Assert.h"
|
||||
|
||||
#include "third-party/span.hpp"
|
||||
|
||||
class BinaryReader {
|
||||
public:
|
||||
explicit BinaryReader(const std::vector<uint8_t>& _buffer) : m_buffer(_buffer) {}
|
||||
explicit BinaryReader(nonstd::span<const uint8_t> _span) : m_span(_span) {}
|
||||
|
||||
template <typename T>
|
||||
T read() {
|
||||
ASSERT(m_seek + sizeof(T) <= m_buffer.size());
|
||||
ASSERT(m_seek + sizeof(T) <= m_span.size());
|
||||
T obj;
|
||||
memcpy(&obj, m_buffer.data() + m_seek, sizeof(T));
|
||||
memcpy(&obj, m_span.data() + m_seek, sizeof(T));
|
||||
m_seek += sizeof(T);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void ffwd(int amount) {
|
||||
m_seek += amount;
|
||||
ASSERT(m_seek <= m_buffer.size());
|
||||
ASSERT(m_seek <= m_span.size());
|
||||
}
|
||||
|
||||
uint32_t bytes_left() const { return m_buffer.size() - m_seek; }
|
||||
uint8_t* here() { return m_buffer.data() + m_seek; }
|
||||
uint32_t bytes_left() const { return m_span.size() - m_seek; }
|
||||
const uint8_t* here() { return m_span.data() + m_seek; }
|
||||
BinaryReader at(u32 pos) { return BinaryReader(m_span.subspan(pos)); }
|
||||
uint32_t get_seek() const { return m_seek; }
|
||||
void set_seek(u32 seek) { m_seek = seek; }
|
||||
|
||||
private:
|
||||
std::vector<u8> m_buffer;
|
||||
nonstd::span<const u8> m_span;
|
||||
uint32_t m_seek = 0;
|
||||
};
|
||||
@@ -88,6 +88,11 @@ fs::path get_user_memcard_dir(GameVersion game_version) {
|
||||
return get_user_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";
|
||||
}
|
||||
|
||||
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";
|
||||
@@ -636,6 +641,9 @@ std::vector<fs::path> find_files_in_dir(const fs::path& dir, const std::regex& p
|
||||
|
||||
std::vector<fs::path> find_files_recursively(const fs::path& base_dir, const std::regex& pattern) {
|
||||
std::vector<fs::path> files = {};
|
||||
if (!fs::exists(base_dir)) {
|
||||
return files;
|
||||
}
|
||||
for (auto& p : fs::recursive_directory_iterator(base_dir)) {
|
||||
if (p.is_regular_file()) {
|
||||
if (std::regex_match(p.path().filename().string(), pattern)) {
|
||||
@@ -692,15 +700,33 @@ void copy_file(const fs::path& src, const fs::path& dst) {
|
||||
std::string make_screenshot_filepath(const GameVersion game_version, const std::string& name) {
|
||||
std::string file_name;
|
||||
if (name.empty()) {
|
||||
file_name = fmt::format("{}_{}.png", version_to_game_name(game_version),
|
||||
str_util::current_local_timestamp_no_colons());
|
||||
file_name = fmt::format("{}.png", str_util::current_local_timestamp_no_colons());
|
||||
} else {
|
||||
file_name = fmt::format("{}_{}_{}.png", version_to_game_name(game_version), name,
|
||||
str_util::current_local_timestamp_no_colons());
|
||||
file_name = fmt::format("{}.png", name);
|
||||
}
|
||||
const auto file_path = file_util::get_file_path({"screenshots", file_name});
|
||||
const auto file_path = get_user_screenshots_dir(game_version) / file_name;
|
||||
file_util::create_dir_if_needed_for_file(file_path);
|
||||
return file_path;
|
||||
return file_path.string();
|
||||
}
|
||||
|
||||
std::string get_majority_file_line_endings(const std::string& file_contents) {
|
||||
size_t lf_count = 0;
|
||||
size_t crlf_count = 0;
|
||||
|
||||
for (size_t i = 0; i < file_contents.size(); ++i) {
|
||||
if (file_contents[i] == '\n') {
|
||||
if (i > 0 && file_contents[i - 1] == '\r') {
|
||||
crlf_count++;
|
||||
} else {
|
||||
lf_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (crlf_count > lf_count) {
|
||||
return "\r\n";
|
||||
}
|
||||
return "\n";
|
||||
}
|
||||
|
||||
} // namespace file_util
|
||||
@@ -31,6 +31,7 @@ fs::path get_user_home_dir();
|
||||
fs::path get_user_config_dir();
|
||||
fs::path get_user_settings_dir(GameVersion game_version);
|
||||
fs::path get_user_memcard_dir(GameVersion game_version);
|
||||
fs::path get_user_screenshots_dir(GameVersion game_version);
|
||||
fs::path get_user_misc_dir(GameVersion game_version);
|
||||
fs::path get_jak_project_dir();
|
||||
|
||||
@@ -69,4 +70,5 @@ std::vector<fs::path> sort_filepaths(const std::vector<fs::path>& paths, const b
|
||||
/// Will overwrite the destination if it exists
|
||||
void copy_file(const fs::path& src, const fs::path& dst);
|
||||
std::string make_screenshot_filepath(const GameVersion game_version, const std::string& name = "");
|
||||
std::string get_majority_file_line_endings(const std::string& file_contents);
|
||||
} // namespace file_util
|
||||
@@ -21,7 +21,7 @@ void assert_string_empty_after(const char* str, int size) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_object_file_name(const std::string& original_name, u8* data, int size) {
|
||||
std::string get_object_file_name(const std::string& original_name, const u8* data, int size) {
|
||||
const std::string art_group_text_strings[] = {
|
||||
fmt::format("/src/next/data/art-group{}/", versions::jak1::ART_FILE_VERSION),
|
||||
fmt::format("/src/jak2/final/art-group{}/", versions::jak2::ART_FILE_VERSION),
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
#include "common/versions/versions.h"
|
||||
|
||||
void assert_string_empty_after(const char* str, int size);
|
||||
std::string get_object_file_name(const std::string& original_name, u8* data, int size);
|
||||
std::string get_object_file_name(const std::string& original_name, const u8* data, int size);
|
||||
@@ -102,6 +102,22 @@ std::vector<std::string> split(const ::std::string& str, char delimiter) {
|
||||
return google_diff::split_string(str, delimiter);
|
||||
}
|
||||
|
||||
std::vector<std::string> split_string(const std::string& str, const std::string& delimiter) {
|
||||
std::vector<std::string> parsed;
|
||||
std::string::size_type pos = 0;
|
||||
while (true) {
|
||||
const std::string::size_type found = str.find(delimiter, pos);
|
||||
if (found == std::string::npos) {
|
||||
parsed.push_back(str.substr(pos));
|
||||
break;
|
||||
} else {
|
||||
parsed.push_back(str.substr(pos, found - pos));
|
||||
pos = found + delimiter.length();
|
||||
}
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
std::vector<std::string> regex_get_capture_groups(const std::string& str,
|
||||
const std::string& regex) {
|
||||
std::vector<std::string> groups;
|
||||
|
||||
@@ -18,7 +18,9 @@ int line_count(const std::string& str);
|
||||
bool valid_regex(const std::string& regex);
|
||||
std::string diff(const std::string& lhs, const std::string& rhs);
|
||||
/// Default splits on \n characters
|
||||
/// DEPRECATED - stop using it, limited as it only takes a char
|
||||
std::vector<std::string> split(const ::std::string& str, char delimiter = '\n');
|
||||
std::vector<std::string> split_string(const std::string& str, const std::string& delimiter = "\n");
|
||||
std::string join(const std::vector<std::string>& strs, const std::string& join_with);
|
||||
std::vector<std::string> regex_get_capture_groups(const std::string& str, const std::string& regex);
|
||||
bool replace(std::string& str, const std::string& from, const std::string& to);
|
||||
|
||||
@@ -11,13 +11,15 @@ GameVersion game_name_to_version(const std::string& name) {
|
||||
return GameVersion::Jak1;
|
||||
} else if (name == "jak2") {
|
||||
return GameVersion::Jak2;
|
||||
} else if (name == "jak3") {
|
||||
return GameVersion::Jak3;
|
||||
} else {
|
||||
ASSERT_MSG(false, fmt::format("invalid game name: {}", name));
|
||||
}
|
||||
}
|
||||
|
||||
bool valid_game_version(const std::string& name) {
|
||||
return name == "jak1" || name == "jak2";
|
||||
return name == "jak1" || name == "jak2" || name == "jak3";
|
||||
}
|
||||
|
||||
std::string version_to_game_name(GameVersion v) {
|
||||
@@ -26,6 +28,8 @@ std::string version_to_game_name(GameVersion v) {
|
||||
return "jak1";
|
||||
case GameVersion::Jak2:
|
||||
return "jak2";
|
||||
case GameVersion::Jak3:
|
||||
return "jak3";
|
||||
default:
|
||||
ASSERT_MSG(false, fmt::format("no game_name for version: {} found", fmt::underlying(v)));
|
||||
}
|
||||
@@ -37,13 +41,16 @@ std::string version_to_game_name_external(GameVersion v) {
|
||||
return "Jak 1";
|
||||
case GameVersion::Jak2:
|
||||
return "Jak 2";
|
||||
case GameVersion::Jak3:
|
||||
return "Jak 3";
|
||||
default:
|
||||
ASSERT_MSG(false, fmt::format("no game_name for version: {} found", fmt::underlying(v)));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> valid_game_version_names() {
|
||||
return {game_version_names[GameVersion::Jak1], game_version_names[GameVersion::Jak2]};
|
||||
return {game_version_names[GameVersion::Jak1], game_version_names[GameVersion::Jak2],
|
||||
game_version_names[GameVersion::Jak3]};
|
||||
}
|
||||
|
||||
std::string build_revision() {
|
||||
|
||||
@@ -34,6 +34,7 @@ constexpr u32 TX_PAGE_VERSION = 8;
|
||||
namespace jak3 {
|
||||
constexpr u32 ART_FILE_VERSION = 8;
|
||||
constexpr u32 LEVEL_FILE_VERSION = 36;
|
||||
constexpr u32 DGO_FILE_VERSION = 1;
|
||||
constexpr u32 TX_PAGE_VERSION = 8;
|
||||
} // namespace jak3
|
||||
|
||||
|
||||
@@ -20,16 +20,40 @@
|
||||
// this makes collision 2x slower and bigger, so only use if really needed
|
||||
"double_sided_collide": false,
|
||||
|
||||
// available res-lump tag data types:
|
||||
// int32, float, meters, vector, vector4m (meters)
|
||||
// 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 vector tag 'movie-pos':
|
||||
// "movie-pos": ["vector", [4096000.0, -176128.0, 1353973.76, 1.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 wt08 wt03 wt01)"]
|
||||
//
|
||||
// adds an eco-info tag:
|
||||
// "eco-info": ["eco-info", "(pickup-type health)", 2]
|
||||
//
|
||||
// adds a cell-info tag:
|
||||
// "eco-info": ["cell-info", "(game-task training-gimmie)"]
|
||||
//
|
||||
// adds a buzzer-info tag:
|
||||
// "eco-info": ["buzzer-info", "(game-task training-buzzer)", 5]
|
||||
//
|
||||
// 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,
|
||||
@@ -65,7 +89,7 @@
|
||||
"lump": {
|
||||
"name": "test-ambient",
|
||||
"type": "'hint",
|
||||
"text-id": ["int32", 557], // text id for the "POWER CELL" text
|
||||
"text-id": ["enum-uint32", "(text-id fuel-cell)"], // text id for the "POWER CELL" text
|
||||
"play-mode": "'notice"
|
||||
}
|
||||
}
|
||||
@@ -75,31 +99,32 @@
|
||||
{
|
||||
"trans": [-21.6238, 20.0496, 17.1191], // translation
|
||||
"etype": "fuel-cell", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-21.6238, 19.3496, 17.1191, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-fuel-cell"
|
||||
"name": "test-fuel-cell",
|
||||
"eco-info": ["cell-info", "(game-task none)"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"trans": [-15.2818, 15.2461, 17.1360], // translation
|
||||
"etype": "crate", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-crate",
|
||||
"crate-type": "'steel",
|
||||
"eco-info": ["int32", 5, 10]
|
||||
"eco-info": ["eco-info", "(pickup-type money)", 10]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"trans": [-5.4630, 17.4553, 1.6169], // translation
|
||||
"etype": "eco-yellow", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere
|
||||
"lump": {
|
||||
@@ -109,7 +134,7 @@
|
||||
// {
|
||||
// "trans": [-7.41, 3.5, 28.42], // translation
|
||||
// "etype": "plat", // actor type
|
||||
// "game_task": 0, // associated game task (for powercells, etc)
|
||||
// "game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
// "quat": [0, 0, 0, 1], // quaternion
|
||||
// "bsphere": [-7.41, 3.5, 28.42, 10], // bounding sphere
|
||||
// "lump": {
|
||||
|
||||
@@ -20,24 +20,41 @@
|
||||
// this makes collision 2x slower and bigger, so only use if really needed
|
||||
"double_sided_collide": false,
|
||||
|
||||
// available res-lump tag data types:
|
||||
// int32, float, meters, vector, vector4m (meters)
|
||||
// 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 vector tag 'movie-pos':
|
||||
// "movie-pos": ["vector", [4096000.0, -176128.0, 1353973.76, 1.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.
|
||||
// Removed so that the release builds don't have to double-decompile the game
|
||||
//"art_groups": ["prsn-torture-ag"],
|
||||
"art_groups": [],
|
||||
// "art_groups": ["prsn-torture-ag"],
|
||||
|
||||
// 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.
|
||||
@@ -55,14 +72,14 @@
|
||||
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
|
||||
"lump": {
|
||||
"name": "test-crate",
|
||||
"eco-info": ["int32", 18, 2]
|
||||
"eco-info": ["eco-info", "(pickup-type health)", 2]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"trans": [-5.4630, 17.4553, 1.6169], // translation
|
||||
"etype": "eco-yellow", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"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
|
||||
@@ -74,7 +91,7 @@
|
||||
{
|
||||
"trans": [-7.41, 13.5, 28.42], // translation
|
||||
"etype": "prsn-torture", // actor type
|
||||
"game_task": 0, // associated game task (for powercells, etc)
|
||||
"game_task": "(game-task none)", // associated game task (for powercells, etc)
|
||||
"quat": [0, 0, 0, 1], // quaternion
|
||||
"bsphere": [-7.41, 13.5, 28.42, 10], // bounding sphere
|
||||
"lump": {
|
||||
|
||||
@@ -191,7 +191,7 @@ TP_Type SimpleExpression::get_type(const TypeState& input,
|
||||
return TP_Type::make_from_ts("float");
|
||||
}
|
||||
// new for jak 2:
|
||||
if (env.version == GameVersion::Jak2 && in_type.is_integer_constant() &&
|
||||
if (env.version >= GameVersion::Jak2 && in_type.is_integer_constant() &&
|
||||
(s64)((s32)in_type.get_integer_constant()) == (s64)in_type.get_integer_constant()) {
|
||||
return TP_Type::make_from_ts("float");
|
||||
}
|
||||
@@ -406,7 +406,7 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||
}
|
||||
|
||||
if (m_kind == Kind::RIGHT_SHIFT_ARITH) {
|
||||
if (env.version == GameVersion::Jak2 && arg0_type.typespec().base_type() == "float") {
|
||||
if (env.version >= GameVersion::Jak2 && arg0_type.typespec().base_type() == "float") {
|
||||
return TP_Type::make_from_ts(TypeSpec("float"));
|
||||
}
|
||||
return TP_Type::make_from_ts(TypeSpec("int"));
|
||||
|
||||
@@ -170,7 +170,7 @@ FormElement* handle_get_property_struct(const std::vector<Form*>& forms,
|
||||
const Env& env) {
|
||||
return handle_get_property_data_or_structure(
|
||||
forms, pool, env, ResLumpMacroElement::Kind::STRUCT,
|
||||
env.version == GameVersion::Jak2 ? "(the-as structure #f)" : "#f", TypeSpec("structure"));
|
||||
env.version >= GameVersion::Jak2 ? "(the-as structure #f)" : "#f", TypeSpec("structure"));
|
||||
}
|
||||
|
||||
FormElement* handle_get_property_value(const std::vector<Form*>& forms,
|
||||
|
||||
@@ -3141,11 +3141,11 @@ goos::Object DefskelgroupElement::to_form_internal(const Env& env) const {
|
||||
}
|
||||
if (m_static_info.shadow_joint_index != 0) {
|
||||
forms.push_back(pretty_print::to_symbol(
|
||||
fmt::format(":shadow-joint-index {}", m_static_info.origin_joint_index)));
|
||||
fmt::format(":shadow-joint-index {}", m_static_info.shadow_joint_index)));
|
||||
}
|
||||
if (m_static_info.light_index != 0) {
|
||||
forms.push_back(pretty_print::to_symbol(
|
||||
fmt::format(":light-index {}", m_static_info.origin_joint_index)));
|
||||
forms.push_back(
|
||||
pretty_print::to_symbol(fmt::format(":light-index {}", m_static_info.light_index)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3255,7 +3255,7 @@ goos::Object DefpartgroupElement::to_form_internal(const Env& env) const {
|
||||
|
||||
if (offset) {
|
||||
// jak2 has switched this field to a signed 16 bit number
|
||||
if (env.version == GameVersion::Jak2) {
|
||||
if (env.version >= GameVersion::Jak2) {
|
||||
result += fmt::format(" :offset {}", (s16)offset);
|
||||
} else {
|
||||
result += fmt::format(" :offset {}", offset);
|
||||
|
||||
@@ -122,7 +122,7 @@ Form* try_cast_simplify(Form* in,
|
||||
return in;
|
||||
}
|
||||
|
||||
if (env.version == GameVersion::Jak2) {
|
||||
if (env.version >= GameVersion::Jak2) {
|
||||
if (new_type == TypeSpec("float")) {
|
||||
auto ic = get_goal_integer_constant(in, env);
|
||||
if (ic) {
|
||||
@@ -138,7 +138,7 @@ Form* try_cast_simplify(Form* in,
|
||||
if (new_type == TypeSpec("meters")) {
|
||||
auto fc = get_goal_float_constant(in);
|
||||
|
||||
if (!fc && env.version == GameVersion::Jak2) {
|
||||
if (!fc && env.version >= GameVersion::Jak2) {
|
||||
auto ic = get_goal_integer_constant(in, env);
|
||||
if (ic) {
|
||||
ASSERT((s64)*ic == (s64)(s32)*ic);
|
||||
@@ -2853,7 +2853,7 @@ bool try_to_rewrite_vector_inline_ctor(const Env& env,
|
||||
token_matchers = {DerefTokenMatcher::string("quad")};
|
||||
}
|
||||
|
||||
if (env.version == GameVersion::Jak2) {
|
||||
if (env.version >= GameVersion::Jak2) {
|
||||
token_matchers = {DerefTokenMatcher::string("quad")};
|
||||
}
|
||||
|
||||
@@ -3376,7 +3376,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
|
||||
argset = argset.substr(1);
|
||||
auto argsym = arg_forms.at(1)->to_string(env);
|
||||
// convert the float param
|
||||
if (env.version == GameVersion::Jak2) {
|
||||
if (env.version >= GameVersion::Jak2) {
|
||||
static const std::unordered_set<std::string> use_degrees_settings = {
|
||||
"matrix-blend-max-angle",
|
||||
"fov",
|
||||
@@ -4081,7 +4081,7 @@ void DerefElement::update_from_stack(const Env& env,
|
||||
}
|
||||
|
||||
auto as_simple_expr = m_base->try_as_element<SimpleExpressionElement>();
|
||||
if (env.version == GameVersion::Jak2 && as_simple_expr && as_simple_expr->expr().is_identity() &&
|
||||
if (env.version >= GameVersion::Jak2 && as_simple_expr && as_simple_expr->expr().is_identity() &&
|
||||
as_simple_expr->expr().get_arg(0).is_sym_val() &&
|
||||
as_simple_expr->expr().get_arg(0).get_str() == "*game-info*" && m_tokens.size() >= 2 &&
|
||||
m_tokens.at(0).is_field_name("sub-task-list") && m_tokens.at(1).is_int()) {
|
||||
|
||||
@@ -263,7 +263,7 @@ static void link_v2_or_v4(LinkedObjectFile& f,
|
||||
const uint8_t* code_end =
|
||||
&data.at(code_offset + code_size - 1) + 1; // get the pointer to one past the end.
|
||||
|
||||
if (version == GameVersion::Jak2) {
|
||||
if (version >= GameVersion::Jak2) {
|
||||
while (((code_end - code_start) % 4)) {
|
||||
code_end++;
|
||||
}
|
||||
@@ -472,7 +472,7 @@ static void link_v5(LinkedObjectFile& f,
|
||||
for (int i = 0; i < n_segs; i++) {
|
||||
segment_data_offsets[i] = header->length_to_get_to_code + seg_info_array[i].data;
|
||||
segment_link_offsets[i] = header->length_to_get_to_link + seg_info_array[i].relocs;
|
||||
ASSERT(seg_info_array[i].magic == 1);
|
||||
ASSERT(seg_info_array[i].magic == 1); // if set, always use symlink2.
|
||||
}
|
||||
|
||||
// check that the data region is filled
|
||||
@@ -689,7 +689,7 @@ static void link_v3(LinkedObjectFile& f,
|
||||
segment_size++;
|
||||
}
|
||||
|
||||
if (game_version == GameVersion::Jak2) {
|
||||
if (game_version >= GameVersion::Jak2) {
|
||||
while (segment_size % 4) {
|
||||
segment_size++;
|
||||
}
|
||||
|
||||
@@ -222,13 +222,14 @@ class ObjectFileDB {
|
||||
void ir2_setup_labels(const Config& config, ObjectFileData& data);
|
||||
void ir2_run_mips2c(const Config& config, ObjectFileData& data);
|
||||
struct PerObjectAllTypeInfo {
|
||||
std::string object_name;
|
||||
std::unordered_set<std::string> already_seen_symbols;
|
||||
|
||||
// type-name : { method id : state name }
|
||||
std::unordered_map<std::string, std::unordered_map<int, std::string>> state_methods;
|
||||
// symbol-name : type-name
|
||||
std::unordered_map<std::string, std::string> symbol_types;
|
||||
// state-name : type-name
|
||||
std::unordered_map<std::string, std::string> non_virtual_state_guesses;
|
||||
|
||||
struct TypeInfo {
|
||||
bool from_inspect_method = false; // does this come from an inspect method?
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "common/util/Timer.h"
|
||||
#include "common/util/string_util.h"
|
||||
|
||||
#include "decompiler/IR2/Form.h"
|
||||
#include "decompiler/analysis/analyze_inspect_method.h"
|
||||
@@ -319,7 +320,11 @@ void ObjectFileDB::ir2_top_level_pass(const Config& config) {
|
||||
void ObjectFileDB::ir2_analyze_all_types(const fs::path& output_file,
|
||||
const std::optional<std::string>& previous_game_types,
|
||||
const std::unordered_set<std::string>& bad_types) {
|
||||
std::vector<PerObjectAllTypeInfo> per_object;
|
||||
auto is_code_file = [](ObjectFileData& data) {
|
||||
return (data.obj_version == 3 ||
|
||||
(data.obj_version == 5 && data.linked_data.has_any_functions()));
|
||||
};
|
||||
std::unordered_map<std::string, PerObjectAllTypeInfo> per_object;
|
||||
|
||||
DecompilerTypeSystem previous_game_ts(GameVersion::Jak2); // version here doesn't matter.
|
||||
if (previous_game_types) {
|
||||
@@ -328,16 +333,66 @@ void ObjectFileDB::ir2_analyze_all_types(const fs::path& output_file,
|
||||
|
||||
TypeInspectorCache ti_cache;
|
||||
|
||||
// Do a first pass to initialize all types and symbols
|
||||
for_each_obj([&](ObjectFileData& data) {
|
||||
if (data.obj_version == 3 || (data.obj_version == 5 && data.linked_data.has_any_functions())) {
|
||||
auto& object_result = per_object.emplace_back();
|
||||
object_result.object_name = data.to_unique_name();
|
||||
|
||||
if (is_code_file(data)) {
|
||||
per_object[data.to_unique_name()] = PerObjectAllTypeInfo();
|
||||
// Go through the top-level segment first to identify the type names associated with each
|
||||
// symbol def
|
||||
for_each_function_in_seg_in_obj(TOP_LEVEL_SEGMENT, data, [&](Function& f) {
|
||||
inspect_top_level_for_metadata(f, data.linked_data, dts, previous_game_ts, object_result);
|
||||
inspect_top_level_for_metadata(f, data.linked_data, dts, previous_game_ts,
|
||||
per_object.at(data.to_unique_name()));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Guess at non-virtual state type's:
|
||||
//
|
||||
// Collect all type names, since the DTS doesn't know the actual type tree (all-types is empty!)
|
||||
// we can't filter by what is actually a process type (with existing code).
|
||||
std::unordered_map<std::string, std::vector<std::string>> all_type_names;
|
||||
for (auto& [obj_name, obj_info] : per_object) {
|
||||
for (const auto& type_name : obj_info.type_names_in_order) {
|
||||
if (all_type_names.find(obj_name) == all_type_names.end()) {
|
||||
all_type_names[obj_name] = {};
|
||||
}
|
||||
all_type_names[obj_name].push_back(type_name);
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> state_to_type_map;
|
||||
for (auto& [obj_name, obj_info] : per_object) {
|
||||
for (const auto& [sym_name, sym_type] : obj_info.symbol_types) {
|
||||
if (sym_type == "state") {
|
||||
int longest_match_length = 0;
|
||||
std::string longest_match = "";
|
||||
std::string longest_match_object_name = "";
|
||||
// Make a best effort guess by finding the longest prefix match
|
||||
for (const auto& [obj_name, type_names] : all_type_names) {
|
||||
for (const auto& type_name : type_names) {
|
||||
if (str_util::starts_with(sym_name, type_name) &&
|
||||
(int)type_name.length() > longest_match_length) {
|
||||
longest_match_length = type_name.length();
|
||||
longest_match = type_name;
|
||||
longest_match_object_name = obj_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (longest_match != "") {
|
||||
if (per_object.find(longest_match_object_name) != per_object.end()) {
|
||||
per_object.at(longest_match_object_name).non_virtual_state_guesses[sym_name] =
|
||||
longest_match;
|
||||
obj_info.already_seen_symbols.insert(sym_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then another to actually setup the definitions
|
||||
for_each_obj([&](ObjectFileData& data) {
|
||||
if (is_code_file(data)) {
|
||||
auto& object_result = per_object.at(data.to_unique_name());
|
||||
|
||||
// Handle the top level last, which is fine as all symbol_defs are always written after
|
||||
// typedefs
|
||||
@@ -368,21 +423,27 @@ void ObjectFileDB::ir2_analyze_all_types(const fs::path& output_file,
|
||||
}
|
||||
});
|
||||
|
||||
// Output result
|
||||
|
||||
std::string result;
|
||||
result += ";; All Types\n\n";
|
||||
|
||||
for (auto& obj : per_object) {
|
||||
result += fmt::format(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
|
||||
result += fmt::format(";; {:30s} ;;\n", obj.object_name);
|
||||
result += fmt::format(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n");
|
||||
for (const auto& type_name : obj.type_names_in_order) {
|
||||
auto& info = obj.type_info.at(type_name);
|
||||
result += info.type_definition;
|
||||
for_each_obj([&](ObjectFileData& data) {
|
||||
if (is_code_file(data)) {
|
||||
auto& obj = per_object.at(data.to_unique_name());
|
||||
|
||||
result += fmt::format(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
|
||||
result += fmt::format(";; {:30s} ;;\n", data.name_in_dgo);
|
||||
result += fmt::format(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n");
|
||||
for (const auto& type_name : obj.type_names_in_order) {
|
||||
auto& info = obj.type_info.at(type_name);
|
||||
result += info.type_definition;
|
||||
result += "\n";
|
||||
}
|
||||
result += obj.symbol_defs;
|
||||
result += "\n";
|
||||
}
|
||||
result += obj.symbol_defs;
|
||||
result += "\n";
|
||||
}
|
||||
});
|
||||
|
||||
file_util::write_text_file(output_file, result);
|
||||
}
|
||||
@@ -594,8 +655,8 @@ void ObjectFileDB::ir2_type_analysis_pass(int seg, const Config& config, ObjectF
|
||||
}
|
||||
|
||||
constexpr bool kForceNewTypes = false;
|
||||
if (config.game_version == GameVersion::Jak2 || kForceNewTypes) {
|
||||
// use new types for jak 2 always
|
||||
if (config.game_version != GameVersion::Jak1 || kForceNewTypes) {
|
||||
// use new types for jak 2/3 always
|
||||
types2::Input in;
|
||||
types2::Output out;
|
||||
in.func = &func;
|
||||
@@ -749,7 +810,7 @@ void ObjectFileDB::ir2_insert_lets(int seg, ObjectFileData& data) {
|
||||
"Error while inserting lets: {}. Make sure that the return type is not "
|
||||
"none if something is actually returned.",
|
||||
e.what());
|
||||
lg::warn(err);
|
||||
lg::warn("{}", err);
|
||||
func.warnings.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ VuDisassembler::VuDisassembler(VuKind kind) : m_kind(kind) {
|
||||
// m_upper_op6_table[0b100011].set(VuInstrK::MADDi); // 35
|
||||
// m_upper_op6_table[0b100100].set(VuInstrK::SUBq); // 36
|
||||
// m_upper_op6_table[0b100101].set(VuInstrK::MSUBq); // 37
|
||||
// m_upper_op6_table[0b100110].set(VuInstrK::SUBi); // 38
|
||||
m_upper_op6_table[0b100110].set(VuInstrK::SUBi); // 38
|
||||
// m_upper_op6_table[0b100111].set(VuInstrK::MSUBi); // 39
|
||||
m_upper_op6_table[0b101000].set(VuInstrK::ADD); // 40
|
||||
m_upper_op6_table[0b101001].set(VuInstrK::MADD); // 41
|
||||
@@ -148,6 +148,7 @@ VuDisassembler::VuDisassembler(VuKind kind) : m_kind(kind) {
|
||||
add_op(VuInstrK::MULi, "muli").iemdt().dst_mask().vft_zero().dst_vfd().src_vfs().src_i();
|
||||
add_op(VuInstrK::ADDi, "addi").iemdt().dst_mask().vft_zero().dst_vfd().src_vfs().src_i();
|
||||
add_op(VuInstrK::MULAq, "mula").iemdt().dst_mask().dst_acc().vft_zero().src_vfs().src_q();
|
||||
add_op(VuInstrK::SUBi, "subi").iemdt().dst_mask().vft_zero().dst_vfd().src_vfs().src_i();
|
||||
|
||||
m_lower_op6_table[0b000000].set(VuInstrK::LQ);
|
||||
m_lower_op6_table[0b000001].set(VuInstrK::SQ);
|
||||
|
||||
@@ -20,7 +20,7 @@ enum class VuInstrK {
|
||||
// ADDAq,
|
||||
ADDAbc,
|
||||
SUB,
|
||||
// SUBi, // 10
|
||||
SUBi, // 10
|
||||
// SUBq,
|
||||
SUBbc,
|
||||
// SUBA,
|
||||
|
||||
@@ -1427,10 +1427,15 @@ std::string inspect_inspect_method(Function& inspect_method,
|
||||
object_file_meta);
|
||||
}
|
||||
|
||||
std::string old_method_string(const MethodInfo& info) {
|
||||
std::string old_method_string(const MethodInfo& info, const bool omit_comment = false) {
|
||||
if (info.type.arg_count() > 0) {
|
||||
if (info.type.base_type() == "function" || info.type.base_type() == "state") {
|
||||
std::string result = fmt::format(" ;; ({} (", info.name);
|
||||
std::string result;
|
||||
if (omit_comment) {
|
||||
result = fmt::format(" ({} (", info.name);
|
||||
} else {
|
||||
result = fmt::format(" ;; ({} (", info.name);
|
||||
}
|
||||
bool add = false;
|
||||
for (int i = 0; i < (int)info.type.arg_count() - 1; i++) {
|
||||
result += info.type.get_arg(i).print();
|
||||
@@ -1445,11 +1450,14 @@ std::string old_method_string(const MethodInfo& info) {
|
||||
if (info.type.base_type() == "state") {
|
||||
result += " :state";
|
||||
}
|
||||
result += fmt::format(" {})", info.id);
|
||||
result += ")";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (omit_comment) {
|
||||
return fmt::format(" ({} {}) weird method", info.name, info.type.print());
|
||||
}
|
||||
return fmt::format(" ;; ({} {}) weird method", info.name, info.type.print());
|
||||
}
|
||||
|
||||
@@ -1637,81 +1645,75 @@ std::string TypeInspectorResult::print_as_deftype(
|
||||
result.append("\n ");
|
||||
}
|
||||
|
||||
std::string state_methods_list;
|
||||
std::unordered_map<int, std::string> method_states = {};
|
||||
if (object_file_meta.state_methods.count(type_name) != 0) {
|
||||
method_states = object_file_meta.state_methods.at(type_name);
|
||||
for (const auto& [method_id, state_name] : method_states) {
|
||||
MethodInfo info;
|
||||
state_methods_list += fmt::format(" {} ;; {}", state_name, method_id);
|
||||
if (old_game_type && old_game_type->get_my_method(method_id, &info)) {
|
||||
state_methods_list += ", old:" + old_method_string(info, true);
|
||||
}
|
||||
state_methods_list += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
std::string methods_list;
|
||||
if (type_method_count > 9) {
|
||||
std::string methods_list;
|
||||
std::string state_methods_list;
|
||||
|
||||
MethodInfo old_new_method;
|
||||
if (old_game_type && old_game_type->get_my_new_method(&old_new_method)) {
|
||||
methods_list.append(" ");
|
||||
methods_list.append(" (new (symbol type) _type_) ;; 0");
|
||||
methods_list.append(old_method_string(old_new_method));
|
||||
methods_list.push_back('\n');
|
||||
}
|
||||
bool done_with_state_methods = false;
|
||||
for (int i = parent_method_count; i < type_method_count; i++) {
|
||||
bool print_as_state_method = false;
|
||||
if (method_states.count(i) != 0) {
|
||||
if (!done_with_state_methods) {
|
||||
print_as_state_method = true;
|
||||
state_methods_list.append(fmt::format(" {}", method_states.at(i)));
|
||||
} else {
|
||||
methods_list.append(
|
||||
fmt::format(" ({} () _type_ :state) ;; {}", method_states.at(i), i));
|
||||
}
|
||||
} else {
|
||||
done_with_state_methods = true;
|
||||
methods_list.append(fmt::format(" ({}-method-{} () none) ;; {}", type_name, i, i));
|
||||
// If it's a state-method (virtual state) skip it
|
||||
if (method_states.find(i) != method_states.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
methods_list.append(fmt::format(" ({}-method-{} () none) ;; {}", type_name, i, i));
|
||||
if (old_game_type) {
|
||||
MethodInfo info;
|
||||
if (old_game_type->get_my_method(i, &info)) {
|
||||
if (print_as_state_method) {
|
||||
state_methods_list += old_method_string(info);
|
||||
} else {
|
||||
methods_list += old_method_string(info);
|
||||
}
|
||||
methods_list += old_method_string(info);
|
||||
}
|
||||
}
|
||||
if (print_as_state_method) {
|
||||
state_methods_list.push_back('\n');
|
||||
} else {
|
||||
methods_list.push_back('\n');
|
||||
}
|
||||
}
|
||||
if (!state_methods_list.empty()) {
|
||||
result.append("(:state-methods\n");
|
||||
result.append(state_methods_list);
|
||||
result.append(" )\n ");
|
||||
}
|
||||
if (!methods_list.empty()) {
|
||||
result.append("(:methods");
|
||||
result.append(methods_list);
|
||||
result.append(" )\n ");
|
||||
methods_list.push_back('\n');
|
||||
}
|
||||
}
|
||||
|
||||
// Print out (normal) states if we have em
|
||||
// - Could probably assume the process name comes first and associate it with the right type
|
||||
// but that may or may not be risky so, edit the types yourself...
|
||||
if (method_states.size() > 0) {
|
||||
result.append("(:states\n ");
|
||||
for (const auto& [id, name] : method_states) {
|
||||
result.append(name);
|
||||
// Append old symbol def if we have it
|
||||
auto it = previous_game_ts.symbol_types.find(name);
|
||||
// non-virtual states
|
||||
std::string non_virtual_states_list;
|
||||
for (const auto& [state_name, guessed_type_name] : object_file_meta.non_virtual_state_guesses) {
|
||||
if (type_name == guessed_type_name) {
|
||||
std::string line;
|
||||
line += fmt::format(" {}", state_name);
|
||||
auto it = previous_game_ts.symbol_types.find(state_name);
|
||||
if (it != previous_game_ts.symbol_types.end()) {
|
||||
result.append(fmt::format(" ;; {}", it->second.print()));
|
||||
line += fmt::format(" ;; associated process guessed by decompiler, old: {}",
|
||||
it->second.print());
|
||||
}
|
||||
// Add symbol name to `already_seen_symbols`
|
||||
object_file_meta.already_seen_symbols.insert(name);
|
||||
result.append("\n ");
|
||||
non_virtual_states_list.append(line + "\n");
|
||||
}
|
||||
result.append(")\n ");
|
||||
}
|
||||
// methods and virtual states
|
||||
if (!methods_list.empty()) {
|
||||
result.append("(:methods\n");
|
||||
result.append(methods_list);
|
||||
result.append(" )\n ");
|
||||
}
|
||||
if (!state_methods_list.empty()) {
|
||||
result.append("(:state-methods\n");
|
||||
result.append(state_methods_list);
|
||||
result.append(" )\n ");
|
||||
}
|
||||
// non-virtual states
|
||||
if (!non_virtual_states_list.empty()) {
|
||||
result.append("(:states\n");
|
||||
result.append(non_virtual_states_list);
|
||||
result.append(" )\n ");
|
||||
}
|
||||
|
||||
result.append(")\n");
|
||||
@@ -1800,7 +1802,8 @@ void inspect_top_level_for_metadata(Function& top_level,
|
||||
const auto& aop = top_level.ir2.atomic_ops->ops.at(i);
|
||||
const std::string as_str = aop.get()->to_string(top_level.ir2.env);
|
||||
|
||||
// Keep track of the last seen label so we can easily reference it if a later operation uses it
|
||||
// Keep track of the last seen label so we can easily reference it if a later operation uses
|
||||
// it
|
||||
auto label_match = get_regex_match(as_str, std::regex("\\(set!\\s[^\\s]*\\s(L.*)\\)"));
|
||||
if (!label_match.empty()) {
|
||||
last_seen_label = label_match;
|
||||
@@ -1843,7 +1846,24 @@ void inspect_top_level_for_metadata(Function& top_level,
|
||||
if (state_name.empty()) {
|
||||
continue;
|
||||
}
|
||||
objectFile.state_methods[type_match][method_id] = state_name;
|
||||
// Ensure there are no labels between now and when the `method-set!` is actually called
|
||||
bool was_another_label = false;
|
||||
for (int j = i; j < (int)top_level.ir2.atomic_ops->ops.size(); j++) {
|
||||
const auto& temp_aop = top_level.ir2.atomic_ops->ops.at(j);
|
||||
const std::string temp_as_str = temp_aop.get()->to_string(top_level.ir2.env);
|
||||
if (temp_as_str.find("call!") != std::string::npos) {
|
||||
break;
|
||||
}
|
||||
auto temp_label_match =
|
||||
get_regex_match(temp_as_str, std::regex("\\(set!\\s[^\\s]*\\s(L.*)\\)"));
|
||||
if (!temp_label_match.empty()) {
|
||||
was_another_label = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!was_another_label) {
|
||||
objectFile.state_methods[type_match][method_id] = state_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1858,7 +1878,8 @@ void inspect_top_level_for_metadata(Function& top_level,
|
||||
}
|
||||
|
||||
// lwu t9, 16(v1) ;; [ 21] (set! t9-0 (l.wu (+ v1-10 16)))
|
||||
// ;; [v1: <the etype type> ] -> [t9: (function symbol type int type)
|
||||
// ;; [v1: <the etype type> ] -> [t9: (function symbol type int
|
||||
// type)
|
||||
const auto& aop_1 = top_level.ir2.atomic_ops->ops.at(i + 1);
|
||||
if (!is_set_reg_to_load(aop_1.get(), Register(Reg::GPR, Reg::T9), 16)) {
|
||||
continue;
|
||||
@@ -1935,8 +1956,9 @@ std::string inspect_top_level_symbol_defines(Function& top_level,
|
||||
if (as_store && as_store->addr().kind() == SimpleExpression::Kind::IDENTITY &&
|
||||
as_store->addr().get_arg(0).is_sym_val()) {
|
||||
auto& sym_name = as_store->addr().get_arg(0).get_str();
|
||||
if (object_file_meta.already_seen_symbols.find(sym_name) ==
|
||||
object_file_meta.already_seen_symbols.end()) {
|
||||
const auto sym_already_seen = object_file_meta.already_seen_symbols.find(sym_name) !=
|
||||
object_file_meta.already_seen_symbols.end();
|
||||
if (!sym_already_seen) {
|
||||
object_file_meta.already_seen_symbols.insert(sym_name);
|
||||
if (dts.ts.partially_defined_type_exists(sym_name)) {
|
||||
continue;
|
||||
|
||||
@@ -1428,7 +1428,9 @@ Form* try_sc_as_type_of_jak2(FormPool& pool, Function& f, const ShortCircuit* vt
|
||||
f.ir2.env.disable_def(b2_delay_op.dst(), f.warnings);
|
||||
f.ir2.env.disable_use(shift_left->expr().get_arg(0).var());
|
||||
|
||||
f.warnings.warning("Using new Jak 2 rtype-of");
|
||||
if (f.ir2.env.version != GameVersion::Jak3) {
|
||||
f.warnings.warning("Using new Jak 2 rtype-of");
|
||||
}
|
||||
return b0_ptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ bool convert_to_expressions(
|
||||
"statement.",
|
||||
f.name());
|
||||
f.warnings.warning(warn);
|
||||
lg::warn(warn);
|
||||
lg::warn("{}", warn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,27 @@ goos::Object get_arg_list_for_function(const Function& func, const Env& env) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::string fix_docstring_indent(const std::string& input) {
|
||||
std::string result;
|
||||
for (auto c : input) {
|
||||
if (c == '\n') {
|
||||
result += '\n';
|
||||
for (int i = 0; i < 3; i++) {
|
||||
result += ' ';
|
||||
}
|
||||
} else {
|
||||
result += c;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void append_body_to_function_definition(goos::Object* top_form,
|
||||
const std::vector<goos::Object>& inline_body,
|
||||
const FunctionVariableDefinitions& var_dec,
|
||||
const TypeSpec& ts) {
|
||||
const TypeSpec& ts,
|
||||
GameVersion version) {
|
||||
// Some forms like docstrings and local-vars we _always_ want to be at the top level and first (in
|
||||
// the order added)
|
||||
std::vector<goos::Object> initial_top_level_forms;
|
||||
@@ -35,7 +52,12 @@ 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()) {
|
||||
initial_top_level_forms.push_back(inline_body.at(0));
|
||||
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));
|
||||
}
|
||||
body_elements.erase(body_elements.begin());
|
||||
}
|
||||
|
||||
@@ -65,7 +87,7 @@ void append_body_to_function_definition(goos::Object* top_form,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
goos::Object final_output_lambda(const Function& func) {
|
||||
goos::Object final_output_lambda(const Function& func, GameVersion version) {
|
||||
std::vector<goos::Object> inline_body;
|
||||
func.ir2.top_form->inline_forms(inline_body, func.ir2.env);
|
||||
auto var_dec = func.ir2.env.local_var_type_list(func.ir2.top_form, func.type.arg_count() - 1);
|
||||
@@ -74,11 +96,11 @@ goos::Object final_output_lambda(const Function& func) {
|
||||
if (behavior) {
|
||||
auto result = pretty_print::build_list(fmt::format("lambda :behavior {}", *behavior),
|
||||
get_arg_list_for_function(func, func.ir2.env));
|
||||
append_body_to_function_definition(&result, inline_body, var_dec, func.type);
|
||||
append_body_to_function_definition(&result, inline_body, var_dec, func.type, version);
|
||||
return result;
|
||||
} else {
|
||||
auto result = pretty_print::build_list("lambda", get_arg_list_for_function(func, func.ir2.env));
|
||||
append_body_to_function_definition(&result, inline_body, var_dec, func.type);
|
||||
append_body_to_function_definition(&result, inline_body, var_dec, func.type, version);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -115,7 +137,7 @@ goos::Object final_output_defstate_anonymous_behavior(const Function& func,
|
||||
auto var_dec = func.ir2.env.local_var_type_list(func.ir2.top_form, func.type.arg_count() - 1);
|
||||
|
||||
auto result = pretty_print::build_list("behavior", get_arg_list_for_function(func, func.ir2.env));
|
||||
append_body_to_function_definition(&result, inline_body, var_dec, func.type);
|
||||
append_body_to_function_definition(&result, inline_body, var_dec, func.type, dts.version());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -167,7 +189,7 @@ std::string final_defun_out(const Function& func,
|
||||
}
|
||||
}
|
||||
|
||||
append_body_to_function_definition(&top_form, inline_body, var_dec, func.type);
|
||||
append_body_to_function_definition(&top_form, inline_body, var_dec, func.type, dts.version());
|
||||
return pretty_print::to_string(top_form);
|
||||
}
|
||||
|
||||
@@ -188,7 +210,8 @@ std::string final_defun_out(const Function& func,
|
||||
inline_body.insert(inline_body.begin(),
|
||||
pretty_print::new_string(method_info.docstring.value()));
|
||||
}
|
||||
append_body_to_function_definition(&top_form, inline_body, var_dec, method_info.type);
|
||||
append_body_to_function_definition(&top_form, inline_body, var_dec, method_info.type,
|
||||
dts.version());
|
||||
return pretty_print::to_string(top_form);
|
||||
}
|
||||
|
||||
@@ -199,7 +222,7 @@ std::string final_defun_out(const Function& func,
|
||||
top.push_back(arguments);
|
||||
auto top_form = pretty_print::build_list(top);
|
||||
|
||||
append_body_to_function_definition(&top_form, inline_body, var_dec, func.type);
|
||||
append_body_to_function_definition(&top_form, inline_body, var_dec, func.type, dts.version());
|
||||
return pretty_print::to_string(top_form);
|
||||
}
|
||||
|
||||
@@ -212,7 +235,7 @@ std::string final_defun_out(const Function& func,
|
||||
top.push_back(arguments);
|
||||
auto top_form = pretty_print::build_list(top);
|
||||
|
||||
append_body_to_function_definition(&top_form, inline_body, var_dec, func.type);
|
||||
append_body_to_function_definition(&top_form, inline_body, var_dec, func.type, dts.version());
|
||||
return pretty_print::to_string(top_form);
|
||||
}
|
||||
|
||||
@@ -226,7 +249,7 @@ std::string final_defun_out(const Function& func,
|
||||
top.push_back(arguments);
|
||||
auto top_form = pretty_print::build_list(top);
|
||||
|
||||
append_body_to_function_definition(&top_form, inline_body, var_dec, func.type);
|
||||
append_body_to_function_definition(&top_form, inline_body, var_dec, func.type, dts.version());
|
||||
return pretty_print::to_string(top_form);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ std::string write_from_top_level(const Function& top_level,
|
||||
const std::unordered_set<std::string>& skip_functions);
|
||||
|
||||
goos::Object get_arg_list_for_function(const Function& func, const Env& env);
|
||||
goos::Object final_output_lambda(const Function& function);
|
||||
goos::Object final_output_lambda(const Function& function, GameVersion version);
|
||||
goos::Object final_output_defstate_anonymous_behavior(const Function& func,
|
||||
const DecompilerTypeSystem& dts);
|
||||
} // namespace decompiler
|
||||
@@ -87,7 +87,7 @@ bool rewrite_inline_asm_instructions(Form* top_level_form,
|
||||
} catch (std::exception& e) {
|
||||
std::string warning =
|
||||
fmt::format("ASM instruction re-writing failed in {}: {}", f.name(), e.what());
|
||||
lg::warn(warning);
|
||||
lg::warn("{}", warning);
|
||||
f.warnings.error(";; {}", warning);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -347,6 +347,7 @@ FormElement* rewrite_as_send_event(LetElement* in,
|
||||
Matcher::any_reg(1));
|
||||
break;
|
||||
case GameVersion::Jak2:
|
||||
case GameVersion::Jak3:
|
||||
// in jak 2, the event message block holds a ppointer instead.
|
||||
set_from_matcher = Matcher::set(
|
||||
Matcher::deref(Matcher::reg(block_var_reg), false, {DerefTokenMatcher::string("from")}),
|
||||
|
||||
@@ -46,7 +46,7 @@ bool try_convert_lambda(const Function& parent_function,
|
||||
if (defstate_behavior) {
|
||||
result = final_output_defstate_anonymous_behavior(*other_func, dts);
|
||||
} else {
|
||||
result = final_output_lambda(*other_func);
|
||||
result = final_output_lambda(*other_func, dts.version());
|
||||
}
|
||||
|
||||
f->clear();
|
||||
|
||||
+29
-20
@@ -97,6 +97,9 @@ Config make_config_via_json(nlohmann::json& json) {
|
||||
if (json.contains("read_spools")) {
|
||||
config.read_spools = json.at("read_spools").get<bool>();
|
||||
}
|
||||
if (json.contains("ignore_var_name_casts")) {
|
||||
config.ignore_var_name_casts = json.at("ignore_var_name_casts").get<bool>();
|
||||
}
|
||||
if (json.contains("old_all_types_file")) {
|
||||
config.old_all_types_file = json.at("old_all_types_file").get<std::string>();
|
||||
}
|
||||
@@ -156,29 +159,31 @@ Config make_config_via_json(nlohmann::json& json) {
|
||||
config.anon_function_types_by_obj_by_id[obj_file_name][id] = type_name;
|
||||
}
|
||||
}
|
||||
auto var_names_json = read_json_file_from_config(json, "var_names_file");
|
||||
for (auto& kv : var_names_json.items()) {
|
||||
auto& function_name = kv.key();
|
||||
auto arg = kv.value().find("args");
|
||||
if (arg != kv.value().end()) {
|
||||
for (auto& x : arg.value()) {
|
||||
config.function_arg_names[function_name].push_back(x);
|
||||
if (!config.ignore_var_name_casts) {
|
||||
auto var_names_json = read_json_file_from_config(json, "var_names_file");
|
||||
for (auto& kv : var_names_json.items()) {
|
||||
auto& function_name = kv.key();
|
||||
auto arg = kv.value().find("args");
|
||||
if (arg != kv.value().end()) {
|
||||
for (auto& x : arg.value()) {
|
||||
config.function_arg_names[function_name].push_back(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto var = kv.value().find("vars");
|
||||
if (var != kv.value().end()) {
|
||||
for (auto& vkv : var->get<std::unordered_map<std::string, nlohmann::json>>()) {
|
||||
LocalVarOverride override;
|
||||
if (vkv.second.is_string()) {
|
||||
override.name = vkv.second.get<std::string>();
|
||||
} else if (vkv.second.is_array()) {
|
||||
override.name = vkv.second[0].get<std::string>();
|
||||
override.type = vkv.second[1].get<std::string>();
|
||||
} else {
|
||||
throw std::runtime_error("Invalid function var override.");
|
||||
auto var = kv.value().find("vars");
|
||||
if (var != kv.value().end()) {
|
||||
for (auto& vkv : var->get<std::unordered_map<std::string, nlohmann::json>>()) {
|
||||
LocalVarOverride override;
|
||||
if (vkv.second.is_string()) {
|
||||
override.name = vkv.second.get<std::string>();
|
||||
} else if (vkv.second.is_array()) {
|
||||
override.name = vkv.second[0].get<std::string>();
|
||||
override.type = vkv.second[1].get<std::string>();
|
||||
} else {
|
||||
throw std::runtime_error("Invalid function var override.");
|
||||
}
|
||||
config.function_var_overrides[function_name][vkv.first] = override;
|
||||
}
|
||||
config.function_var_overrides[function_name][vkv.first] = override;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -309,6 +314,10 @@ Config make_config_via_json(nlohmann::json& json) {
|
||||
config.import_deps_by_file =
|
||||
import_deps.get<std::unordered_map<std::string, std::vector<std::string>>>();
|
||||
|
||||
if (json.contains("rip_collision")) {
|
||||
config.rip_collision = json.at("rip_collision").get<bool>();
|
||||
}
|
||||
|
||||
config.write_patches = json.at("write_patches").get<bool>();
|
||||
config.apply_patches = json.at("apply_patches").get<bool>();
|
||||
const auto& object_patches = json.at("object_patches");
|
||||
|
||||
@@ -121,6 +121,7 @@ struct Config {
|
||||
bool extract_collision = false;
|
||||
bool find_functions = false;
|
||||
bool read_spools = false;
|
||||
bool ignore_var_name_casts = false;
|
||||
|
||||
bool write_hex_near_instructions = false;
|
||||
bool hexdump_code = false;
|
||||
@@ -178,6 +179,8 @@ struct Config {
|
||||
std::unordered_map<std::string, std::string> joint_node_hacks;
|
||||
|
||||
std::unordered_map<std::string, std::vector<std::string>> import_deps_by_file;
|
||||
|
||||
bool rip_collision = false;
|
||||
};
|
||||
|
||||
Config read_config_file(const fs::path& path_to_config_file,
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
(z float :offset 64)
|
||||
(w float :offset 96))
|
||||
:method-count-assert 9
|
||||
:size-assert #x10
|
||||
:size-assert #x10
|
||||
:flag-assert #x900000010
|
||||
)
|
||||
|
||||
@@ -23608,7 +23608,7 @@
|
||||
(define-extern nav-enemy-turn-to-face-point (function vector float none :behavior nav-enemy))
|
||||
(define-extern nav-enemy-execute-jump (function none :behavior nav-enemy))
|
||||
(define-extern nav-enemy-jump-land-anim (function none :behavior nav-enemy)) ;; TODO
|
||||
(define-extern nav-enemy-rnd-float-range (function float float float :behavior nav-enemy))
|
||||
(define-extern nav-enemy-rnd-float-range (function float float float))
|
||||
(define-extern nav-enemy-common-post (function none :behavior nav-enemy)) ;; TODO not confirmed
|
||||
(define-extern nav-enemy-execute-custom-jump (function int float float none :behavior nav-enemy))
|
||||
(define-extern nav-enemy-initialize-custom-jump (function vector symbol float float float none :behavior nav-enemy))
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"generate_symbol_definition_map": false,
|
||||
|
||||
// genreate the all-types file
|
||||
"generate_all_types" : false,
|
||||
"generate_all_types": false,
|
||||
|
||||
// debug option for instruction decoder
|
||||
"write_hex_near_instructions": false,
|
||||
@@ -100,15 +100,17 @@
|
||||
// LEVEL EXTRACTION
|
||||
////////////////////////////
|
||||
|
||||
// turn this on to extract level background graphics data
|
||||
// turn this on to extract level background graphics data as .fr3 files in out/<game>/fr3
|
||||
"levels_extract": true,
|
||||
// turn this on if you want extracted levels to be saved out as .obj files
|
||||
// turn this on if you want extracted levels to be saved out as .glb files in glb_out/<game>
|
||||
"rip_levels": false,
|
||||
// should we extract collision meshes?
|
||||
// these can be displayed in game, but makes the .fr3 files slightly larger
|
||||
// should we also extract collision meshes to the .fr3 files?
|
||||
// these can be displayed in-game with the OpenGOAL collision renderer
|
||||
"extract_collision": true,
|
||||
// save game textures as .png files.
|
||||
"save_texture_pngs": 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,
|
||||
|
||||
////////////////////////////
|
||||
// PATCHING OPTIONS
|
||||
|
||||
@@ -7381,6 +7381,14 @@
|
||||
(progress-cheats-board-tricks #x1260)
|
||||
(progress-cheats-weather-bad #x1261)
|
||||
(progress-cheats-weather-good #x1262)
|
||||
(progress-cheats-hijack-lines #x1263)
|
||||
(progress-cheats-locked #x1264)
|
||||
(progress-cheats-turbo-board-unlock #x1265)
|
||||
(progress-cheats-health-bars-unlock #x1266)
|
||||
(progress-cheats-vehicle-health-bars-unlock #x1267)
|
||||
(progress-cheats-statistics-unlock #x1268)
|
||||
(progress-cheats-suck-in-all-unlock #x1269)
|
||||
(progress-cheats-fast-travel-unlock #x126a)
|
||||
(progress-camera-options #x1280)
|
||||
(progress-camera-options-first-horz #x1281)
|
||||
(progress-camera-options-first-vert #x1282)
|
||||
@@ -7415,6 +7423,47 @@
|
||||
(progress-shadows #x12a0)
|
||||
(progress-shadows-normal #x12a1)
|
||||
(progress-shadows-extended #x12a2)
|
||||
(progress-error-no-resolutions #x12a3)
|
||||
(progress-territory-auto #x12a4)
|
||||
(progress-kill-stats #x12a5)
|
||||
(progress-other-stats #x12a6)
|
||||
(progress-ks-total-killed #x12a7)
|
||||
(progress-ks-killed-by-jak #x12a8)
|
||||
(progress-ks-killed-by-darkjak #x12a9)
|
||||
(progress-ks-killed-by-daxter #x12aa)
|
||||
(progress-ks-killed-by-others #x12ab)
|
||||
(progress-ks-source-gun-yellow #x12ac)
|
||||
(progress-ks-source-gun-red #x12ad)
|
||||
(progress-ks-source-gun-blue #x12ae)
|
||||
(progress-ks-source-gun-dark #x12af)
|
||||
(progress-ks-source-board #x12b0)
|
||||
(progress-ks-source-board-trick #x12b1)
|
||||
(progress-ks-source-mech #x12b2)
|
||||
(progress-ks-source-mech-bonk #x12b3)
|
||||
(progress-ks-source-turret #x12b4)
|
||||
(progress-ks-source-punch #x12b5)
|
||||
(progress-ks-source-flop #x12b6)
|
||||
(progress-ks-source-uppercut #x12b7)
|
||||
(progress-ks-source-spin #x12b8)
|
||||
(progress-ks-source-roll #x12b9)
|
||||
(progress-ks-source-darkjak-punch #x12ba)
|
||||
(progress-ks-source-darkjak-flop #x12bb)
|
||||
(progress-ks-source-darkjak-uppercut #x12bc)
|
||||
(progress-ks-source-darkjak-spin #x12bd)
|
||||
(progress-ks-source-darkjak-roll #x12be)
|
||||
(progress-ks-source-darkjak-bomb0 #x12bf)
|
||||
(progress-ks-source-darkjak-bomb1 #x12c0)
|
||||
(progress-ks-source-indax-punch #x12c1)
|
||||
(progress-ks-source-indax-spin #x12c2)
|
||||
(progress-ks-source-guard #x12c3)
|
||||
(progress-ks-source-sig #x12c4)
|
||||
(progress-ks-source-ashelin #x12c5)
|
||||
(progress-ks-source-jinx #x12c6)
|
||||
(progress-ks-source-grim #x12c7)
|
||||
(progress-ks-source-mog #x12c8)
|
||||
(progress-ks-source-metalhead #x12c9)
|
||||
(progress-ks-source-other-bot #x12ca)
|
||||
(progress-ks-source-other-enemy #x12cb)
|
||||
(progress-input-options-auto-hide-cursor #x1300)
|
||||
(progress-menu-reassign-binds #x1301)
|
||||
(progress-reassign-binds-controller #x1302)
|
||||
@@ -7437,6 +7486,7 @@
|
||||
(progress-highscores-local-time #x1313)
|
||||
(progress-fps-disclaimer-warning #x1314)
|
||||
(progress-fps-disclaimer #x1315)
|
||||
(progress-highscores-local-score #x1316)
|
||||
(trick-board-none #x1320)
|
||||
(trick-board-spin #x1321)
|
||||
(trick-board-boost #x1322)
|
||||
@@ -15775,6 +15825,24 @@
|
||||
(test 22) ;; hi 64
|
||||
)
|
||||
|
||||
|
||||
;; +++game-h:knocked-type
|
||||
(defenum knocked-type
|
||||
:type uint8
|
||||
(knocked-type-0 0)
|
||||
(knocked-type-1 1)
|
||||
(knocked-type-2 2)
|
||||
(knocked-type-3 3)
|
||||
(knocked-type-4 4) ;; what the heck is this! (its on gator, and cant trigger it for the life of me)
|
||||
(knocked-type-5 5)
|
||||
(knocked-type-6 6)
|
||||
(knocked-type-7 7)
|
||||
(knocked-type-8 8)
|
||||
(knocked-type-9 9)
|
||||
(knocked-type-10 10)
|
||||
)
|
||||
;; ---game-h:knocked-type
|
||||
|
||||
(declare-type touching-shapes-entry structure)
|
||||
|
||||
(deftype attack-info (structure)
|
||||
@@ -15800,7 +15868,7 @@
|
||||
(penetrate-using penetrate :offset-assert 136)
|
||||
(damage float :offset-assert 144)
|
||||
(shield-damage float :offset-assert 148)
|
||||
(knock uint8 :offset-assert 152)
|
||||
(knock knocked-type :offset-assert 152)
|
||||
(test symbol :offset-assert 156)
|
||||
)
|
||||
:method-count-assert 12
|
||||
@@ -24877,7 +24945,7 @@
|
||||
(define-extern shadow-add-single-tris function)
|
||||
(define-extern shadow-add-double-tris function)
|
||||
(define-extern shadow-add-double-edges function)
|
||||
(define-extern debug-draw-settings (function matrix none))
|
||||
(define-extern debug-draw-settings (function shadow-settings symbol))
|
||||
(define-extern shadow-execute (function shadow-dma-packet pointer pointer))
|
||||
(define-extern shadow-vu0-upload (function none))
|
||||
(define-extern shadow-execute-all (function dma-buffer none))
|
||||
@@ -27728,7 +27796,7 @@
|
||||
(define-extern dist-info-valid? (function collide-los-dist-info symbol)) ;;
|
||||
(define-extern dist-info-append (function collide-los-dist-info vector none)) ;;
|
||||
(define-extern dist-info-print (function collide-los-dist-info string object)) ;;
|
||||
(define-extern los-cw-ccw (function (inline-array collide-cache-tri) vector vector float collide-los-result vector float symbol)) ;;
|
||||
(define-extern los-cw-ccw (function (inline-array collide-cache-tri) vector vector float collide-los-result vector float symbol :behavior camera-slave)) ;;
|
||||
(define-extern cam-los-spline-collide (function vector vector pat-surface float)) ;;
|
||||
(define-extern cam-los-setup-lateral (function collide-los-result vector vector symbol :behavior camera-slave)) ;;
|
||||
(define-extern cam-los-collide (function vector vector collide-los-result pat-surface symbol :behavior camera-slave)) ;;
|
||||
@@ -32801,42 +32869,42 @@
|
||||
(defenum enemy-flag
|
||||
:type int64
|
||||
:bitfield #t
|
||||
(lock-focus 0)
|
||||
(death-start 1)
|
||||
(enable-on-active 2)
|
||||
(checking-water 3)
|
||||
(check-water 4)
|
||||
(spawn-gem 5)
|
||||
(chase-startup 6)
|
||||
(attackable-backup 7)
|
||||
(look-at-focus 8)
|
||||
(use-notice-distance 9)
|
||||
(enable-on-notice 10)
|
||||
(look-at-move-dest 11)
|
||||
(notice 12)
|
||||
(auto-reset-penetrate 13)
|
||||
(jump-check-blocked 14)
|
||||
(drawn-mirrored 15)
|
||||
(multi-focus 16)
|
||||
(alert 17)
|
||||
(victory 18)
|
||||
(dangerous-backup 19)
|
||||
(actor-pause-backup 20)
|
||||
(trackable 21)
|
||||
(called-dying 22)
|
||||
(check-water-backup 23)
|
||||
(no-initial-move-to-ground 24)
|
||||
(cam-attack-mode 25)
|
||||
(trackable-backup 26)
|
||||
(enable-on-hostile 27)
|
||||
(directed-ready 28)
|
||||
(use-trigger 29)
|
||||
(directed 30)
|
||||
(dislike-combo 31)
|
||||
(recover-applied-velocity 32)
|
||||
(vulnerable-backup 33)
|
||||
(vulnerable 34)
|
||||
(recover 35)
|
||||
(look-at-focus 0)
|
||||
(look-at-move-dest 1)
|
||||
(vulnerable 2)
|
||||
(vulnerable-backup 3)
|
||||
(dangerous-backup 4)
|
||||
(notice 5)
|
||||
(alert 6)
|
||||
(auto-reset-penetrate 7)
|
||||
(victory 8)
|
||||
(cam-attack-mode 9)
|
||||
(use-notice-distance 10)
|
||||
(attackable-backup 11)
|
||||
(actor-pause-backup 12)
|
||||
(enable-on-notice 13)
|
||||
(enable-on-active 14)
|
||||
(enable-on-hostile 15)
|
||||
(dislike-combo 16)
|
||||
(directed 17)
|
||||
(directed-ready 18)
|
||||
(chase-startup 19)
|
||||
(lock-focus 20)
|
||||
(multi-focus 21)
|
||||
(use-trigger 22)
|
||||
(trackable 23)
|
||||
(trackable-backup 24)
|
||||
(spawn-gem 25)
|
||||
(check-water 26)
|
||||
(check-water-backup 27)
|
||||
(checking-water 28)
|
||||
(recover 29)
|
||||
(recover-applied-velocity 30)
|
||||
(drawn-mirrored 31)
|
||||
(called-dying 32)
|
||||
(no-initial-move-to-ground 33)
|
||||
(jump-check-blocked 34)
|
||||
(death-start 35)
|
||||
(enemy-flag36 36)
|
||||
(enemy-flag37 37)
|
||||
(enemy-flag38 38)
|
||||
@@ -32975,8 +33043,21 @@
|
||||
:flag-assert #x900000018
|
||||
)
|
||||
|
||||
(defenum enemy-jump-flags
|
||||
:bitfield #t
|
||||
:type uint8
|
||||
(enjflag-0)
|
||||
(enjflag-1)
|
||||
(enjflag-2)
|
||||
(enjflag-3)
|
||||
(enjflag-4)
|
||||
(enjflag-5)
|
||||
(enjflag-6)
|
||||
(enjflag-7)
|
||||
)
|
||||
|
||||
(deftype enemy-jump-info (structure)
|
||||
((flags uint8 :offset-assert 0)
|
||||
((flags enemy-jump-flags :offset-assert 0)
|
||||
(anim-speed float :offset-assert 4)
|
||||
(hang-time time-frame :offset-assert 8)
|
||||
(start-pos vector :inline :offset-assert 16)
|
||||
@@ -33000,27 +33081,13 @@
|
||||
:flag-assert #x90000002c
|
||||
)
|
||||
|
||||
;; +++enemy-h:knocked-type
|
||||
(defenum knocked-type
|
||||
:type uint8
|
||||
(knocked-type-0 0)
|
||||
(knocked-type-1 1)
|
||||
(knocked-type-2 2)
|
||||
(knocked-type-3 3)
|
||||
(knocked-type-4 4) ;; what the heck is this! (its on gator, and cant trigger it for the life of me)
|
||||
(knocked-type-5 5)
|
||||
(knocked-type-6 6)
|
||||
(knocked-type-7 7)
|
||||
)
|
||||
;; ---enemy-h:knocked-type
|
||||
|
||||
(deftype enemy-attack-info (structure)
|
||||
((attack-id uint32 :offset-assert 0)
|
||||
(knocked-type knocked-type :offset-assert 4)
|
||||
(blue-juggle-count uint8 :offset-assert 5)
|
||||
(attacker-handle handle :offset-assert 8)
|
||||
(attack-time time-frame :offset-assert 16)
|
||||
(penetrate-using uint64 :offset-assert 24)
|
||||
(penetrate-using penetrate :offset-assert 24)
|
||||
(attacker-pos vector :inline :offset-assert 32)
|
||||
(attack-direction vector :inline :offset-assert 48)
|
||||
)
|
||||
@@ -33114,7 +33181,7 @@
|
||||
"TODO"
|
||||
(_type_ process-focusable) symbol) ;; 53
|
||||
(enemy-method-54 (_type_) enemy-flag) ;; 54
|
||||
(track-target!
|
||||
(common-post
|
||||
"Does a lot of various things relating to interacting with the target
|
||||
- tracks when the enemy was last drawn
|
||||
- looks at the target and handles attacking
|
||||
@@ -33139,8 +33206,8 @@
|
||||
(enemy-method-61 (_type_ int) int :behavior enemy) ;; 61
|
||||
(enemy-method-62 (_type_) none) ;; 62
|
||||
(enemy-method-63 (_type_ process-focusable enemy-aware) symbol) ;; 63
|
||||
(enemy-method-64 (_type_) none) ;; 64
|
||||
(enemy-method-65 (_type_) none) ;; 65
|
||||
(go-dormant (_type_) object) ;; 64
|
||||
(go-dormant-aware (_type_) object) ;; 65
|
||||
(go-ambush (_type_) object) ;; 66
|
||||
(go-stare (_type_) object) ;; 67
|
||||
(go-stare2 (_type_) object) ;; 68
|
||||
@@ -33159,8 +33226,8 @@
|
||||
(_type_ process int symbol event-message-block) object) ;; 74
|
||||
(enemy-method-75 (_type_ process event-message-block) object) ;; 75
|
||||
(enemy-method-76 (_type_ process event-message-block) symbol) ;; 76
|
||||
(enemy-method-77 (_type_ (pointer float)) symbol) ;; 77
|
||||
(enemy-method-78 (_type_ (pointer float)) symbol) ;; 78
|
||||
(enemy-method-77 (_type_ enemy-knocked-info) symbol) ;; 77
|
||||
(enemy-method-78 (_type_ enemy-knocked-info) symbol) ;; 78
|
||||
(enemy-method-79 (_type_ int enemy-knocked-info) symbol) ;; 79
|
||||
(enemy-method-80 (_type_ enemy-knocked-info) symbol) ;; 80
|
||||
(enemy-method-81 (_type_) symbol) ;; 81
|
||||
@@ -33174,10 +33241,7 @@
|
||||
(enemy-method-89 (_type_ enemy-jump-info) symbol) ;; 89
|
||||
(enemy-method-90 (_type_ int enemy-jump-info) symbol) ;; 90
|
||||
(enemy-method-91 (_type_ int enemy-jump-info) none) ;; 91
|
||||
(enemy-method-92
|
||||
"TODO - nav-poly is a guess
|
||||
@abstract"
|
||||
(_type_ int nav-poly) none) ;; 92
|
||||
(enemy-method-92 "@abstract" (_type_ int enemy-jump-info) none) ;; 92
|
||||
(enemy-method-93 (_type_) none) ;; 93
|
||||
(enemy-method-94 (_type_ vector float) symbol) ;; 94
|
||||
(enemy-method-95 (_type_ vector float) symbol) ;; 95
|
||||
@@ -33197,11 +33261,11 @@
|
||||
(enemy-method-103 (_type_) collide-spec) ;; 103
|
||||
(enemy-method-104 (_type_ process touching-shapes-entry uint) symbol :behavior process) ;; 104
|
||||
(enemy-method-105 (_type_ process) enemy-flag) ;; 105
|
||||
(enemy-method-106 (_type_ process object int attack-info) none :behavior enemy) ;; 106
|
||||
(set-incoming-attack-info (_type_ process object penetrate attack-info) none :behavior enemy) ;; 106
|
||||
(get-enemy-target
|
||||
"@returns the [[process-focusable]] that the enemy is currently focusing on, or [[#f]] otherwise"
|
||||
(_type_) process-focusable) ;; 107
|
||||
(enemy-method-108 (_type_ enemy event-message-block) int) ;; 108
|
||||
(enemy-method-108 (_type_ process-drawable event-message-block) int) ;; 108
|
||||
(look-at-target!
|
||||
"Logic for looking at the target that is locked on, sets some flags and adjusts the neck to look at the target if available
|
||||
@param flag Reacts to [[enemy-flag::death-start]] and [[enemy-flag::enable-on-active]], see implementation for details"
|
||||
@@ -33224,33 +33288,32 @@
|
||||
"Common method called to initialize the enemy, typically sets up default field values and calls ancillary helper methods"
|
||||
(_type_) none) ;; 115
|
||||
(go-idle (_type_) none) ;; 116
|
||||
(get-rand-float
|
||||
(rnd-float
|
||||
"@returns the result of calling [[rand-vu]]"
|
||||
(_type_) float) ;; 117
|
||||
(get-rand-float-range
|
||||
(rnd-float-range
|
||||
"@param low The lower bound of the range (inclusive)
|
||||
@param high The upper bound of the range (exclusive)
|
||||
@returns A random float in the specified range"
|
||||
(_type_ float float) float) ;; 118
|
||||
(get-rand-int
|
||||
(rnd-int-count
|
||||
"@param high The upper bound of the range (exclusive)
|
||||
@returns a random integer in the range 0 to `high`
|
||||
@see [[rand-vu]]"
|
||||
(_type_ int) int) ;; 119
|
||||
(enemy-method-120 "TODO" (_type_ int int) int) ;; 120
|
||||
(get-rand-int-range
|
||||
(rnd-bit "TODO" (_type_ int int) int) ;; 120
|
||||
(rnd-int-range
|
||||
"@param low The lower bound of the range (inclusive)
|
||||
@param high The upper bound of the range (exclusive)
|
||||
@returns A random integer in the specified range"
|
||||
(_type_ int int) int) ;; 121
|
||||
(rng-hit?
|
||||
"TODO - not the best name
|
||||
@param chance The value to compare ([[>=]]) with the result from [[rand-vu]].
|
||||
(rnd-percent?
|
||||
"@param chance The value to compare ([[>=]]) with the result from [[rand-vu]].
|
||||
@returns If `chance` is greater than the random draw"
|
||||
(_type_ float) symbol) ;; 122
|
||||
(enemy-method-123 "TODO" (_type_ float) symbol) ;; 123
|
||||
(rnd-go-idle? "TODO" (_type_ float) symbol) ;; 123
|
||||
(enemy-method-124 "TODO" (_type_) collide-spec) ;; 124
|
||||
(enemy-method-125 (_type_ collide-query collide-spec float float float) pat-surface) ;; 125
|
||||
(ground-pat-set! (_type_ collide-query collide-spec float float float) pat-surface) ;; 125
|
||||
(enemy-above-ground?
|
||||
"@returns if the enemy is above the ground or not
|
||||
@see [[above-ground?]]"
|
||||
@@ -33259,12 +33322,12 @@
|
||||
(enemy-method-128 (_type_ vector move-above-ground-params) none) ;; 128
|
||||
(enemy-method-129 (_type_) none) ;; 129
|
||||
(enemy-method-130 (_type_ float) symbol) ;; 130
|
||||
(enemy-method-131 (_type_ int) uint) ;; 131
|
||||
(dispose!
|
||||
(penetrate-using->knocked (_type_ penetrate) knocked-type) ;; 131
|
||||
(dying
|
||||
"Cleans-up the enemy and any associated resources. Potentially spawns skull gems"
|
||||
(_type_) none) ;; 132
|
||||
(enemy-method-133 (_type_) symbol) ;; 133
|
||||
(enemy-method-134 (_type_ process attack-info) process-focusable) ;; 134
|
||||
(get-attacker (_type_ process attack-info) process-focusable) ;; 134
|
||||
(enemy-method-135 (_type_ int) sound-id) ;; 135
|
||||
(enemy-method-136 (_type_) enemy-flag) ;; 136
|
||||
)
|
||||
@@ -34814,7 +34877,7 @@
|
||||
(unknown-byte-n1k2n3 int8 :offset 636)
|
||||
(unknown-byte-m2j342 int8 :offset 637)
|
||||
(unknown-byte-1ji2n3 int8 :offset 638)
|
||||
(unknown-byte-n123n int8 :offset 639)
|
||||
(unknown-byte-n123n uint8 :offset 639)
|
||||
(state-timeout2 uint64 :offset-assert 640)
|
||||
(next-warn-time time-frame :offset-assert 648)
|
||||
(dest vector :inline :offset-assert 656)
|
||||
@@ -38515,7 +38578,7 @@
|
||||
charge
|
||||
)
|
||||
(:methods
|
||||
(rhino-method-182 (_type_ process event-message-block) symbol) ;; 182
|
||||
(hit-stomach? (_type_ process event-message-block) symbol) ;; 182
|
||||
)
|
||||
)
|
||||
|
||||
@@ -39415,7 +39478,7 @@
|
||||
(hit-by-enemy-count uint16 :offset-assert 698)
|
||||
(hit-by-player-count uint16 :offset-assert 700)
|
||||
(notice-enemy-dist float :offset-assert 704)
|
||||
(channel uint8 :offset-assert 708)
|
||||
(channel gui-channel :offset-assert 708)
|
||||
(focus-mode int8 :offset-assert 709)
|
||||
(nav-mesh-index int8 :offset-assert 710)
|
||||
(delay-too-far-check int8 :offset-assert 711)
|
||||
@@ -39478,13 +39541,13 @@
|
||||
(play-speech (_type_ int) none) ;; 206
|
||||
(play-death-sound "Play one of our death sounds." (_type_ string) none) ;; 207
|
||||
(bot-method-208 (_type_) symbol) ;; 208
|
||||
(channel-active? "Is the given [[gui-channel]] active?" (_type_ uint) symbol) ;; 209
|
||||
(channel-active? "Is the given [[gui-channel]] active?" (_type_ gui-channel) symbol) ;; 209
|
||||
(init! "Set defaults for various fields." (_type_) none) ;; 210
|
||||
(clear-speech-flags! "Clear the `playing` flag for all of our speeches." (_type_) none) ;; 211
|
||||
(reset-warn-time! (_type_) none) ;; 212
|
||||
(go-to-waypoint! "Start moving to the given [[bot-waypoint]]." (_type_ int symbol) object) ;; 213
|
||||
(bot-method-214 (_type_) symbol) ;; 214
|
||||
(skip-waypoint (_type_) none) ;; 215
|
||||
(skip-waypoint (_type_) object) ;; 215
|
||||
(bot-method-216 (_type_) none) ;; 216
|
||||
(speech-ended? "Is the given speech active?" (_type_ int) symbol) ;; 217
|
||||
(speech-playing? "Is the given speech playing?" (_type_ int) symbol) ;; 218
|
||||
@@ -43427,7 +43490,7 @@
|
||||
(define-extern set-countdown-to-roar (function none :behavior metalkor))
|
||||
(define-extern metalkor-go-next-stage (function none :behavior metalkor))
|
||||
(define-extern metalkor-setup-hit-anim (function attack-info process-drawable art-element art-element float none :behavior metalkor))
|
||||
(define-extern metalkor-get-gem-tracker (function process-focusable none :behavior metalkor))
|
||||
(define-extern metalkor-get-gem-tracker (function process-focusable gem-tracker :behavior metalkor))
|
||||
(define-extern metalkor-handler (function process int symbol event-message-block object :behavior metalkor))
|
||||
(define-extern metalkor-start-egg (function symbol :behavior metalkor))
|
||||
(define-extern metalkor-check-egg (function symbol :behavior metalkor))
|
||||
@@ -50579,13 +50642,15 @@
|
||||
(
|
||||
(ai-hook (function vehicle-guard none) :offset-assert 880)
|
||||
(turret turret-control :inline :offset-assert 888)
|
||||
(target-flags turret-flag :offset-assert 968)
|
||||
(target-flags traffic-target-flag :offset-assert 968)
|
||||
(target-in-sight-time time-frame :offset-assert 976)
|
||||
(minimap connection-minimap :offset-assert 984)
|
||||
(vehicle-guard-pad-k1jn23k1 uint32 :offset-assert 988)
|
||||
(traffic-target-status traffic-target-status :offset-assert 992)
|
||||
(pursuit-target handle :offset-assert 1000)
|
||||
(vehicle-guard-pad-1kjh2nb3k1 uint32 16 :offset-assert 1008)
|
||||
(vehicle-guard-pad-0jkfdjslf uint32 4 :offset-assert 1008)
|
||||
(vehicle-guard-vector0341413 vector :inline :offset-assert 1024)
|
||||
(vehicle-guard-pad-1kjh2nb3k1 uint32 8 :offset-assert 1040)
|
||||
(lod2 symbol :offset-assert 1072)
|
||||
)
|
||||
:method-count-assert 159
|
||||
@@ -50616,7 +50681,7 @@
|
||||
(define-extern vehicle-draw-beam (function sparticle-launcher vector vector object symbol none))
|
||||
(define-extern vehicle-draw-laser-spot (function vector vector symbol none))
|
||||
(define-extern vehicle-draw-laser (function vector vector none))
|
||||
(define-extern vehicle-guard-choose-branch (function vehicle-controller vehicle nav-branch))
|
||||
(define-extern vehicle-guard-choose-branch (function vehicle-controller vehicle-guard nav-branch))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; transport ;;
|
||||
@@ -52949,7 +53014,9 @@
|
||||
(deftype mechblock (process-drawable)
|
||||
((root collide-shape-moving :override)
|
||||
(origin vector :inline :offset-assert 208)
|
||||
(drop-point vector :inline :offset 256)
|
||||
(unknown-quat quaternion :inline :offset-assert 224)
|
||||
(unknown-vector vector :inline :offset-assert 240)
|
||||
(drop-point vector :inline :offset-assert 256)
|
||||
(allow-drag? symbol :offset-assert 272)
|
||||
(reset-on-land? symbol :offset-assert 276)
|
||||
(hit-something? symbol :offset-assert 280)
|
||||
@@ -53473,4 +53540,4 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define-extern *default-envmap-shader* adgif-shader)
|
||||
(define-extern *generic-envmap-texture* texture)
|
||||
(define-extern *generic-envmap-texture* texture)
|
||||
@@ -110,14 +110,16 @@
|
||||
// LEVEL EXTRACTION
|
||||
////////////////////////////
|
||||
|
||||
// turn this on to extract level background graphics data
|
||||
// turn this on to extract level background graphics data as .fr3 files in out/<game>/fr3
|
||||
"levels_extract": true,
|
||||
// turn this on if you want extracted levels to be saved out as .obj files
|
||||
// turn this on if you want extracted levels to be saved out as .glb files in glb_out/<game>
|
||||
"rip_levels": false,
|
||||
// should we extract collision meshes?
|
||||
// these can be displayed in game, but makes the .fr3 files slightly larger
|
||||
// should we also extract collision meshes to the .fr3 files?
|
||||
// these can be displayed in-game with the OpenGOAL collision renderer
|
||||
"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,
|
||||
|
||||
////////////////////////////
|
||||
|
||||
@@ -654,7 +654,7 @@
|
||||
"collectables": [[69, "(function part-tracker vector)"]],
|
||||
"mech-states": [[50, "(function none :behavior target)"]],
|
||||
"target-mech": [
|
||||
[7, "(function none :behavior target)"],
|
||||
[7, "(function none :behavior manipy)"],
|
||||
[8, "(function none :behavior mech)"],
|
||||
[9, "(function none :behavior manipy)"],
|
||||
[18, "(function surface object surface int none :behavior target)"],
|
||||
@@ -1227,8 +1227,8 @@
|
||||
"castle-baron": [[7, "(function collectable none)"]],
|
||||
"metalkor-extras": [[65, "(function vector :behavior metalkor-shot)"]],
|
||||
"metalkor-setup": [
|
||||
[1, "(function gem-tracker none)"],
|
||||
[2, "(function gem-tracker none)"]
|
||||
[1, "(function gem-tracker symbol)"],
|
||||
[2, "(function gem-tracker symbol)"]
|
||||
],
|
||||
"meet-brutter": [
|
||||
[0, "(function none :behavior task-manager)"],
|
||||
|
||||
@@ -4309,7 +4309,8 @@
|
||||
"(method 74 enemy)": [
|
||||
[50, "s3", "process-drawable"],
|
||||
[94, "v1", "attack-info"],
|
||||
[[111, 205], "s2", "attack-info"],
|
||||
[[111, 137], "s2", "attack-info"],
|
||||
[204, "s2", "attack-info"],
|
||||
[554, "a0", "vector"]
|
||||
],
|
||||
"(method 56 enemy)": [[[0, 6], "v1", "attack-info"]],
|
||||
@@ -4537,7 +4538,7 @@
|
||||
],
|
||||
"(method 23 joint-exploder)": [[26, "v1", "process-drawable"]],
|
||||
"(method 28 joint-exploder)": [[[0, 250], "s5", "joint-exploder-list"]],
|
||||
"joint-exploder-joint-callback": [[3, "s4", "joint-exploder"]],
|
||||
"joint-exploder-joint-callback": [[[3, 25], "s4", "joint-exploder"]],
|
||||
"(event idle fort-trap-door)": [[4, "v1", "attack-info"]],
|
||||
"(code idle hide-light)": [[10, "v1", "art-joint-anim"]],
|
||||
"(event impact turret-shot)": [[11, "s4", "process-drawable"]],
|
||||
@@ -4968,10 +4969,6 @@
|
||||
],
|
||||
"(enter target-mech-carry-hit-ground)": [[3, "v0", "sound-rpc-set-param"]],
|
||||
"(event target-mech-grab)": [[24, "a0", "process"]],
|
||||
"(anon-function 7 target-mech)": [
|
||||
[32, "a0", "joint-mod-ik"],
|
||||
[26, "a0", "(array joint-mod-ik)"]
|
||||
],
|
||||
"(enter target-mech-hit-ground)": [[3, "v0", "sound-rpc-set-param"]],
|
||||
"(exit target-mech-carry-drag)": [
|
||||
[11, "v0", "sound-rpc-set-param"],
|
||||
@@ -7064,7 +7061,7 @@
|
||||
],
|
||||
"(method 9 city-level-info)": [[387, "v1", "nav-segment"]],
|
||||
"(method 67 traffic-engine)": [
|
||||
[[137, 183], "s0", "crimson-guard"],
|
||||
[[137, 185], "s0", "crimson-guard"],
|
||||
[[44, 86], "a3", "vehicle"]
|
||||
],
|
||||
"set-eye-draw-flag": [[20, "s5", "eye-control"]],
|
||||
@@ -10155,5 +10152,8 @@
|
||||
"race-birth-func-texture-position-word": [
|
||||
[10, "v1", "(array int32)"],
|
||||
[1, "v1", "(array int32)"]
|
||||
]
|
||||
],
|
||||
"(method 206 hal)": [[32, "a2", "bot"]],
|
||||
"(method 209 hal)": [[32, "v1", "bot"]],
|
||||
"(method 220 hal)": [[29, "v1", "bot"]]
|
||||
}
|
||||
@@ -4228,7 +4228,9 @@
|
||||
"vars": {
|
||||
"v1-3": "shadow-settings",
|
||||
"a3-0": "shadow-geo",
|
||||
"t0-0": "dist"
|
||||
"t0-0": "dist",
|
||||
"a3-2": ["shadow-pack1", "shadow-dma-packet"],
|
||||
"t2-11": ["shadow-pack2", "shadow-dma-packet"]
|
||||
}
|
||||
},
|
||||
"progress-selected": {
|
||||
@@ -4637,5 +4639,27 @@
|
||||
"vars": {
|
||||
"t1-3": ["imp-sound", "sound-name"]
|
||||
}
|
||||
},
|
||||
"(method 9 menu-secret-option)": {
|
||||
"vars": {
|
||||
"s5-1": "hero?",
|
||||
"s3-0": "min-item",
|
||||
"s2-0": "max-item",
|
||||
"s5-2": "scroll-sound?",
|
||||
"v1-74": "item",
|
||||
"a0-54": "flag",
|
||||
"a1-9": "on-off?"
|
||||
}
|
||||
},
|
||||
"(method 10 menu-unlocked-menu-option)": {
|
||||
"vars": {
|
||||
"s5-0": "secrets",
|
||||
"f30-0": "alpha"
|
||||
}
|
||||
},
|
||||
"joint-exploder-joint-callback": {
|
||||
"vars": {
|
||||
"s4-0": ["exploder", "joint-exploder"]
|
||||
}
|
||||
}
|
||||
}
|
||||
+71131
-298
File diff suppressed because it is too large.
Load diff
@@ -80,7 +80,7 @@
|
||||
////////////////////////////
|
||||
// CONFIG FILES
|
||||
////////////////////////////
|
||||
|
||||
|
||||
"type_casts_file": "decompiler/config/jak3/ntsc_v1/type_casts.jsonc",
|
||||
"anonymous_function_types_file": "decompiler/config/jak3/ntsc_v1/anonymous_function_types.jsonc",
|
||||
"var_names_file": "decompiler/config/jak3/ntsc_v1/var_names.jsonc",
|
||||
@@ -102,14 +102,16 @@
|
||||
// LEVEL EXTRACTION
|
||||
////////////////////////////
|
||||
|
||||
// turn this on to extract level background graphics data
|
||||
// turn this on to extract level background graphics data as .fr3 files in out/<game>/fr3
|
||||
"levels_extract": false,
|
||||
// turn this on if you want extracted levels to be saved out as .obj files
|
||||
// turn this on if you want extracted levels to be saved out as .glb files in glb_out/<game>
|
||||
"rip_levels": false,
|
||||
// should we extract collision meshes?
|
||||
// these can be displayed in game, but makes the .fr3 files slightly larger
|
||||
// should we also extract collision meshes to the .fr3 files?
|
||||
// these can be displayed in-game with the OpenGOAL collision renderer
|
||||
"extract_collision": false,
|
||||
|
||||
// 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,
|
||||
|
||||
////////////////////////////
|
||||
@@ -125,5 +127,14 @@
|
||||
"apply_patches": true,
|
||||
// what to patch an object to and what the patch file is
|
||||
"object_patches": {
|
||||
},
|
||||
"version_overrides": {
|
||||
"ntsc_v1": {},
|
||||
"pal": {
|
||||
"game_name": "jak3_pal",
|
||||
"expected_elf_name": "SCES_524.60",
|
||||
"is_pal": true,
|
||||
"object_patches": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1,14 @@
|
||||
{}
|
||||
{
|
||||
"gkernel": [
|
||||
[17, "(function process symbol)"],
|
||||
[24, "(function process symbol)"],
|
||||
[26, "(function process symbol)"],
|
||||
[29, "(function process symbol)"],
|
||||
[32, "(function process symbol)"],
|
||||
[34, "(function process symbol)"],
|
||||
[36, "(function process symbol)"]
|
||||
],
|
||||
"profile": [
|
||||
[3, "(function profile-segment-array profile-collapse none)"]
|
||||
]
|
||||
}
|
||||
@@ -126,6 +126,7 @@
|
||||
// will be less picky about types related to pairs.
|
||||
"pair_functions_by_name": [
|
||||
"ref",
|
||||
"ref&",
|
||||
"(method 4 pair)",
|
||||
"last",
|
||||
"member",
|
||||
@@ -755,14 +756,21 @@
|
||||
"generic-warp-dest",
|
||||
"generic-warp-envmap-dest",
|
||||
"generic-no-light-proc"
|
||||
|
||||
],
|
||||
|
||||
"mips2c_jump_table_functions": {},
|
||||
|
||||
// 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": [["lfac", 0, 0], ["ltow", 0, 0], ["lcit", 0, 0], ["pow", 0, 0], ["wasintro", 0, 0], ["lfacctyb", 0, 0], ["intpfall", 0, 0]],
|
||||
"missing_textures": [
|
||||
["lfac", 0, 0],
|
||||
["ltow", 0, 0],
|
||||
["lcit", 0, 0],
|
||||
["pow", 0, 0],
|
||||
["wasintro", 0, 0],
|
||||
["lfacctyb", 0, 0],
|
||||
["intpfall", 0, 0]
|
||||
],
|
||||
|
||||
// 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.
|
||||
|
||||
@@ -7,285 +7,285 @@
|
||||
// most objects are part of CGO/DGO files (both go in dgo_names). This includes levels and the engine
|
||||
// the DGOs will be processed in this order. Usually it's best to have KERNEL, ENGINE, then the levels when
|
||||
// you want to run on the entire game.
|
||||
"dgo_names":[
|
||||
"dgo_names": [
|
||||
//"CGO/ART.CGO",
|
||||
"CGO/KERNEL.CGO",
|
||||
// "CGO/ENGINE.CGO",
|
||||
"CGO/GAME.CGO",
|
||||
"CGO/GAME.CGO"
|
||||
// "CGO/COMMON.CGO",
|
||||
"DGO/LJKDMPK.DGO",
|
||||
"DGO/LBBSDRP1.DGO",
|
||||
"DGO/LTNJXHIP.DGO",
|
||||
"DGO/MIC.DGO",
|
||||
"DGO/OASISCST.DGO",
|
||||
"DGO/CTYPEPA.DGO",
|
||||
"DGO/LPRENME.DGO",
|
||||
"DGO/LFREEOUT.DGO",
|
||||
"DGO/LGUNNORM.DGO",
|
||||
"DGO/LTOWA.DGO",
|
||||
"DGO/TEMA.DGO",
|
||||
"DGO/CTA.DGO",
|
||||
"DGO/LPRECC.DGO",
|
||||
"DGO/LJKDXVIN.DGO",
|
||||
"DGO/CTYPEPC.DGO",
|
||||
"DGO/SEA.DGO",
|
||||
"DGO/COMBE.DGO",
|
||||
"DGO/CTYPESA.DGO",
|
||||
"DGO/LBLOWCST.DGO",
|
||||
"DGO/WSD.DGO",
|
||||
"DGO/LBBRING3.DGO",
|
||||
"DGO/LCTYPATK.DGO",
|
||||
"DGO/WCB.DGO",
|
||||
"DGO/DESRESC.DGO",
|
||||
"DGO/LBBRING4.DGO",
|
||||
"DGO/GRIDCST.DGO",
|
||||
"DGO/RAILX.DGO",
|
||||
"DGO/SEJ.DGO",
|
||||
"DGO/LJAKC.DGO",
|
||||
"DGO/CTB.DGO",
|
||||
"DGO/CTYCARC.DGO",
|
||||
"DGO/LMECH.DGO",
|
||||
"DGO/LBBSDRP2.DGO",
|
||||
"DGO/NSA.DGO",
|
||||
"DGO/LBBTCHA3.DGO",
|
||||
"DGO/GUNGAME2.DGO",
|
||||
"DGO/CTC.DGO",
|
||||
"DGO/LVINCST.DGO",
|
||||
"DGO/COMBX.DGO",
|
||||
"DGO/DESH.DGO",
|
||||
"DGO/DESRACE2.DGO",
|
||||
"DGO/RAILD.DGO",
|
||||
"DGO/FACC.DGO",
|
||||
"DGO/CTYPESC.DGO",
|
||||
"DGO/LWASBBV.DGO",
|
||||
"DGO/TOWB.DGO",
|
||||
"DGO/HGA.DGO",
|
||||
"DGO/SEH.DGO",
|
||||
"DGO/MHCTYCST.DGO",
|
||||
"DGO/GUNGAME1.DGO",
|
||||
"DGO/INTROCST.DGO",
|
||||
"DGO/DESJUMP.DGO",
|
||||
"DGO/SEM.DGO",
|
||||
"DGO/SEI.DGO",
|
||||
"DGO/DESG.DGO",
|
||||
"DGO/DESW.DGO",
|
||||
"DGO/LOUTRO3.DGO",
|
||||
"DGO/LDAMKLEV.DGO",
|
||||
"DGO/DESERROL.DGO",
|
||||
"DGO/RAILB2.DGO",
|
||||
"DGO/LERROL.DGO",
|
||||
"DGO/IPF.DGO",
|
||||
"DGO/RAILB.DGO",
|
||||
"DGO/LCTYHIJK.DGO",
|
||||
"DGO/CTYPEPB.DGO",
|
||||
"DGO/PRECB.DGO",
|
||||
"DGO/LFORM.DGO",
|
||||
"DGO/WASLEAPR.DGO",
|
||||
"DGO/LKEIRA.DGO",
|
||||
"DGO/LJAK.DGO",
|
||||
"DGO/SLUMBSET.DGO",
|
||||
"DGO/FACD.DGO",
|
||||
"DGO/LWASSIG.DGO",
|
||||
"DGO/LBIPED.DGO",
|
||||
"DGO/DESD.DGO",
|
||||
"DGO/CFB.DGO",
|
||||
"DGO/FREECAST.DGO",
|
||||
"DGO/SEG.DGO",
|
||||
"DGO/FACTORYA.DGO",
|
||||
"DGO/LPATK.DGO",
|
||||
"DGO/FRSTX.DGO",
|
||||
"DGO/SEB.DGO",
|
||||
"DGO/DESBCST.DGO",
|
||||
"DGO/DESE.DGO",
|
||||
"DGO/DESOASIS.DGO",
|
||||
"DGO/CTYCARA.DGO",
|
||||
"DGO/LSIGKLV.DGO",
|
||||
"DGO/CIB.DGO",
|
||||
"DGO/LBBRING2.DGO",
|
||||
"DGO/LTNFXHIP.DGO",
|
||||
"DGO/MIA.DGO",
|
||||
"DGO/MHCB.DGO",
|
||||
"DGO/LNSTOBC.DGO",
|
||||
"DGO/COMBD.DGO",
|
||||
"DGO/RBCT.DGO",
|
||||
"DGO/LTORNJNX.DGO",
|
||||
"DGO/DESBATTL.DGO",
|
||||
"DGO/SEK.DGO",
|
||||
"DGO/LSNKWHLS.DGO",
|
||||
"DGO/LMHCB.DGO",
|
||||
"DGO/LBOMBBOT.DGO",
|
||||
"DGO/OUTCAST3.DGO",
|
||||
"DGO/LBLOWTMH.DGO",
|
||||
"DGO/TEMD.DGO",
|
||||
"DGO/LTOWCITY.DGO",
|
||||
"DGO/OUTROCST.DGO",
|
||||
"DGO/WASCAST.DGO",
|
||||
"DGO/LFACRM2.DGO",
|
||||
"DGO/WASPGAME.DGO",
|
||||
"DGO/RAILE.DGO",
|
||||
"DGO/CTYPESB.DGO",
|
||||
"DGO/DESBOSS1.DGO",
|
||||
"DGO/FREEHQ.DGO",
|
||||
"DGO/LTORN.DGO",
|
||||
"DGO/TOWERA.DGO",
|
||||
"DGO/LSAMOS.DGO",
|
||||
"DGO/LFORP.DGO",
|
||||
"DGO/CFA.DGO",
|
||||
"DGO/LJINX.DGO",
|
||||
"DGO/SEO.DGO",
|
||||
"DGO/PRECA.DGO",
|
||||
"DGO/TOWERC.DGO",
|
||||
"DGO/WCA.DGO",
|
||||
"DGO/SEC.DGO",
|
||||
"DGO/DESF.DGO",
|
||||
"DGO/SEL.DGO",
|
||||
"DGO/LCTYDEST.DGO",
|
||||
"DGO/LTORNSAM.DGO",
|
||||
"DGO/MUSEUM3B.DGO",
|
||||
"DGO/SEE.DGO",
|
||||
"DGO/DESHUNT.DGO",
|
||||
"DGO/RAILA.DGO",
|
||||
"DGO/TITLE.DGO",
|
||||
"DGO/RUBC.DGO",
|
||||
"DGO/DESB.DGO",
|
||||
"DGO/LFACCAR.DGO",
|
||||
"DGO/LNSTOA.DGO",
|
||||
"DGO/MUSEUM3.DGO",
|
||||
"DGO/ONINTENT.DGO",
|
||||
"DGO/STA.DGO",
|
||||
"DGO/WASSTADA.DGO",
|
||||
"DGO/POWERGD.DGO",
|
||||
"DGO/LKLEEVER.DGO",
|
||||
"DGO/FACB.DGO",
|
||||
"DGO/LCTYASS.DGO",
|
||||
"DGO/MHCA.DGO",
|
||||
"DGO/LTOWB.DGO",
|
||||
"DGO/LNSTCST.DGO",
|
||||
"DGO/DESRESCG.DGO",
|
||||
"DGO/INTPALRF.DGO",
|
||||
"DGO/LMHCA.DGO",
|
||||
"DGO/TOWERCST.DGO",
|
||||
"DGO/RAILF.DGO",
|
||||
"DGO/CIA.DGO",
|
||||
"DGO/CTYCARKG.DGO",
|
||||
"DGO/WASCHASE.DGO",
|
||||
"DGO/LFACO.DGO",
|
||||
"DGO/WIN.DGO",
|
||||
"DGO/TEMPLEE.DGO",
|
||||
"DGO/LBBSPIRT.DGO",
|
||||
"DGO/MUSEUM2.DGO",
|
||||
"DGO/INTTITLE.DGO",
|
||||
"DGO/STAA.DGO",
|
||||
"DGO/MUSEUM4B.DGO",
|
||||
"DGO/PRECD.DGO",
|
||||
"DGO/SEF.DGO",
|
||||
"DGO/CTYCARB.DGO",
|
||||
"DGO/WASDEFEN.DGO",
|
||||
"DGO/LBLOWTKG.DGO",
|
||||
"DGO/DESA.DGO",
|
||||
"DGO/COMBB.DGO",
|
||||
"DGO/WASSTADC.DGO",
|
||||
"DGO/DESC.DGO",
|
||||
"DGO/LDAMPECK.DGO",
|
||||
"DGO/LJAKSIG.DGO",
|
||||
"DGO/HALFPIPE.DGO",
|
||||
"DGO/DESRACE1.DGO",
|
||||
"DGO/SEN.DGO",
|
||||
"DGO/TEMP.DGO",
|
||||
"DGO/SED.DGO",
|
||||
"DGO/LFACB.DGO",
|
||||
"DGO/LCTYSNPR.DGO",
|
||||
"DGO/LBBSPID.DGO",
|
||||
"DGO/FRSTA.DGO",
|
||||
"DGO/LBBRING5.DGO",
|
||||
"DGO/LBBSPRT3.DGO",
|
||||
"DGO/HHG.DGO",
|
||||
"DGO/LBBSPRT2.DGO",
|
||||
"DGO/CGB.DGO",
|
||||
"DGO/LDMPCKGN.DGO",
|
||||
"DGO/LSEEMWCA.DGO",
|
||||
"DGO/HGB.DGO",
|
||||
"DGO/LONINSIM.DGO",
|
||||
"DGO/RUBA.DGO",
|
||||
"DGO/DESRALLY.DGO",
|
||||
"DGO/WWD.DGO",
|
||||
"DGO/STB.DGO",
|
||||
"DGO/MIB.DGO",
|
||||
"DGO/LCTYBLOW.DGO",
|
||||
"DGO/LWSTDPCK.DGO",
|
||||
"DGO/MUSEUM.DGO",
|
||||
"DGO/LJAKCKLV.DGO",
|
||||
"DGO/LBBRING1.DGO",
|
||||
"DGO/MUSEUM4.DGO",
|
||||
"DGO/LFACRM1.DGO",
|
||||
"DGO/LJKCDMKL.DGO",
|
||||
"DGO/LDAMSIG.DGO",
|
||||
"DGO/DESTRACK.DGO",
|
||||
"DGO/GGA.DGO",
|
||||
"DGO/RAILC.DGO",
|
||||
"DGO/LBBTCHA2.DGO",
|
||||
"DGO/DESINTER.DGO",
|
||||
"DGO/NSB.DGO",
|
||||
"DGO/LOUTRO.DGO",
|
||||
"DGO/VIN.DGO",
|
||||
"DGO/LDESGCST.DGO",
|
||||
"DGO/WARPCAST.DGO",
|
||||
"DGO/LBBRING6.DGO",
|
||||
"DGO/FRSTB.DGO",
|
||||
"DGO/TEMC.DGO",
|
||||
"DGO/COMBC.DGO",
|
||||
"DGO/LTRTWHLS.DGO",
|
||||
"DGO/PRECC.DGO",
|
||||
"DGO/DESCHASE.DGO",
|
||||
"DGO/CITYCAST.DGO",
|
||||
"DGO/CPO.DGO",
|
||||
"DGO/LFACCITY.DGO",
|
||||
"DGO/RAILCST.DGO",
|
||||
"DGO/LJNDKLEV.DGO",
|
||||
"DGO/CWI.DGO",
|
||||
"DGO/MINEE.DGO",
|
||||
"DGO/LFORRING.DGO",
|
||||
"DGO/LASHELIN.DGO",
|
||||
"DGO/LJAKKLEV.DGO",
|
||||
"DGO/LCTYPALT.DGO",
|
||||
"DGO/LNSTOBB.DGO",
|
||||
"DGO/LJKFEET.DGO",
|
||||
"DGO/DST.DGO",
|
||||
"DGO/LBBTCHA1.DGO",
|
||||
"DGO/LGUNRNC.DGO",
|
||||
"DGO/COMBN.DGO",
|
||||
"DGO/DESRESCC.DGO",
|
||||
"DGO/LSIGJAKC.DGO",
|
||||
"DGO/DESLIZ.DGO",
|
||||
"DGO/WASPALA.DGO",
|
||||
"DGO/LJAKNDAX.DGO",
|
||||
"DGO/WASSEEM.DGO",
|
||||
"DGO/WASALL.DGO",
|
||||
"DGO/WCASEEM.DGO",
|
||||
"DGO/LSIG.DGO",
|
||||
"DGO/LFACTORY.DGO",
|
||||
"DGO/LWLANDM.DGO",
|
||||
"DGO/LPTRL.DGO",
|
||||
"DGO/MINED.DGO",
|
||||
"DGO/LDAMPKSM.DGO",
|
||||
"DGO/RUBB.DGO",
|
||||
"DGO/LCITYSML.DGO",
|
||||
"DGO/RUBA2.DGO",
|
||||
"DGO/LOUTRO2.DGO",
|
||||
"DGO/VOCX.DGO",
|
||||
"DGO/TEMX.DGO",
|
||||
"DGO/ARENACST.DGO",
|
||||
"DGO/TEMB.DGO",
|
||||
"DGO/COMBA.DGO",
|
||||
"DGO/LBBSDRP3.DGO",
|
||||
"DGO/LPATKCS.DGO",
|
||||
"DGO/VOCA.DGO",
|
||||
"DGO/WASSTADB.DGO",
|
||||
"DGO/LDAX.DGO",
|
||||
"DGO/LCTYPROT.DGO",
|
||||
"DGO/DESHOVER.DGO",
|
||||
"DGO/DESBOSS2.DGO"
|
||||
],
|
||||
// "DGO/LJKDMPK.DGO",
|
||||
// "DGO/LBBSDRP1.DGO",
|
||||
// "DGO/LTNJXHIP.DGO",
|
||||
// "DGO/MIC.DGO",
|
||||
// "DGO/OASISCST.DGO",
|
||||
// "DGO/CTYPEPA.DGO",
|
||||
// "DGO/LPRENME.DGO",
|
||||
// "DGO/LFREEOUT.DGO",
|
||||
// "DGO/LGUNNORM.DGO",
|
||||
// "DGO/LTOWA.DGO",
|
||||
// "DGO/TEMA.DGO",
|
||||
// "DGO/CTA.DGO",
|
||||
// "DGO/LPRECC.DGO",
|
||||
// "DGO/LJKDXVIN.DGO",
|
||||
// "DGO/CTYPEPC.DGO",
|
||||
// "DGO/SEA.DGO",
|
||||
// "DGO/COMBE.DGO",
|
||||
// "DGO/CTYPESA.DGO",
|
||||
// "DGO/LBLOWCST.DGO",
|
||||
// "DGO/WSD.DGO",
|
||||
// "DGO/LBBRING3.DGO",
|
||||
// "DGO/LCTYPATK.DGO",
|
||||
// "DGO/WCB.DGO",
|
||||
// "DGO/DESRESC.DGO",
|
||||
// "DGO/LBBRING4.DGO",
|
||||
// "DGO/GRIDCST.DGO",
|
||||
// "DGO/RAILX.DGO",
|
||||
// "DGO/SEJ.DGO",
|
||||
// "DGO/LJAKC.DGO",
|
||||
// "DGO/CTB.DGO",
|
||||
// "DGO/CTYCARC.DGO",
|
||||
// "DGO/LMECH.DGO",
|
||||
// "DGO/LBBSDRP2.DGO",
|
||||
// "DGO/NSA.DGO",
|
||||
// "DGO/LBBTCHA3.DGO",
|
||||
// "DGO/GUNGAME2.DGO",
|
||||
// "DGO/CTC.DGO",
|
||||
// "DGO/LVINCST.DGO",
|
||||
// "DGO/COMBX.DGO",
|
||||
// "DGO/DESH.DGO",
|
||||
// "DGO/DESRACE2.DGO",
|
||||
// "DGO/RAILD.DGO",
|
||||
// "DGO/FACC.DGO",
|
||||
// "DGO/CTYPESC.DGO",
|
||||
// "DGO/LWASBBV.DGO",
|
||||
// "DGO/TOWB.DGO",
|
||||
// "DGO/HGA.DGO",
|
||||
// "DGO/SEH.DGO",
|
||||
// "DGO/MHCTYCST.DGO",
|
||||
// "DGO/GUNGAME1.DGO",
|
||||
// "DGO/INTROCST.DGO",
|
||||
// "DGO/DESJUMP.DGO",
|
||||
// "DGO/SEM.DGO",
|
||||
// "DGO/SEI.DGO",
|
||||
// "DGO/DESG.DGO",
|
||||
// "DGO/DESW.DGO",
|
||||
// "DGO/LOUTRO3.DGO",
|
||||
// "DGO/LDAMKLEV.DGO",
|
||||
// "DGO/DESERROL.DGO",
|
||||
// "DGO/RAILB2.DGO",
|
||||
// "DGO/LERROL.DGO",
|
||||
// "DGO/IPF.DGO",
|
||||
// "DGO/RAILB.DGO",
|
||||
// "DGO/LCTYHIJK.DGO",
|
||||
// "DGO/CTYPEPB.DGO",
|
||||
// "DGO/PRECB.DGO",
|
||||
// "DGO/LFORM.DGO",
|
||||
// "DGO/WASLEAPR.DGO",
|
||||
// "DGO/LKEIRA.DGO",
|
||||
// "DGO/LJAK.DGO",
|
||||
// "DGO/SLUMBSET.DGO",
|
||||
// "DGO/FACD.DGO",
|
||||
// "DGO/LWASSIG.DGO",
|
||||
// "DGO/LBIPED.DGO",
|
||||
// "DGO/DESD.DGO",
|
||||
// "DGO/CFB.DGO",
|
||||
// "DGO/FREECAST.DGO",
|
||||
// "DGO/SEG.DGO",
|
||||
// "DGO/FACTORYA.DGO",
|
||||
// "DGO/LPATK.DGO",
|
||||
// "DGO/FRSTX.DGO",
|
||||
// "DGO/SEB.DGO",
|
||||
// "DGO/DESBCST.DGO",
|
||||
// "DGO/DESE.DGO",
|
||||
// "DGO/DESOASIS.DGO",
|
||||
// "DGO/CTYCARA.DGO",
|
||||
// "DGO/LSIGKLV.DGO",
|
||||
// "DGO/CIB.DGO",
|
||||
// "DGO/LBBRING2.DGO",
|
||||
// "DGO/LTNFXHIP.DGO",
|
||||
// "DGO/MIA.DGO",
|
||||
// "DGO/MHCB.DGO",
|
||||
// "DGO/LNSTOBC.DGO",
|
||||
// "DGO/COMBD.DGO",
|
||||
// "DGO/RBCT.DGO",
|
||||
// "DGO/LTORNJNX.DGO",
|
||||
// "DGO/DESBATTL.DGO",
|
||||
// "DGO/SEK.DGO",
|
||||
// "DGO/LSNKWHLS.DGO",
|
||||
// "DGO/LMHCB.DGO",
|
||||
// "DGO/LBOMBBOT.DGO",
|
||||
// "DGO/OUTCAST3.DGO",
|
||||
// "DGO/LBLOWTMH.DGO",
|
||||
// "DGO/TEMD.DGO",
|
||||
// "DGO/LTOWCITY.DGO",
|
||||
// "DGO/OUTROCST.DGO",
|
||||
// "DGO/WASCAST.DGO",
|
||||
// "DGO/LFACRM2.DGO",
|
||||
// "DGO/WASPGAME.DGO",
|
||||
// "DGO/RAILE.DGO",
|
||||
// "DGO/CTYPESB.DGO",
|
||||
// "DGO/DESBOSS1.DGO",
|
||||
// "DGO/FREEHQ.DGO",
|
||||
// "DGO/LTORN.DGO",
|
||||
// "DGO/TOWERA.DGO",
|
||||
// "DGO/LSAMOS.DGO",
|
||||
// "DGO/LFORP.DGO",
|
||||
// "DGO/CFA.DGO",
|
||||
// "DGO/LJINX.DGO",
|
||||
// "DGO/SEO.DGO",
|
||||
// "DGO/PRECA.DGO",
|
||||
// "DGO/TOWERC.DGO",
|
||||
// "DGO/WCA.DGO",
|
||||
// "DGO/SEC.DGO",
|
||||
// "DGO/DESF.DGO",
|
||||
// "DGO/SEL.DGO",
|
||||
// "DGO/LCTYDEST.DGO",
|
||||
// "DGO/LTORNSAM.DGO",
|
||||
// "DGO/MUSEUM3B.DGO",
|
||||
// "DGO/SEE.DGO",
|
||||
// "DGO/DESHUNT.DGO",
|
||||
// "DGO/RAILA.DGO",
|
||||
// "DGO/TITLE.DGO",
|
||||
// "DGO/RUBC.DGO",
|
||||
// "DGO/DESB.DGO",
|
||||
// "DGO/LFACCAR.DGO",
|
||||
// "DGO/LNSTOA.DGO",
|
||||
// "DGO/MUSEUM3.DGO",
|
||||
// "DGO/ONINTENT.DGO",
|
||||
// "DGO/STA.DGO",
|
||||
// "DGO/WASSTADA.DGO",
|
||||
// "DGO/POWERGD.DGO",
|
||||
// "DGO/LKLEEVER.DGO",
|
||||
// "DGO/FACB.DGO",
|
||||
// "DGO/LCTYASS.DGO",
|
||||
// "DGO/MHCA.DGO",
|
||||
// "DGO/LTOWB.DGO",
|
||||
// "DGO/LNSTCST.DGO",
|
||||
// "DGO/DESRESCG.DGO",
|
||||
// "DGO/INTPALRF.DGO",
|
||||
// "DGO/LMHCA.DGO",
|
||||
// "DGO/TOWERCST.DGO",
|
||||
// "DGO/RAILF.DGO",
|
||||
// "DGO/CIA.DGO",
|
||||
// "DGO/CTYCARKG.DGO",
|
||||
// "DGO/WASCHASE.DGO",
|
||||
// "DGO/LFACO.DGO",
|
||||
// "DGO/WIN.DGO",
|
||||
// "DGO/TEMPLEE.DGO",
|
||||
// "DGO/LBBSPIRT.DGO",
|
||||
// "DGO/MUSEUM2.DGO",
|
||||
// "DGO/INTTITLE.DGO",
|
||||
// "DGO/STAA.DGO",
|
||||
// "DGO/MUSEUM4B.DGO",
|
||||
// "DGO/PRECD.DGO",
|
||||
// "DGO/SEF.DGO",
|
||||
// "DGO/CTYCARB.DGO",
|
||||
// "DGO/WASDEFEN.DGO",
|
||||
// "DGO/LBLOWTKG.DGO",
|
||||
// "DGO/DESA.DGO",
|
||||
// "DGO/COMBB.DGO",
|
||||
// "DGO/WASSTADC.DGO",
|
||||
// "DGO/DESC.DGO",
|
||||
// "DGO/LDAMPECK.DGO",
|
||||
// "DGO/LJAKSIG.DGO",
|
||||
// "DGO/HALFPIPE.DGO",
|
||||
// "DGO/DESRACE1.DGO",
|
||||
// "DGO/SEN.DGO",
|
||||
// "DGO/TEMP.DGO",
|
||||
// "DGO/SED.DGO",
|
||||
// "DGO/LFACB.DGO",
|
||||
// "DGO/LCTYSNPR.DGO",
|
||||
// "DGO/LBBSPID.DGO",
|
||||
// "DGO/FRSTA.DGO",
|
||||
// "DGO/LBBRING5.DGO",
|
||||
// "DGO/LBBSPRT3.DGO",
|
||||
// "DGO/HHG.DGO",
|
||||
// "DGO/LBBSPRT2.DGO",
|
||||
// "DGO/CGB.DGO",
|
||||
// "DGO/LDMPCKGN.DGO",
|
||||
// "DGO/LSEEMWCA.DGO",
|
||||
// "DGO/HGB.DGO",
|
||||
// "DGO/LONINSIM.DGO",
|
||||
// "DGO/RUBA.DGO",
|
||||
// "DGO/DESRALLY.DGO",
|
||||
// "DGO/WWD.DGO",
|
||||
// "DGO/STB.DGO",
|
||||
// "DGO/MIB.DGO",
|
||||
// "DGO/LCTYBLOW.DGO",
|
||||
// "DGO/LWSTDPCK.DGO",
|
||||
// "DGO/MUSEUM.DGO",
|
||||
// "DGO/LJAKCKLV.DGO",
|
||||
// "DGO/LBBRING1.DGO",
|
||||
// "DGO/MUSEUM4.DGO",
|
||||
// "DGO/LFACRM1.DGO",
|
||||
// "DGO/LJKCDMKL.DGO",
|
||||
// "DGO/LDAMSIG.DGO",
|
||||
// "DGO/DESTRACK.DGO",
|
||||
// "DGO/GGA.DGO",
|
||||
// "DGO/RAILC.DGO",
|
||||
// "DGO/LBBTCHA2.DGO",
|
||||
// "DGO/DESINTER.DGO",
|
||||
// "DGO/NSB.DGO",
|
||||
// "DGO/LOUTRO.DGO",
|
||||
// "DGO/VIN.DGO",
|
||||
// "DGO/LDESGCST.DGO",
|
||||
// "DGO/WARPCAST.DGO",
|
||||
// "DGO/LBBRING6.DGO",
|
||||
// "DGO/FRSTB.DGO",
|
||||
// "DGO/TEMC.DGO",
|
||||
// "DGO/COMBC.DGO",
|
||||
// "DGO/LTRTWHLS.DGO",
|
||||
// "DGO/PRECC.DGO",
|
||||
// "DGO/DESCHASE.DGO",
|
||||
// "DGO/CITYCAST.DGO",
|
||||
// "DGO/CPO.DGO",
|
||||
// "DGO/LFACCITY.DGO",
|
||||
// "DGO/RAILCST.DGO",
|
||||
// "DGO/LJNDKLEV.DGO",
|
||||
// "DGO/CWI.DGO",
|
||||
// "DGO/MINEE.DGO",
|
||||
// "DGO/LFORRING.DGO",
|
||||
// "DGO/LASHELIN.DGO",
|
||||
// "DGO/LJAKKLEV.DGO",
|
||||
// "DGO/LCTYPALT.DGO",
|
||||
// "DGO/LNSTOBB.DGO",
|
||||
// "DGO/LJKFEET.DGO",
|
||||
// "DGO/DST.DGO",
|
||||
// "DGO/LBBTCHA1.DGO",
|
||||
// "DGO/LGUNRNC.DGO",
|
||||
// "DGO/COMBN.DGO",
|
||||
// "DGO/DESRESCC.DGO",
|
||||
// "DGO/LSIGJAKC.DGO",
|
||||
// "DGO/DESLIZ.DGO",
|
||||
// "DGO/WASPALA.DGO",
|
||||
// "DGO/LJAKNDAX.DGO",
|
||||
// "DGO/WASSEEM.DGO",
|
||||
// "DGO/WASALL.DGO",
|
||||
// "DGO/WCASEEM.DGO",
|
||||
// "DGO/LSIG.DGO",
|
||||
// "DGO/LFACTORY.DGO",
|
||||
// "DGO/LWLANDM.DGO",
|
||||
// "DGO/LPTRL.DGO",
|
||||
// "DGO/MINED.DGO",
|
||||
// "DGO/LDAMPKSM.DGO",
|
||||
// "DGO/RUBB.DGO",
|
||||
// "DGO/LCITYSML.DGO",
|
||||
// "DGO/RUBA2.DGO",
|
||||
// "DGO/LOUTRO2.DGO",
|
||||
// "DGO/VOCX.DGO",
|
||||
// "DGO/TEMX.DGO",
|
||||
// "DGO/ARENACST.DGO",
|
||||
// "DGO/TEMB.DGO",
|
||||
// "DGO/COMBA.DGO",
|
||||
// "DGO/LBBSDRP3.DGO",
|
||||
// "DGO/LPATKCS.DGO",
|
||||
// "DGO/VOCA.DGO",
|
||||
// "DGO/WASSTADB.DGO",
|
||||
// "DGO/LDAX.DGO",
|
||||
// "DGO/LCTYPROT.DGO",
|
||||
// "DGO/DESHOVER.DGO",
|
||||
// "DGO/DESBOSS2.DGO"
|
||||
],
|
||||
|
||||
// some objects are part of STR files (streaming data).
|
||||
"str_file_names": [],
|
||||
@@ -310,7 +310,15 @@
|
||||
// "audio_dir_file_name": "jak3/VAG",
|
||||
"audio_dir_file_name": "",
|
||||
|
||||
"streamed_audio_file_names": [],
|
||||
"streamed_audio_file_names": [
|
||||
"VAGWAD.ENG",
|
||||
"VAGWAD.FRE",
|
||||
"VAGWAD.GER",
|
||||
"VAGWAD.SPA",
|
||||
"VAGWAD.ITA",
|
||||
"VAGWAD.COM",
|
||||
"VAGWAD.INT"
|
||||
],
|
||||
|
||||
"levels_to_extract": [
|
||||
"LJKDMPK.DGO",
|
||||
|
||||
@@ -1 +1,44 @@
|
||||
{}
|
||||
{
|
||||
"math": [
|
||||
["L108", "(pointer float)", 32],
|
||||
["L109", "(pointer float)", 32]
|
||||
],
|
||||
"ocean-trans-tables": [
|
||||
["L1", "(inline-array vector)", 4],
|
||||
["L2", "(pointer float)", 160],
|
||||
["L3", "(pointer float)", 100],
|
||||
["L4", "(pointer float)", 72],
|
||||
["L5", "(pointer float)", 72],
|
||||
["L6", "(pointer float)", 72],
|
||||
["L7", "(pointer float)", 72],
|
||||
["L8", "(pointer float)", 44],
|
||||
["L9", "(pointer float)", 44],
|
||||
["L10", "(pointer float)", 44],
|
||||
["L11", "(pointer float)", 44],
|
||||
["L12", "(pointer float)", 40],
|
||||
["L13", "(pointer float)", 40],
|
||||
["L14", "(pointer float)", 40],
|
||||
["L15", "(pointer float)", 40],
|
||||
["L16", "(pointer float)", 28],
|
||||
["L17", "(pointer float)", 28],
|
||||
["L18", "(pointer float)", 28],
|
||||
["L19", "(pointer float)", 28]
|
||||
],
|
||||
"ocean-frames": [["L1", "(pointer uint32)", 16384]],
|
||||
"task-control-h": [
|
||||
["L1042", "uint64", true],
|
||||
["L1047", "uint64", true],
|
||||
["L1048", "uint64", true],
|
||||
["L1045", "uint64", true],
|
||||
["L1049", "uint64", true],
|
||||
["L1043", "uint64", true],
|
||||
["L1046", "uint64", true],
|
||||
["L1044", "uint64", true]
|
||||
],
|
||||
"profile": [
|
||||
["L3", "(inline-array profile-spec)", 14],
|
||||
["L2", "(pointer uint64)", 584]
|
||||
],
|
||||
"texture-anim-h": [["L1", "(pointer uint8)", 256]],
|
||||
"capture": [["L4", "gs-store-image-packet"]]
|
||||
}
|
||||
@@ -1 +1,14 @@
|
||||
{}
|
||||
{
|
||||
"quaternion-smooth-seek!": [[16, "quaternion"]],
|
||||
"eul->matrix": [[16, "vector"]],
|
||||
"segment-segment-find-intersection-xz": [[16, "vector"]],
|
||||
"vector-line-xz-distance-point!": [[16, "matrix"]],
|
||||
"vector-segment-xz-distance-point!": [[16, "matrix"]],
|
||||
"nearest-dist2-between-moving-points": [[16, ["inline-array", "vector", 2]]],
|
||||
"vector-circle-tangent-new": [
|
||||
[32, "vector"],
|
||||
[48, "vector"]
|
||||
],
|
||||
"rotate-vector-to-vector": [[16, "quaternion"]],
|
||||
"init-for-transform": [[192, "vector"]]
|
||||
}
|
||||
@@ -1 +1,264 @@
|
||||
{}
|
||||
{
|
||||
"(method 2 array)": [
|
||||
[23, "gp", "(array int32)"],
|
||||
[43, "gp", "(array uint32)"],
|
||||
[63, "gp", "(array int64)"],
|
||||
[83, "gp", "(array uint64)"],
|
||||
[102, "gp", "(array int8)"],
|
||||
[121, "gp", "(array uint8)"],
|
||||
[141, "gp", "(array int16)"],
|
||||
[161, "gp", "(array uint16)"],
|
||||
[186, "gp", "(array uint128)"],
|
||||
[204, "gp", "(array int32)"],
|
||||
[223, "gp", "(array float)"],
|
||||
[232, "gp", "(array float)"],
|
||||
[249, "gp", "(array basic)"],
|
||||
[258, "gp", "(array basic)"]
|
||||
],
|
||||
"(method 3 array)": [
|
||||
[51, "gp", "(array int32)"],
|
||||
[69, "gp", "(array uint32)"],
|
||||
[87, "gp", "(array int64)"],
|
||||
[105, "gp", "(array uint64)"],
|
||||
[122, "gp", "(array int8)"],
|
||||
[139, "gp", "(array int8)"],
|
||||
[157, "gp", "(array int16)"],
|
||||
[175, "gp", "(array uint16)"],
|
||||
[198, "gp", "(array uint128)"],
|
||||
[214, "gp", "(array int32)"],
|
||||
[233, "gp", "(array float)"],
|
||||
[250, "gp", "(array basic)"]
|
||||
],
|
||||
"(method 0 cpu-thread)": [[[0, 35], "v0", "cpu-thread"]],
|
||||
"(method 0 process)": [
|
||||
[11, "a0", "int"],
|
||||
[[12, 52], "v0", "process"]
|
||||
],
|
||||
"inspect-process-heap": [
|
||||
[[4, 11], "s5", "basic"],
|
||||
[17, "s5", "pointer"]
|
||||
],
|
||||
"(method 14 dead-pool)": [
|
||||
[[24, 25], "v1", "(pointer process)"],
|
||||
[[30, 39], "s4", "(pointer process)"]
|
||||
],
|
||||
"(method 24 dead-pool-heap)": [
|
||||
[5, "v1", "pointer"],
|
||||
[13, "a0", "pointer"],
|
||||
[25, "v1", "pointer"]
|
||||
],
|
||||
"method-state": [[12, "a2", "state"]],
|
||||
"(method 0 protect-frame)": [
|
||||
[0, "a0", "int"],
|
||||
[[1, 8], "v0", "protect-frame"]
|
||||
],
|
||||
"(method 9 process)": [[[58, 61], "s5", "process"]],
|
||||
"(method 10 process)": [[[24, 30], "s4", "protect-frame"]],
|
||||
"string-cat-to-last-char": [
|
||||
[3, "s5", "(pointer uint8)"],
|
||||
[4, "s5", "string"]
|
||||
],
|
||||
"enter-state": [
|
||||
[70, "s0", "protect-frame"],
|
||||
[103, "t9", "(function object object object object object object none)"]
|
||||
],
|
||||
"send-event-function": [[[7, 15], "a0", "process"]],
|
||||
"logf": [
|
||||
[12, "f0", "float"],
|
||||
[12, "f1", "float"],
|
||||
[19, "f0", "float"],
|
||||
[19, "f1", "float"]
|
||||
],
|
||||
"log2f": [
|
||||
[12, "f0", "float"],
|
||||
[12, "f1", "float"],
|
||||
[19, "f0", "float"],
|
||||
[19, "f1", "float"]
|
||||
],
|
||||
"cube-root": [
|
||||
[17, "f0", "float"],
|
||||
[17, "f1", "float"],
|
||||
[18, "f0", "float"],
|
||||
[18, "f1", "float"],
|
||||
[[23, 32], "f0", "float"]
|
||||
],
|
||||
"generate-rand-vector-on-sphere": [
|
||||
[12, "v1", "float"],
|
||||
[28, "v1", "float"]
|
||||
],
|
||||
"vector-segment-distance-point!": [[[21, 30], "f1", "float"]],
|
||||
"vector4-array-add!": [
|
||||
[11, "s5", "(inline-array vector4)"],
|
||||
[12, "s4", "(inline-array vector4)"],
|
||||
[13, "gp", "(inline-array vector4)"]
|
||||
],
|
||||
"vector4-array-sub!": [
|
||||
[11, "s5", "(inline-array vector4)"],
|
||||
[12, "s4", "(inline-array vector4)"],
|
||||
[13, "gp", "(inline-array vector4)"]
|
||||
],
|
||||
"vector4-array-mul!": [
|
||||
[11, "s5", "(inline-array vector4)"],
|
||||
[12, "s4", "(inline-array vector4)"],
|
||||
[13, "gp", "(inline-array vector4)"]
|
||||
],
|
||||
"vector4-array-scale!": [
|
||||
[11, "s5", "(inline-array vector4)"],
|
||||
[12, "gp", "(inline-array vector4)"]
|
||||
],
|
||||
"vector4-array-madd!": [
|
||||
[13, "s5", "(inline-array vector4)"],
|
||||
[14, "s4", "(inline-array vector4)"],
|
||||
[15, "gp", "(inline-array vector4)"]
|
||||
],
|
||||
"vector4-array-msub!": [
|
||||
[13, "s5", "(inline-array vector4)"],
|
||||
[14, "s4", "(inline-array vector4)"],
|
||||
[15, "gp", "(inline-array vector4)"]
|
||||
],
|
||||
"vector4-array-lerp!": [
|
||||
[13, "s5", "(inline-array vector4)"],
|
||||
[14, "s4", "(inline-array vector4)"],
|
||||
[15, "gp", "(inline-array vector4)"]
|
||||
],
|
||||
"(method 9 clock)": [[47, "v1", "float"]],
|
||||
"service-cpads": [[[207, 311], "s3", "pad-buttons"]],
|
||||
"(method 3 connection-pers)": [[97, "f0", "float"]],
|
||||
"(method 0 engine-pers)": [
|
||||
[32, "v1", "pointer"],
|
||||
[23, "v1", "pointer"],
|
||||
[26, "v1", "pointer"],
|
||||
[24, "v1", "(pointer pointer)"]
|
||||
],
|
||||
"(method 0 engine)": [
|
||||
[44, "v1", "pointer"],
|
||||
[47, "v1", "pointer"],
|
||||
[53, "v1", "connectable"],
|
||||
[65, "v1", "connectable"]
|
||||
],
|
||||
"(method 21 engine)": [[8, "a0", "connection"]],
|
||||
"(method 20 engine)": [[8, "a0", "connection"]],
|
||||
"(method 19 engine)": [[8, "a0", "connection"]],
|
||||
"(method 15 engine)": [[[0, 36], "v1", "connection"]],
|
||||
"(method 13 engine)": [
|
||||
[[0, 25], "s4", "connection"],
|
||||
[13, "t9", "(function object object object object object)"]
|
||||
],
|
||||
"(method 12 engine)": [
|
||||
[[0, 25], "s4", "connection"],
|
||||
[13, "t9", "(function object object object object object)"]
|
||||
],
|
||||
"(method 9 connection)": [[8, "a0", "pointer"]],
|
||||
"(method 10 connection)": [[8, "a0", "pointer"]],
|
||||
"(method 11 connection)": [[5, "a1", "pointer"]],
|
||||
"(method 10 profile-array)": [
|
||||
[[69, 73], "a0", "(pointer uint128)"],
|
||||
[[73, 82], "a1", "vector4w"],
|
||||
[[82, 89], "a1", "vector4w"],
|
||||
[[90, 96], "a0", "vector4w"],
|
||||
[[113, 117], "a1", "(pointer uint128)"],
|
||||
[[117, 126], "a2", "vector4w"],
|
||||
[[126, 136], "a2", "vector4w"],
|
||||
[[137, 149], "a1", "vector4w"],
|
||||
[[187, 191], "t2", "(pointer int128)"],
|
||||
[[191, 225], "t4", "vector4w"],
|
||||
[[225, 231], "a2", "vector4w"],
|
||||
[[231, 237], "a2", "vector4w"]
|
||||
],
|
||||
"draw-sprite2d-xy": [
|
||||
[[35, 40], "t0", "dma-packet"],
|
||||
[[45, 49], "t0", "gs-gif-tag"],
|
||||
[54, "t0", "(pointer gs-prim)"],
|
||||
[56, "t0", "(pointer gs-rgbaq)"],
|
||||
[67, "t0", "(pointer gs-xyzf)"],
|
||||
[88, "t0", "(pointer gs-xyzf)"],
|
||||
[[97, 109], "v1", "(pointer uint64)"]
|
||||
],
|
||||
"draw-sprite2d-xy-absolute": [
|
||||
[[6, 10], "t4", "dma-packet"],
|
||||
[[16, 19], "t4", "gs-gif-tag"],
|
||||
[24, "t4", "(pointer gs-prim)"],
|
||||
[25, "t4", "(pointer gs-rgbaq)"],
|
||||
[36, "t4", "(pointer gs-xyzf)"],
|
||||
[49, "t4", "(pointer gs-xyzf)"],
|
||||
[[62, 69], "v1", "(pointer uint64)"]
|
||||
],
|
||||
"draw-quad2d": [
|
||||
[[18, 22], "t2", "dma-packet"],
|
||||
[[28, 31], "t2", "gs-gif-tag"],
|
||||
[36, "t2", "(pointer gs-prim)"],
|
||||
[38, "t2", "(pointer gs-rgbaq)"],
|
||||
[46, "t2", "(pointer gs-xyzf)"],
|
||||
[48, "t2", "(pointer gs-rgbaq)"],
|
||||
[61, "t2", "(pointer gs-xyzf)"],
|
||||
[63, "t2", "(pointer gs-rgbaq)"],
|
||||
[76, "t2", "(pointer gs-xyzf)"],
|
||||
[78, "t2", "(pointer gs-rgbaq)"],
|
||||
[96, "t2", "(pointer gs-xyzf)"],
|
||||
[97, "t2", "(pointer uint64)"],
|
||||
[[110, 117], "v1", "(pointer uint64)"]
|
||||
],
|
||||
"dma-bucket-insert-tag": [
|
||||
[[2, 6], "v1", "dma-bucket"],
|
||||
[3, "a0", "dma-bucket"]
|
||||
],
|
||||
"dma-buffer-add-buckets": [
|
||||
[[1, 4], "v1", "dma-bucket"],
|
||||
[5, "v1", "pointer"],
|
||||
[[9, 11], "v1", "dma-bucket"],
|
||||
[11, "v1", "pointer"]
|
||||
],
|
||||
"dma-buffer-patch-buckets": [
|
||||
[[3, 34], "a0", "dma-bucket"],
|
||||
[[34, 38], "a0", "dma-packet"]
|
||||
// [34, "a0", "(inline-array dma-bucket)"]
|
||||
],
|
||||
"disasm-dma-list": [
|
||||
[43, "v1", "dma-packet"],
|
||||
[266, "v1", "(pointer uint64)"],
|
||||
[272, "v1", "(pointer uint64)"],
|
||||
[133, "v1", "(pointer uint64)"],
|
||||
[152, "v1", "(pointer uint64)"],
|
||||
[167, "v1", "(pointer uint64)"],
|
||||
[176, "v1", "(pointer uint64)"],
|
||||
[198, "v1", "(pointer uint64)"],
|
||||
[207, "v1", "(pointer uint64)"],
|
||||
[238, "v1", "(pointer uint64)"],
|
||||
[247, "v1", "(pointer uint64)"],
|
||||
[282, "v1", "(pointer uint64)"],
|
||||
[291, "v1", "(pointer uint64)"],
|
||||
[324, "v1", "(pointer uint64)"],
|
||||
[334, "v1", "(pointer uint64)"],
|
||||
[141, "v1", "int"],
|
||||
[25, "v1", "dma-tag"]
|
||||
],
|
||||
"(method 3 connection-minimap)": [
|
||||
[97, "f0", "float"]
|
||||
],
|
||||
"dma-buffer-add-ref-texture": [
|
||||
[[47, 54], "a3", "dma-packet"],
|
||||
[[56, 69], "a3", "gs-gif-tag"],
|
||||
[[71, 87], "a2", "dma-packet"]
|
||||
],
|
||||
"texture-page-default-allocate":
|
||||
[[51, "a3", "(pointer int32)"]],
|
||||
"texture-page-font-allocate":[[33, "a3", "(pointer int32)"]],
|
||||
"upload-vram-pages":[[[187, 193], "v1", "dma-packet"]],
|
||||
"upload-vram-pages-pris": [[[181, 187], "v1", "dma-packet"]],
|
||||
"(method 13 texture-page)": [[45, "a0", "(pointer uint64)"]],
|
||||
"(method 11 texture-pool)": [[217, "a0", "(pointer uint64)"]],
|
||||
"texture-page-login": [[34, "v0", "texture-page"]],
|
||||
"(method 9 texture-page-dir)": [
|
||||
[[36, 40], "t1", "adgif-shader"],
|
||||
[[31, 41], "t2", "(pointer shader-ptr)"],
|
||||
[37, "t0", "(pointer int32)"]
|
||||
],
|
||||
"texture-page-dir-inspect": [[[137, 138], "v1", "adgif-shader"]],
|
||||
"(method 24 texture-pool)": [
|
||||
[[77, 100], "a1", "adgif-shader"]
|
||||
// [[70, 93], "a1", "adgif-shader"],
|
||||
// [92, "a1", "adgif-shader"]
|
||||
]
|
||||
|
||||
|
||||
}
|
||||
@@ -1 +1,877 @@
|
||||
{}
|
||||
{
|
||||
"(method 0 inline-array-class)": {
|
||||
"args": ["allocation", "type-to-make", "count"]
|
||||
},
|
||||
"(method 9 inline-array-class)": {
|
||||
"args": ["object-to-insert"]
|
||||
},
|
||||
"(method 3 inline-array-class)": {
|
||||
"args": ["idx-to-remove"]
|
||||
},
|
||||
"identity": {
|
||||
"args": ["obj"]
|
||||
},
|
||||
"1/": {
|
||||
"args": ["x"]
|
||||
},
|
||||
"+": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"-": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"*": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"/": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"ash": {
|
||||
"args": ["x", "shift-amount"]
|
||||
},
|
||||
"mod": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"rem": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"abs": {
|
||||
"args": ["x"]
|
||||
},
|
||||
"min": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"max": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"logior": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"logand": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"lognor": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"logxor": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"lognot": {
|
||||
"args": ["x"]
|
||||
},
|
||||
"basic-type?": {
|
||||
"args": ["obj", "typ"]
|
||||
},
|
||||
"type-type?": {
|
||||
"args": ["check-type", "parent-type"]
|
||||
},
|
||||
"type?": {
|
||||
"args": ["obj", "desired-type"]
|
||||
},
|
||||
"find-parent-method": {
|
||||
"args": ["typ", "method-id"]
|
||||
},
|
||||
"ref&": {
|
||||
"args": ["list", "idx"]
|
||||
},
|
||||
"ref": {
|
||||
"args": ["list", "idx"]
|
||||
},
|
||||
"last": {
|
||||
"args": ["list"]
|
||||
},
|
||||
"member": {
|
||||
"args": ["obj-to-find", "list"]
|
||||
},
|
||||
"nmember": {
|
||||
"args": ["obj-to-find", "list"]
|
||||
},
|
||||
"assoc": {
|
||||
"args": ["key", "assoc-list"]
|
||||
},
|
||||
"assoce": {
|
||||
"args": ["key", "assoc-list"]
|
||||
},
|
||||
"nassoc": {
|
||||
"args": ["key", "assoc-list"]
|
||||
},
|
||||
"nassoce": {
|
||||
"args": ["key", "assoc-list"]
|
||||
},
|
||||
"append!": {
|
||||
"args": ["list", "new-obj"]
|
||||
},
|
||||
"delete!": {
|
||||
"args": ["obj", "list"]
|
||||
},
|
||||
"delete-car!": {
|
||||
"args": ["car-to-match", "list"]
|
||||
},
|
||||
"insert-cons!": {
|
||||
"args": ["new-obj", "list"]
|
||||
},
|
||||
"sort": {
|
||||
"args": ["list", "compare-func"]
|
||||
},
|
||||
"string->symbol-debug": {
|
||||
"args": ["str"]
|
||||
},
|
||||
"symbol->string-debug": {
|
||||
"args": ["sym"]
|
||||
},
|
||||
"symbol->hash": {
|
||||
"args": ["sym"]
|
||||
},
|
||||
"mem-copy!": {
|
||||
"args": ["dst", "src", "bytes"]
|
||||
},
|
||||
"qmem-copy<-!": {
|
||||
"args": ["dst", "src", "qwc"]
|
||||
},
|
||||
"qmem-copy->!": {
|
||||
"args": ["dst", "src", "qwc"]
|
||||
},
|
||||
"qmem-clear!": {
|
||||
"args": ["dst", "qwc"]
|
||||
},
|
||||
"mem-set32!": {
|
||||
"args": ["dst", "word-count", "value"]
|
||||
},
|
||||
"mem-or!": {
|
||||
"args": ["dst", "src", "bytes"]
|
||||
},
|
||||
"fact": {
|
||||
"args": ["x"]
|
||||
},
|
||||
"print": {
|
||||
"args": ["obj"]
|
||||
},
|
||||
"printl": {
|
||||
"args": ["obj"]
|
||||
},
|
||||
"inspect": {
|
||||
"args": ["obj"]
|
||||
},
|
||||
"mem-print": {
|
||||
"args": ["ptr", "word-count"]
|
||||
},
|
||||
"print-tree-bitmask": {
|
||||
"args": ["mask", "count"]
|
||||
},
|
||||
"valid?": {
|
||||
"args": [
|
||||
"obj",
|
||||
"expected-type",
|
||||
"err-msg-str",
|
||||
"allow-false",
|
||||
"err-msg-dest"
|
||||
]
|
||||
},
|
||||
"(method 0 process-tree)": {
|
||||
"args": ["allocation", "type-to-make", "name"]
|
||||
},
|
||||
"(method 9 process-tree)": {
|
||||
"args": ["this", "active-tree", "name", "stack-pointer"]
|
||||
},
|
||||
"(method 9 process)": {
|
||||
"args": ["this", "active-tree", "name", "stack-pointer"]
|
||||
},
|
||||
"(method 10 process-tree)": {
|
||||
"args": ["this", "ent"]
|
||||
},
|
||||
"(method 0 clock)": {
|
||||
"args": ["allocation", "type-to-make", "index"]
|
||||
},
|
||||
"(method 9 clock)": {
|
||||
"args": ["this", "rate"]
|
||||
},
|
||||
"(method 16 clock)": {
|
||||
"args": ["this", "xor-val"]
|
||||
},
|
||||
"(method 17 clock)": {
|
||||
"args": ["this", "xor-val"]
|
||||
},
|
||||
"(method 18 clock)": {
|
||||
"args": ["this", "xor-val"]
|
||||
},
|
||||
"(method 19 clock)": {
|
||||
"args": ["this", "xor-val"]
|
||||
},
|
||||
"(method 20 clock)": {
|
||||
"args": ["this", "xor-val"]
|
||||
},
|
||||
"(method 21 clock)": {
|
||||
"args": ["this", "xor-val"]
|
||||
},
|
||||
"(method 22 clock)": {
|
||||
"args": ["this", "xor-val"]
|
||||
},
|
||||
"(method 23 clock)": {
|
||||
"args": ["this", "xor-val"]
|
||||
},
|
||||
"(method 9 thread)": {
|
||||
"args": ["this", "size-bytes"]
|
||||
},
|
||||
"(method 0 cpu-thread)": {
|
||||
"args": [
|
||||
"allocation",
|
||||
"type-to-make",
|
||||
"proc",
|
||||
"name",
|
||||
"stack-size",
|
||||
"stack-top"
|
||||
]
|
||||
},
|
||||
"(method 0 dead-pool)": {
|
||||
"args": ["allocation", "type-to-make", "num-proc", "process-size", "name"]
|
||||
},
|
||||
"(method 14 dead-pool)": {
|
||||
"args": ["this", "proc-type", "proc-size", "unk"]
|
||||
},
|
||||
"(method 14 dead-pool-heap)": {
|
||||
"args": ["this", "proc-type", "proc-size", "unk"]
|
||||
},
|
||||
"(method 15 dead-pool)": {
|
||||
"args": ["this", "proc"]
|
||||
},
|
||||
"(method 15 dead-pool-heap)": {
|
||||
"args": ["this", "proc"]
|
||||
},
|
||||
"(method 0 dead-pool-heap)": {
|
||||
"args": ["allocation", "type-to-make", "name", "max-num-proc", "heap-size"]
|
||||
},
|
||||
"(method 16 dead-pool-heap)": {
|
||||
"args": ["this", "allocation", "heap-size"]
|
||||
},
|
||||
"(method 17 dead-pool-heap)": {
|
||||
"args": ["this", "compact-count"]
|
||||
},
|
||||
"(method 18 dead-pool-heap)": {
|
||||
"args": ["this", "proc"]
|
||||
},
|
||||
"(method 19 dead-pool-heap)": {
|
||||
"args": ["this", "count"]
|
||||
},
|
||||
"(method 24 dead-pool-heap)": {
|
||||
"args": ["this", "first-rec"]
|
||||
},
|
||||
"(method 25 dead-pool-heap)": {
|
||||
"args": ["this", "rec"]
|
||||
},
|
||||
"(method 26 dead-pool-heap)": {
|
||||
"args": ["this", "first-rec"]
|
||||
},
|
||||
"(method 27 dead-pool-heap)": {
|
||||
"args": ["this", "size"]
|
||||
},
|
||||
"(method 0 protect-frame)": {
|
||||
"args": ["stack-addr", "type-to-make", "exit-func"]
|
||||
},
|
||||
"(method 0 process)": {
|
||||
"args": ["allocation", "type-to-make", "name", "process-heap-size"]
|
||||
},
|
||||
"(method 0 sql-result)": {
|
||||
"args": ["allocation", "type-to-make", "num-elts"]
|
||||
},
|
||||
"load-package": {
|
||||
"args": ["package-name", "heap"]
|
||||
},
|
||||
"unload-package": {
|
||||
"args": ["package-name"]
|
||||
},
|
||||
"inspect-process-heap": {
|
||||
"args": ["proc"]
|
||||
},
|
||||
"method-state": {
|
||||
"args": ["typ", "state-name"]
|
||||
},
|
||||
"process-by-name": {
|
||||
"args": ["process-name", "tree"]
|
||||
},
|
||||
"process-not-name": {
|
||||
"args": ["name", "tree"]
|
||||
},
|
||||
"process-count": {
|
||||
"args": ["tree"]
|
||||
},
|
||||
"kill-by-name": {
|
||||
"args": ["name", "tree"]
|
||||
},
|
||||
"kill-by-type": {
|
||||
"args": ["typ", "tree"]
|
||||
},
|
||||
"kill-not-name": {
|
||||
"args": ["name", "tree"]
|
||||
},
|
||||
"kill-not-type": {
|
||||
"args": ["typ", "tree"]
|
||||
},
|
||||
"kill-by-type-inherited": {
|
||||
"args": ["typ", "tree"]
|
||||
},
|
||||
"iterate-process-tree": {
|
||||
"args": ["tree", "callback", "context"]
|
||||
},
|
||||
"execute-process-tree": {
|
||||
"args": ["tree", "callback", "context"]
|
||||
},
|
||||
"search-process-tree": {
|
||||
"args": ["tree", "callback"]
|
||||
},
|
||||
"inspect-process-tree": {
|
||||
"args": ["tree", "depth", "mask", "detail"]
|
||||
},
|
||||
"previous-brother": {
|
||||
"args": ["tree"]
|
||||
},
|
||||
"change-parent": {
|
||||
"args": ["proc-to-change", "new-parent"]
|
||||
},
|
||||
"change-to-last-brother": {
|
||||
"args": ["proc"]
|
||||
},
|
||||
"matrix-transpose!": {
|
||||
"args": ["dst", "src"]
|
||||
},
|
||||
"matrix-axis-sin-cos!": {
|
||||
"args": ["dst", "axis", "s", "c"]
|
||||
},
|
||||
"vector-rad<-vector-deg/2!": {
|
||||
"args": ["out", "in"]
|
||||
},
|
||||
"vector-rad<-vector-deg!": {
|
||||
"args": ["out", "in"]
|
||||
},
|
||||
"copy-string<-string": {
|
||||
"args": ["dst", "src"]
|
||||
},
|
||||
"string=": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"string-prefix=": {
|
||||
"args": ["prefix", "str"]
|
||||
},
|
||||
"charp-prefix=": {
|
||||
"args": ["prefix", "str"]
|
||||
},
|
||||
"string-suffix=": {
|
||||
"args": ["suffix", "str"]
|
||||
},
|
||||
"string-position": {
|
||||
"args": ["substr", "base-str"]
|
||||
},
|
||||
"string-charp=": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"name=": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"copyn-string<-charp": {
|
||||
"args": ["dst", "src", "num-chars"]
|
||||
},
|
||||
"string<-charp": {
|
||||
"args": ["dst", "src"]
|
||||
},
|
||||
"charp<-string": {
|
||||
"args": ["dst", "src"]
|
||||
},
|
||||
"copyn-charp<-string": {
|
||||
"args": ["dst", "src", "len"]
|
||||
},
|
||||
"copy-charp<-charp": {
|
||||
"args": ["dst", "src"]
|
||||
},
|
||||
"cat-string<-string": {
|
||||
"args": ["dst", "src"]
|
||||
},
|
||||
"catn-string<-charp": {
|
||||
"args": ["dst", "src", "num-chars"]
|
||||
},
|
||||
"cat-string<-string_to_charp": {
|
||||
"args": ["dst", "src", "stop-ptr"]
|
||||
},
|
||||
"append-character-to-string": {
|
||||
"args": ["str", "char"]
|
||||
},
|
||||
"charp-basename": {
|
||||
"args": ["str"]
|
||||
},
|
||||
"clear": {
|
||||
"args": ["str"]
|
||||
},
|
||||
"string<?": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"string>?": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"string<=?": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"string>=?": {
|
||||
"args": ["a", "b"]
|
||||
},
|
||||
"game-task->string": {
|
||||
"args": ["task"],
|
||||
"vars": {
|
||||
"v1-0": "val"
|
||||
}
|
||||
},
|
||||
"file-info-correct-version?": {
|
||||
"args": ["file", "kind", "version-override"],
|
||||
"vars": {
|
||||
"s5-0": "major",
|
||||
"v1-1": "file-kind",
|
||||
"s4-0": "type"
|
||||
}
|
||||
},
|
||||
"make-vfile-name": {
|
||||
"args": ["kind", "name"]
|
||||
},
|
||||
"make-file-name": {
|
||||
"args": ["kind", "name", "ag-version-override", "arg3"]
|
||||
},
|
||||
"file-stream-read-string": {
|
||||
"args": ["fs", "str"]
|
||||
},
|
||||
"(method 0 file-stream)": {
|
||||
"args": ["obj", "arg1", "file-name", "mode"]
|
||||
},
|
||||
"service-cpads": {
|
||||
"vars": {
|
||||
"gp-0": "pads",
|
||||
"s5-0": "pad-idx",
|
||||
"s4-0": "pad",
|
||||
"s3-0": "motor-idx",
|
||||
"s3-1": "buttons-pressed",
|
||||
"v1-123": "lang",
|
||||
"v1-135": "territory"
|
||||
}
|
||||
},
|
||||
"service-keybd": {
|
||||
"vars": {
|
||||
"gp-0": "keyboard",
|
||||
"v1-0": "key-idx"
|
||||
}
|
||||
},
|
||||
"service-mouse": {
|
||||
"vars": {
|
||||
"gp-0": "mouse"
|
||||
}
|
||||
},
|
||||
"(method 0 dma-buffer)": {
|
||||
"args": ["allocation", "type-to-make", "size-bytes"]
|
||||
},
|
||||
"dma-buffer-inplace-new": {
|
||||
"args": ["dma-buff", "size-bytes"]
|
||||
},
|
||||
"dma-buffer-length": {
|
||||
"args": ["dma-buf"]
|
||||
},
|
||||
"dma-buffer-free": {
|
||||
"args": ["dma-buf"]
|
||||
},
|
||||
"dma-buffer-add-vu-function": {
|
||||
"args": ["dma-buf", "vu-func", "flush-path-3"]
|
||||
},
|
||||
"dma-buffer-send": {
|
||||
"args": ["chan", "buf"]
|
||||
},
|
||||
"dma-buffer-send-chain": {
|
||||
"args": ["chan", "buf"]
|
||||
},
|
||||
"dma-buffer-patch-buckets": {
|
||||
"args": ["base", "count"]
|
||||
},
|
||||
"dma-buffer-add-buckets": {
|
||||
"args": ["dma-buf", "bucket-count"]
|
||||
},
|
||||
"dma-bucket-insert-tag": {
|
||||
"args": ["buckets", "bucket", "start-tag", "end-tag-to-patch"]
|
||||
},
|
||||
"disasm-vif-details": {
|
||||
"args": [
|
||||
"fmt-dest",
|
||||
"vif-data",
|
||||
"unpack-cmd",
|
||||
"unpack-count"
|
||||
]
|
||||
},
|
||||
"disasm-vif-tag": {
|
||||
"args": [
|
||||
"tag",
|
||||
"count",
|
||||
"format-dest",
|
||||
"details?"
|
||||
]
|
||||
},
|
||||
"disasm-dma-tag": {
|
||||
"args": [
|
||||
"tag",
|
||||
"format-dest"
|
||||
]
|
||||
},
|
||||
"disasm-dma-list": {
|
||||
"args": [
|
||||
"data",
|
||||
"mode",
|
||||
"verbose",
|
||||
"stream",
|
||||
"expected-size"
|
||||
]
|
||||
},
|
||||
"gs-set-default-store-image": {
|
||||
"args": [
|
||||
"packet",
|
||||
"source-vram",
|
||||
"width",
|
||||
"tex-fmt",
|
||||
"ssax",
|
||||
"ssay",
|
||||
"rrw",
|
||||
"rrh"
|
||||
]
|
||||
},
|
||||
"store-image": {
|
||||
"args": [
|
||||
"work"
|
||||
]
|
||||
},
|
||||
"texture-bpp": {
|
||||
"args": [
|
||||
"tex-format"
|
||||
]
|
||||
},
|
||||
"texture-qwc": {
|
||||
"args": [
|
||||
"w",
|
||||
"h",
|
||||
"tex-format"
|
||||
]
|
||||
},
|
||||
"physical-address": {
|
||||
"args": [
|
||||
"addr"
|
||||
]
|
||||
},
|
||||
"dma-buffer-add-ref-texture": {
|
||||
"args": [
|
||||
"dma-buf",
|
||||
"tex-data-ptr",
|
||||
"w",
|
||||
"h",
|
||||
"tex-format"
|
||||
]
|
||||
},
|
||||
"gs-find-block": {
|
||||
"args": [
|
||||
"bx",
|
||||
"by",
|
||||
"tex-format"
|
||||
]
|
||||
},
|
||||
"gs-page-width": {
|
||||
"args": [
|
||||
"tex-format"
|
||||
]
|
||||
},
|
||||
"gs-page-height": {
|
||||
"args": [
|
||||
"tex-format"
|
||||
]
|
||||
},
|
||||
"gs-block-width": {
|
||||
"args": [
|
||||
"tex-format"
|
||||
]
|
||||
},
|
||||
"gs-block-height": {
|
||||
"args": [
|
||||
"tex-format"
|
||||
]
|
||||
},
|
||||
"gs-largest-block": {
|
||||
"args": [
|
||||
"w",
|
||||
"h",
|
||||
"tex-format"
|
||||
]
|
||||
},
|
||||
"gs-blocks-used": {
|
||||
"args": [
|
||||
"w",
|
||||
"h",
|
||||
"tex-format"
|
||||
]
|
||||
},
|
||||
"texture-page-default-allocate": {
|
||||
"args": [
|
||||
"pool",
|
||||
"page",
|
||||
"heap",
|
||||
"page-id"
|
||||
]
|
||||
},
|
||||
"texture-page-common-allocate": {
|
||||
"args": [
|
||||
"pool",
|
||||
"page",
|
||||
"heap",
|
||||
"page-id"
|
||||
]
|
||||
},
|
||||
"texture-page-font-allocate": {
|
||||
"args": [
|
||||
"pool",
|
||||
"page",
|
||||
"heap",
|
||||
"page-id"
|
||||
]
|
||||
},
|
||||
"texture-page-common-boot-allocate": {
|
||||
"args": [
|
||||
"pool",
|
||||
"page",
|
||||
"heap",
|
||||
"page-id"
|
||||
]
|
||||
},
|
||||
"upload-vram-data": {
|
||||
"args": [
|
||||
"dma-buf",
|
||||
"dest",
|
||||
"data-ptr",
|
||||
"h",
|
||||
"w"
|
||||
]
|
||||
},
|
||||
"upload-vram-pages": {
|
||||
"args": [
|
||||
"pool",
|
||||
"pool-segment",
|
||||
"page",
|
||||
"mode",
|
||||
"bucket"
|
||||
]
|
||||
},
|
||||
"update-vram-pages": {
|
||||
"args": [
|
||||
"pool",
|
||||
"pool-segment",
|
||||
"page",
|
||||
"mode"
|
||||
]
|
||||
},
|
||||
"upload-vram-pages-pris": {
|
||||
"args": [
|
||||
"pool",
|
||||
"pool-segment",
|
||||
"page",
|
||||
"bucket",
|
||||
"mask"
|
||||
]
|
||||
},
|
||||
"texture-page-level-allocate": {
|
||||
"args": [
|
||||
"pool",
|
||||
"page",
|
||||
"heap",
|
||||
"page-id"
|
||||
]
|
||||
},
|
||||
"texture-page-size-check": {
|
||||
"args": [
|
||||
"pool",
|
||||
"lev",
|
||||
"print?"
|
||||
]
|
||||
},
|
||||
"upload-textures": {
|
||||
"args": [
|
||||
"pool"
|
||||
]
|
||||
},
|
||||
"texture-relocate": {
|
||||
"args": [
|
||||
"dma-buf",
|
||||
"tex",
|
||||
"dest",
|
||||
"tex-format",
|
||||
"clut-dest"
|
||||
]
|
||||
},
|
||||
"texture-page-login": {
|
||||
"args": [
|
||||
"id",
|
||||
"alloc-func",
|
||||
"heap"
|
||||
]
|
||||
},
|
||||
"lookup-texture-by-id": {
|
||||
"args": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"lookup-texture-by-id-fast": {
|
||||
"args": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"lookup-texture-by-name": {
|
||||
"args": [
|
||||
"tex-name",
|
||||
"page-name",
|
||||
"page-out"
|
||||
]
|
||||
},
|
||||
"lookup-texture-id-by-name": {
|
||||
"args": [
|
||||
"tex-name",
|
||||
"page-name"
|
||||
]
|
||||
},
|
||||
"lookup-level-texture-by-name": {
|
||||
"args": [
|
||||
"tex-name",
|
||||
"lev",
|
||||
"page-out"
|
||||
]
|
||||
},
|
||||
"lookup-tex-id-from-texture": {
|
||||
"args": [
|
||||
"tex"
|
||||
]
|
||||
},
|
||||
"lookup-level-texture-id-by-name": {
|
||||
"args": [
|
||||
"tex-name",
|
||||
"lev",
|
||||
"lev-page-idx"
|
||||
]
|
||||
},
|
||||
"link-texture-by-id": {
|
||||
"args": [
|
||||
"id",
|
||||
"shader"
|
||||
]
|
||||
},
|
||||
"adgif-shader-update!": {
|
||||
"args": [
|
||||
"shader",
|
||||
"tex"
|
||||
]
|
||||
},
|
||||
"hack-texture": {
|
||||
"args": [
|
||||
"tex"
|
||||
]
|
||||
},
|
||||
"adgif-shader-login": {
|
||||
"args": [
|
||||
"shader"
|
||||
]
|
||||
},
|
||||
"adgif-shader-login-no-remap": {
|
||||
"args": [
|
||||
"shader"
|
||||
]
|
||||
},
|
||||
"adgif-shader-login-fast": {
|
||||
"args": [
|
||||
"shader"
|
||||
]
|
||||
},
|
||||
"adgif-shader-login-no-remap-fast": {
|
||||
"args": [
|
||||
"shader"
|
||||
]
|
||||
},
|
||||
"adgif-shader<-texture-simple!": {
|
||||
"args": [
|
||||
"shader",
|
||||
"tex"
|
||||
]
|
||||
},
|
||||
"set-dirty-mask!": {
|
||||
"args": [
|
||||
"lev",
|
||||
"mask-idx",
|
||||
"m0",
|
||||
"m1"
|
||||
]
|
||||
},
|
||||
"(method 13 texture-pool)": {
|
||||
"args": [
|
||||
"this",
|
||||
"lev",
|
||||
"texture-page-count",
|
||||
"texture-ids"
|
||||
]
|
||||
},
|
||||
"(method 14 texture-pool)": {
|
||||
"args": [
|
||||
"pool",
|
||||
"lev",
|
||||
"category",
|
||||
"bucket"
|
||||
]
|
||||
},
|
||||
"(method 15 texture-pool)": {
|
||||
"args": [
|
||||
"this",
|
||||
"size"
|
||||
]
|
||||
},
|
||||
"(method 16 texture-pool)": {
|
||||
"args": [
|
||||
"this",
|
||||
"segment",
|
||||
"size"
|
||||
]
|
||||
},
|
||||
"(method 17 texture-pool)": {
|
||||
"args": [
|
||||
"this",
|
||||
"page"
|
||||
]
|
||||
},
|
||||
"(method 18 texture-pool)": {
|
||||
"args": [
|
||||
"this",
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"(method 7 texture-page)": {
|
||||
"args": [
|
||||
"this",
|
||||
"heap",
|
||||
"filename"
|
||||
]
|
||||
},
|
||||
"(method 9 texture-page)": {
|
||||
"args": [
|
||||
"this",
|
||||
"heap"
|
||||
]
|
||||
},
|
||||
"(method 11 texture-page)": {
|
||||
"args": [
|
||||
"this",
|
||||
"new-dest",
|
||||
"seg-id"
|
||||
]
|
||||
},
|
||||
"(method 12 texture-page)": {
|
||||
"args": [
|
||||
"page",
|
||||
"buf",
|
||||
"mode"
|
||||
]
|
||||
},
|
||||
"(method 13 texture-page)": {
|
||||
"args": [
|
||||
"this",
|
||||
"mode"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -133,20 +133,23 @@ void TextureDB::replace_textures(const fs::path& path) {
|
||||
fs::path base_path(path);
|
||||
for (auto& tex : textures) {
|
||||
fs::path full_path = base_path / tpage_names.at(tex.second.page) / (tex.second.name + ".png");
|
||||
if (fs::exists(full_path)) {
|
||||
lg::info("Replacing {}", full_path.string().c_str());
|
||||
int w, h;
|
||||
auto data = stbi_load(full_path.string().c_str(), &w, &h, 0, 4); // rgba channels
|
||||
if (!data) {
|
||||
lg::warn("failed to load PNG file: {}", full_path.string().c_str());
|
||||
if (!fs::exists(full_path)) {
|
||||
full_path = base_path / "_all" / (tex.second.name + ".png");
|
||||
if (!fs::exists(full_path))
|
||||
continue;
|
||||
}
|
||||
tex.second.rgba_bytes.resize(w * h);
|
||||
memcpy(tex.second.rgba_bytes.data(), data, w * h * 4);
|
||||
tex.second.w = w;
|
||||
tex.second.h = h;
|
||||
stbi_image_free(data);
|
||||
}
|
||||
lg::info("Replacing {}", tpage_names.at(tex.second.page) + "/" + (tex.second.name));
|
||||
int w, h;
|
||||
auto data = stbi_load(full_path.string().c_str(), &w, &h, 0, 4); // rgba channels
|
||||
if (!data) {
|
||||
lg::warn("failed to load PNG file: {}", full_path.string().c_str());
|
||||
continue;
|
||||
}
|
||||
tex.second.rgba_bytes.resize(w * h);
|
||||
memcpy(tex.second.rgba_bytes.data(), data, w * h * 4);
|
||||
tex.second.w = w;
|
||||
tex.second.h = h;
|
||||
stbi_image_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "third-party/json.hpp"
|
||||
|
||||
namespace decompiler {
|
||||
using std::string;
|
||||
|
||||
// number of bytes per "audio page" in the VAG directory file.
|
||||
constexpr int AUDIO_PAGE_SIZE = 2048;
|
||||
@@ -27,75 +28,67 @@ uint32_t swap32(uint32_t in) {
|
||||
struct AudioDir {
|
||||
struct Entry {
|
||||
std::string name;
|
||||
bool stereo = false;
|
||||
bool international = false;
|
||||
s64 start_byte = -1;
|
||||
s64 end_byte = -1;
|
||||
};
|
||||
|
||||
std::vector<Entry> entries;
|
||||
|
||||
void set_file_size(u64 size) {
|
||||
if (!entries.empty()) {
|
||||
entries.back().end_byte = size;
|
||||
}
|
||||
}
|
||||
|
||||
int entry_count() const { return entries.size(); }
|
||||
|
||||
void debug_print() const {
|
||||
for (auto& e : entries) {
|
||||
lg::debug("\"{}\" 0x{:07x} - 0x{:07x}", e.name, e.start_byte, e.end_byte);
|
||||
// lg::debug("\"{}\" 0x{:07x} - 0x{:07x}", e.name, e.start_byte, e.end_byte);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* Read an entry from a WAD and return the binary data.
|
||||
*/
|
||||
std::vector<u8> read_entry(const AudioDir& dir, const std::vector<u8>& data, int entry_idx) {
|
||||
const auto& entry = dir.entries.at(entry_idx);
|
||||
ASSERT(entry.end_byte > 0);
|
||||
return std::vector<u8>(data.begin() + entry.start_byte, data.begin() + entry.end_byte);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Matches the format in file.
|
||||
*/
|
||||
struct VagFileHeader {
|
||||
char magic[4];
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u32 zero;
|
||||
u32 channel_size;
|
||||
u32 size;
|
||||
u32 sample_rate;
|
||||
u32 z[3];
|
||||
char name[16];
|
||||
|
||||
VagFileHeader swapped_endian_jak1() const {
|
||||
VagFileHeader swap_endian() const {
|
||||
VagFileHeader result(*this);
|
||||
result.version = swap32(result.version);
|
||||
result.channel_size = swap32(result.channel_size);
|
||||
result.size = swap32(result.size);
|
||||
result.sample_rate = swap32(result.sample_rate);
|
||||
return result;
|
||||
}
|
||||
|
||||
VagFileHeader swapped_endian_jak2() const {
|
||||
VagFileHeader result(*this);
|
||||
result.version = swap32(result.version);
|
||||
result.channel_size = swap32(result.channel_size);
|
||||
// for some reason, the sample rate is big endian for jak2
|
||||
// result.sample_rate = swap32(result.sample_rate);
|
||||
return result;
|
||||
}
|
||||
|
||||
void debug_print() {
|
||||
char temp_name[17];
|
||||
memcpy(temp_name, name, 16);
|
||||
temp_name[16] = '\0';
|
||||
lg::debug("{}{}{}{} v {} zero {} chan {} samp {} z {} {} {} name {}", magic[0], magic[1],
|
||||
magic[2], magic[3], version, zero, channel_size, sample_rate, z[0], z[1], z[2],
|
||||
temp_name);
|
||||
lg::debug("{:x} v {} zero {} chan {} samp {} z {} {} {} name {}", magic, version, zero, size,
|
||||
sample_rate, z[0], z[1], z[2], temp_name);
|
||||
}
|
||||
};
|
||||
|
||||
static std::string unpack_vag_name_jak3(u64 compressed) {
|
||||
const char* char_map = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-";
|
||||
u32 chars = compressed & 0x1fffff;
|
||||
std::array<char, 9> buf;
|
||||
buf.fill(0);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 4) {
|
||||
chars = (compressed >> 21) & 0x1fffff;
|
||||
}
|
||||
buf[7 - i] = char_map[chars % 38];
|
||||
chars /= 38;
|
||||
}
|
||||
|
||||
return {buf.data()};
|
||||
}
|
||||
|
||||
/*!
|
||||
* Read the DIR file into an AudioDir
|
||||
*/
|
||||
@@ -103,9 +96,9 @@ AudioDir read_audio_dir(const decompiler::Config& config, const fs::path& path)
|
||||
auto data = file_util::read_binary_file(path);
|
||||
lg::info("Got {} bytes of audio dir.", data.size());
|
||||
auto reader = BinaryReader(data);
|
||||
u32 count = reader.read<u32>();
|
||||
AudioDir result;
|
||||
if (config.game_version == GameVersion::Jak1) {
|
||||
u32 count = reader.read<u32>();
|
||||
// matches the format in file.
|
||||
struct DirEntryJak1 {
|
||||
char name[8];
|
||||
@@ -129,20 +122,15 @@ AudioDir read_audio_dir(const decompiler::Config& config, const fs::path& path)
|
||||
e.name.push_back(c);
|
||||
}
|
||||
e.start_byte = AUDIO_PAGE_SIZE * entries[i].value;
|
||||
if (i + 1 < (entries.size())) {
|
||||
e.end_byte = AUDIO_PAGE_SIZE * entries[i + 1].value;
|
||||
} else {
|
||||
e.end_byte = -1;
|
||||
}
|
||||
result.entries.push_back(e);
|
||||
}
|
||||
} else if (config.game_version == GameVersion::Jak2) {
|
||||
u32 count = reader.read<u32>();
|
||||
// matches the format in file.
|
||||
struct DirEntryJak2 {
|
||||
char name[8];
|
||||
u32 value;
|
||||
// TODO - no idea what this is
|
||||
u32 boolean;
|
||||
u32 stereo;
|
||||
};
|
||||
u32 data_end = sizeof(u32) + sizeof(DirEntryJak2) * count;
|
||||
ASSERT(data_end <= data.size());
|
||||
@@ -161,12 +149,45 @@ AudioDir read_audio_dir(const decompiler::Config& config, const fs::path& path)
|
||||
// padded with spaces, no null terminator.
|
||||
e.name.push_back(c);
|
||||
}
|
||||
e.stereo = entries[i].stereo;
|
||||
e.start_byte = AUDIO_PAGE_SIZE * entries[i].value;
|
||||
if (i + 1 < (entries.size())) {
|
||||
e.end_byte = AUDIO_PAGE_SIZE * entries[i + 1].value;
|
||||
} else {
|
||||
e.end_byte = -1;
|
||||
}
|
||||
result.entries.push_back(e);
|
||||
}
|
||||
} else if (config.game_version == GameVersion::Jak3) {
|
||||
struct VagDirJak3 {
|
||||
u32 id[2];
|
||||
u32 version;
|
||||
u32 count;
|
||||
} dir;
|
||||
struct DirEntryJak3 {
|
||||
union {
|
||||
u64 data;
|
||||
struct {
|
||||
u64 name : 42;
|
||||
bool stereo : 1;
|
||||
bool international : 1;
|
||||
u8 param : 4;
|
||||
u64 offset : 16;
|
||||
};
|
||||
};
|
||||
};
|
||||
dir = reader.read<VagDirJak3>();
|
||||
ASSERT(dir.id[0] == 0x41574756);
|
||||
ASSERT(dir.id[1] == 0x52494444);
|
||||
lg::warn("version {} count {}", dir.version, dir.count);
|
||||
|
||||
std::vector<DirEntryJak3> entries;
|
||||
|
||||
for (size_t i = 0; i < dir.count; i++) {
|
||||
entries.push_back(reader.read<DirEntryJak3>());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < entries.size(); i++) {
|
||||
AudioDir::Entry e;
|
||||
e.name = unpack_vag_name_jak3(entries[i].name);
|
||||
e.stereo = entries[i].stereo;
|
||||
e.international = entries[i].international;
|
||||
e.start_byte = 0x8000 * entries[i].offset;
|
||||
result.entries.push_back(e);
|
||||
}
|
||||
} else {
|
||||
@@ -189,27 +210,22 @@ struct AudioFileInfo {
|
||||
};
|
||||
|
||||
AudioFileInfo process_audio_file(const fs::path& output_folder,
|
||||
const std::vector<u8>& data,
|
||||
nonstd::span<const uint8_t> data,
|
||||
const std::string& name,
|
||||
const std::string& suffix) {
|
||||
const std::string& suffix,
|
||||
bool stereo) {
|
||||
BinaryReader reader(data);
|
||||
|
||||
auto header = reader.read<VagFileHeader>();
|
||||
if (header.magic[0] == 'V') {
|
||||
header = header.swapped_endian_jak1();
|
||||
} else if (header.magic[0] == 'p') {
|
||||
header = header.swapped_endian_jak2();
|
||||
} else {
|
||||
if (header.magic == 0x70474156 /* big endian (VAGp)*/) {
|
||||
header = header.swap_endian();
|
||||
} else if (header.magic != 0x56414770 /* little endian (pGAV) */) {
|
||||
ASSERT(false);
|
||||
}
|
||||
header.debug_print();
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
ASSERT(reader.read<u8>() == 0);
|
||||
}
|
||||
|
||||
const auto [left_samples, right_samples] =
|
||||
decode_adpcm(reader, !str_util::starts_with(std::string(header.name), "Stereo"));
|
||||
reader = BinaryReader(data.subspan(0, header.size));
|
||||
const auto [left_samples, right_samples] = decode_adpcm(reader, stereo);
|
||||
|
||||
while (reader.bytes_left()) {
|
||||
ASSERT(reader.read<u8>() == 0);
|
||||
@@ -251,12 +267,17 @@ void process_streamed_audio(const decompiler::Config& config,
|
||||
auto& file = audio_files[lang_id];
|
||||
auto wad_data = file_util::read_binary_file(input_dir / "VAG" / file);
|
||||
auto suffix = fs::path(file).extension().u8string().substr(1);
|
||||
bool int_bank_p = suffix.compare("INT") == 0;
|
||||
langs.push_back(suffix);
|
||||
dir_data.set_file_size(wad_data.size());
|
||||
for (int i = 0; i < dir_data.entry_count(); i++) {
|
||||
auto audio_data = read_entry(dir_data, wad_data, i);
|
||||
lg::info("File {}, total {:.2f} minutes", dir_data.entries.at(i).name, audio_len / 60.0);
|
||||
auto info = process_audio_file(output_path, audio_data, dir_data.entries.at(i).name, suffix);
|
||||
auto entry = dir_data.entries.at(i);
|
||||
if (entry.international != int_bank_p) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lg::info("File {}, total {:.2f} minutes", entry.name, audio_len / 60.0);
|
||||
auto data = nonstd::span(wad_data).subspan(entry.start_byte);
|
||||
auto info = process_audio_file(output_path, data, entry.name, suffix, entry.stereo);
|
||||
audio_len += info.length_seconds;
|
||||
filename_data[i][lang_id + 1] = info.filename;
|
||||
}
|
||||
|
||||
@@ -200,8 +200,7 @@ void decompile(const fs::path& iso_data_path, const std::string& data_subfolder)
|
||||
auto level_out_path =
|
||||
file_util::get_jak_project_dir() / "out" / game_version_names[config.game_version] / "fr3";
|
||||
file_util::create_dir_if_needed(level_out_path);
|
||||
extract_all_levels(db, tex_db, config.levels_to_extract, "GAME.CGO", config, config.rip_levels,
|
||||
config.extract_collision, level_out_path);
|
||||
extract_all_levels(db, tex_db, config.levels_to_extract, "GAME.CGO", config, level_out_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "extract_collide_frags.h"
|
||||
|
||||
#include "common/log/log.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
|
||||
namespace decompiler {
|
||||
@@ -230,9 +231,9 @@ void set_vertices_for_tri(tfrag3::CollisionMesh::Vertex* out, const math::Vector
|
||||
|
||||
void extract_collide_frags(const level_tools::DrawableTreeCollideFragment* tree,
|
||||
const std::vector<const level_tools::DrawableTreeInstanceTie*>& ties,
|
||||
const Config& config,
|
||||
const std::string& debug_name,
|
||||
tfrag3::Level& out,
|
||||
bool dump_level) {
|
||||
tfrag3::Level& out) {
|
||||
// in-game, the broad-phase collision builds a list of fragments, then unpacks them with:
|
||||
/*
|
||||
*(dotimes (i (-> *collide-list* num-items))
|
||||
@@ -258,10 +259,10 @@ void extract_collide_frags(const level_tools::DrawableTreeCollideFragment* tree,
|
||||
total_faces += frag.unpacked.faces.size();
|
||||
}
|
||||
|
||||
if (dump_level) {
|
||||
if (config.rip_collision) {
|
||||
auto debug_out = debug_dump_to_obj(all_frags);
|
||||
auto file_path =
|
||||
file_util::get_file_path({"debug_out", fmt::format("collide-{}.obj", debug_name)});
|
||||
auto file_path = file_util::get_file_path(
|
||||
{fmt::format("debug_out/{}", config.game_name), fmt::format("collide-{}.obj", debug_name)});
|
||||
file_util::create_dir_if_needed_for_file(file_path);
|
||||
file_util::write_text_file(file_path, debug_out);
|
||||
}
|
||||
@@ -408,8 +409,37 @@ void handle_collide_fragment(const TypedRef& collide_fragment,
|
||||
}
|
||||
}
|
||||
|
||||
std::string debug_dump_to_obj(const std::vector<tfrag3::CollisionMesh::Vertex>& verts_in) {
|
||||
std::vector<math::Vector4f> verts;
|
||||
std::vector<math::Vector<u32, 3>> faces;
|
||||
|
||||
for (auto& v : verts_in) {
|
||||
verts.emplace_back(v.x / 4096.0, v.y / 4096.0, v.z / 4096.0, 1.0);
|
||||
|
||||
u32 v_len = verts.size();
|
||||
if (v_len % 3 == 0) {
|
||||
// add face from last 3 vertices
|
||||
faces.emplace_back(v_len - 2, v_len - 1, v_len);
|
||||
}
|
||||
}
|
||||
|
||||
std::string result;
|
||||
for (auto& vert : verts) {
|
||||
result += fmt::format("v {} {} {}\n", vert.x(), vert.y(), vert.z());
|
||||
}
|
||||
|
||||
for (auto& face : faces) {
|
||||
result += fmt::format("f {}/{} {}/{} {}/{}\n", face.x(), face.x(), face.y(), face.y(), face.z(),
|
||||
face.z());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void extract_collide_frags(const level_tools::CollideHash& chash,
|
||||
const std::vector<const level_tools::DrawableTreeInstanceTie*>& ties,
|
||||
const Config& config,
|
||||
const std::string& debug_name,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
tfrag3::Level& out) {
|
||||
// We need to find all collide-hash-fragments, but we can't just scan through the entire file.
|
||||
@@ -474,5 +504,15 @@ void extract_collide_frags(const level_tools::CollideHash& chash,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.rip_collision) {
|
||||
// out.collision.vertices every 3 vertices make a face, so it duplicates vertices in many cases
|
||||
// for now debug_dump_to_obj isn't smart and doesn't hash these to save space or anything
|
||||
auto debug_out = debug_dump_to_obj(out.collision.vertices);
|
||||
auto file_path = file_util::get_file_path(
|
||||
{fmt::format("debug_out/{}", config.game_name), fmt::format("collide-{}.obj", debug_name)});
|
||||
file_util::create_dir_if_needed_for_file(file_path);
|
||||
file_util::write_text_file(file_path, debug_out);
|
||||
}
|
||||
}
|
||||
} // namespace decompiler
|
||||
@@ -8,13 +8,15 @@ namespace decompiler {
|
||||
|
||||
void extract_collide_frags(const level_tools::DrawableTreeCollideFragment* tree,
|
||||
const std::vector<const level_tools::DrawableTreeInstanceTie*>& ties,
|
||||
const Config& config,
|
||||
const std::string& debug_name,
|
||||
tfrag3::Level& out,
|
||||
bool dump_level);
|
||||
tfrag3::Level& out);
|
||||
|
||||
void extract_collide_frags(const level_tools::CollideHash& chash,
|
||||
const std::vector<const level_tools::DrawableTreeInstanceTie*>& ties,
|
||||
const Config& config,
|
||||
const std::string& debug_name,
|
||||
const decompiler::DecompilerTypeSystem& dts,
|
||||
tfrag3::Level& out);
|
||||
|
||||
} // namespace decompiler
|
||||
} // namespace decompiler
|
||||
@@ -159,9 +159,9 @@ std::vector<level_tools::TextureRemap> extract_tex_remap(const ObjectFileDB& db,
|
||||
level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db,
|
||||
const TextureDB& tex_db,
|
||||
const std::string& dgo_name,
|
||||
const DecompileHacks& hacks,
|
||||
bool extract_collision,
|
||||
const Config& config,
|
||||
tfrag3::Level& level_data) {
|
||||
auto hacks = config.hacks;
|
||||
auto bsp_rec = get_bsp_file(db.obj_files_by_dgo.at(dgo_name), dgo_name);
|
||||
if (!bsp_rec) {
|
||||
lg::warn("Skipping extract for {} because the BSP file was not found", dgo_name);
|
||||
@@ -230,14 +230,15 @@ level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db,
|
||||
ASSERT(as_shrub_tree);
|
||||
extract_shrub(as_shrub_tree, fmt::format("{}-{}-shrub", dgo_name, i++),
|
||||
bsp_header.texture_remap_table, tex_db, {}, level_data, false, db.version());
|
||||
} else if (draw_tree->my_type() == "drawable-tree-collide-fragment" && extract_collision) {
|
||||
} else if (draw_tree->my_type() == "drawable-tree-collide-fragment" &&
|
||||
config.extract_collision) {
|
||||
auto as_collide_frags =
|
||||
dynamic_cast<level_tools::DrawableTreeCollideFragment*>(draw_tree.get());
|
||||
ASSERT(as_collide_frags);
|
||||
ASSERT(!got_collide);
|
||||
got_collide = true;
|
||||
extract_collide_frags(as_collide_frags, all_ties, fmt::format("{}-{}-collide", dgo_name, i++),
|
||||
level_data, false);
|
||||
extract_collide_frags(as_collide_frags, all_ties, config,
|
||||
fmt::format("{}-{}-collide", dgo_name, i++), level_data);
|
||||
} else {
|
||||
lg::print(" unsupported tree {}\n", draw_tree->my_type());
|
||||
}
|
||||
@@ -245,7 +246,8 @@ level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db,
|
||||
|
||||
if (bsp_header.collide_hash.num_items) {
|
||||
ASSERT(!got_collide);
|
||||
extract_collide_frags(bsp_header.collide_hash, all_ties, db.dts, level_data);
|
||||
extract_collide_frags(bsp_header.collide_hash, all_ties, config,
|
||||
fmt::format("{}-{}-collide", dgo_name, i++), db.dts, level_data);
|
||||
}
|
||||
level_data.level_name = level_name;
|
||||
|
||||
@@ -260,7 +262,6 @@ level_tools::BspHeader extract_bsp_from_level(const ObjectFileDB& db,
|
||||
void extract_common(const ObjectFileDB& db,
|
||||
const TextureDB& tex_db,
|
||||
const std::string& dgo_name,
|
||||
bool dump_levels,
|
||||
const fs::path& output_folder,
|
||||
const Config& config) {
|
||||
if (db.obj_files_by_dgo.count(dgo_name) == 0) {
|
||||
@@ -323,7 +324,7 @@ void extract_common(const ObjectFileDB& db,
|
||||
output_folder / fmt::format("{}.fr3", dgo_name.substr(0, dgo_name.length() - 4)),
|
||||
compressed.data(), compressed.size());
|
||||
|
||||
if (dump_levels) {
|
||||
if (config.rip_levels) {
|
||||
auto file_path = file_util::get_jak_project_dir() / "glb_out" / "common.glb";
|
||||
file_util::create_dir_if_needed_for_file(file_path);
|
||||
save_level_foreground_as_gltf(tfrag_level, art_group_data, file_path);
|
||||
@@ -334,8 +335,6 @@ void extract_from_level(const ObjectFileDB& db,
|
||||
const TextureDB& tex_db,
|
||||
const std::string& dgo_name,
|
||||
const Config& config,
|
||||
bool dump_level,
|
||||
bool extract_collision,
|
||||
const fs::path& output_folder,
|
||||
const fs::path& entities_folder) {
|
||||
if (db.obj_files_by_dgo.count(dgo_name) == 0) {
|
||||
@@ -347,8 +346,7 @@ void extract_from_level(const ObjectFileDB& db,
|
||||
add_all_textures_from_level(level_data, dgo_name, tex_db);
|
||||
|
||||
// the bsp header file data
|
||||
auto bsp_header =
|
||||
extract_bsp_from_level(db, tex_db, dgo_name, config.hacks, extract_collision, level_data);
|
||||
auto bsp_header = extract_bsp_from_level(db, tex_db, dgo_name, config, level_data);
|
||||
extract_art_groups_from_level(db, tex_db, bsp_header.texture_remap_table, dgo_name, level_data,
|
||||
art_group_data);
|
||||
|
||||
@@ -364,7 +362,7 @@ void extract_from_level(const ObjectFileDB& db,
|
||||
output_folder / fmt::format("{}.fr3", dgo_name.substr(0, dgo_name.length() - 4)),
|
||||
compressed.data(), compressed.size());
|
||||
|
||||
if (dump_level) {
|
||||
if (config.rip_levels) {
|
||||
auto back_file_path = file_util::get_jak_project_dir() / "glb_out" /
|
||||
fmt::format("{}_background.glb", level_data.level_name);
|
||||
file_util::create_dir_if_needed_for_file(back_file_path);
|
||||
@@ -383,18 +381,15 @@ void extract_all_levels(const ObjectFileDB& db,
|
||||
const std::vector<std::string>& dgo_names,
|
||||
const std::string& common_name,
|
||||
const Config& config,
|
||||
bool debug_dump_level,
|
||||
bool extract_collision,
|
||||
const fs::path& output_path) {
|
||||
extract_common(db, tex_db, common_name, debug_dump_level, output_path, config);
|
||||
extract_common(db, tex_db, common_name, output_path, config);
|
||||
auto entities_dir = file_util::get_jak_project_dir() / "decompiler_out" /
|
||||
game_version_names[config.game_version] / "entities";
|
||||
file_util::create_dir_if_needed(entities_dir);
|
||||
SimpleThreadGroup threads;
|
||||
threads.run(
|
||||
[&](int idx) {
|
||||
extract_from_level(db, tex_db, dgo_names[idx], config, debug_dump_level, extract_collision,
|
||||
output_path, entities_dir);
|
||||
extract_from_level(db, tex_db, dgo_names[idx], config, output_path, entities_dir);
|
||||
},
|
||||
dgo_names.size());
|
||||
threads.join();
|
||||
|
||||
@@ -16,8 +16,6 @@ void extract_all_levels(const ObjectFileDB& db,
|
||||
const std::vector<std::string>& dgo_names,
|
||||
const std::string& common_name,
|
||||
const Config& config,
|
||||
bool debug_dump_level,
|
||||
bool extract_collision,
|
||||
const fs::path& path);
|
||||
void add_all_textures_from_level(tfrag3::Level& lev,
|
||||
const std::string& level_name,
|
||||
|
||||
@@ -424,7 +424,8 @@ void make_draws(tfrag3::Level& lev,
|
||||
std::vector<std::vector<u32>> indices_regrouped_by_draw;
|
||||
std::unordered_map<u32, std::vector<u32>> static_draws_by_tex;
|
||||
size_t global_vert_counter = 0;
|
||||
for (auto& proto : protos) {
|
||||
for (u32 proto_idx = 0; proto_idx < protos.size(); proto_idx++) {
|
||||
auto& proto = protos[proto_idx];
|
||||
// packed_vert_indices[frag][draw] = {start, end}
|
||||
std::vector<std::vector<std::pair<int, int>>> packed_vert_indices;
|
||||
|
||||
@@ -509,7 +510,9 @@ void make_draws(tfrag3::Level& lev,
|
||||
std::vector<u32>* verts_to_add_to = nullptr;
|
||||
if (existing_draws_in_tex != static_draws_by_tex.end()) {
|
||||
for (auto idx : existing_draws_in_tex->second) {
|
||||
if (tree_out.static_draws.at(idx).mode == mode) {
|
||||
auto& candidate_draw_out = tree_out.static_draws.at(idx);
|
||||
if (candidate_draw_out.mode == mode && (!tree_out.has_per_proto_visibility_toggle ||
|
||||
candidate_draw_out.proto_idx == proto_idx)) {
|
||||
draw_to_add_to = &tree_out.static_draws[idx];
|
||||
verts_to_add_to = &indices_regrouped_by_draw[idx];
|
||||
}
|
||||
@@ -523,6 +526,9 @@ void make_draws(tfrag3::Level& lev,
|
||||
draw_to_add_to = &tree_out.static_draws.back();
|
||||
draw_to_add_to->mode = mode;
|
||||
draw_to_add_to->tree_tex_id = idx_in_lev_data;
|
||||
if (tree_out.has_per_proto_visibility_toggle) {
|
||||
draw_to_add_to->proto_idx = proto_idx;
|
||||
}
|
||||
verts_to_add_to = &indices_regrouped_by_draw.emplace_back();
|
||||
}
|
||||
|
||||
@@ -573,10 +579,16 @@ void extract_shrub(const shrub_types::DrawableTreeInstanceShrub* tree,
|
||||
bool dump_level,
|
||||
GameVersion version) {
|
||||
auto& tree_out = out.shrub_trees.emplace_back();
|
||||
|
||||
if (version > GameVersion::Jak1) {
|
||||
tree_out.has_per_proto_visibility_toggle = true;
|
||||
}
|
||||
|
||||
auto& protos = tree->info.prototype_inline_array_shrub;
|
||||
std::vector<ShrubProtoInfo> proto_info;
|
||||
for (auto& proto : protos.data) {
|
||||
proto_info.push_back(extract_proto(proto, tex_db, map, version));
|
||||
tree_out.proto_names.push_back(proto.name);
|
||||
}
|
||||
|
||||
for (auto& arr : tree->discovered_arrays) {
|
||||
|
||||
+1
-2
@@ -321,8 +321,7 @@ int main(int argc, char** argv) {
|
||||
auto level_out_path =
|
||||
file_util::get_jak_project_dir() / "out" / game_version_names[config.game_version] / "fr3";
|
||||
file_util::create_dir_if_needed(level_out_path);
|
||||
extract_all_levels(db, tex_db, config.levels_to_extract, "GAME.CGO", config, config.rip_levels,
|
||||
config.extract_collision, level_out_path);
|
||||
extract_all_levels(db, tex_db, config.levels_to_extract, "GAME.CGO", config, level_out_path);
|
||||
}
|
||||
|
||||
mem_log("After extraction: {} MB", get_peak_rss() / (1024 * 1024));
|
||||
|
||||
@@ -1368,7 +1368,7 @@ void types2_for_add(types2::Type& type_out,
|
||||
}
|
||||
}
|
||||
|
||||
if (env.version == GameVersion::Jak2 && tc(dts, TypeSpec("symbol"), arg1_type) &&
|
||||
if (env.version >= GameVersion::Jak2 && tc(dts, TypeSpec("symbol"), arg1_type) &&
|
||||
is_int_or_uint(dts, arg0_type)) {
|
||||
if (arg0_type.is_integer_constant(jak2::SYM_TO_STRING_OFFSET)) {
|
||||
// symbol -> GOAL String
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "decompiler/Disasm/Register.h"
|
||||
|
||||
namespace decompiler {
|
||||
DecompilerTypeSystem::DecompilerTypeSystem(GameVersion version) {
|
||||
DecompilerTypeSystem::DecompilerTypeSystem(GameVersion version) : m_version(version) {
|
||||
ts.add_builtin_types(version);
|
||||
}
|
||||
|
||||
@@ -115,6 +115,29 @@ void DecompilerTypeSystem::parse_type_defs(const std::vector<std::string>& file_
|
||||
});
|
||||
}
|
||||
|
||||
void DecompilerTypeSystem::parse_enum_defs(const std::vector<std::string>& file_path) {
|
||||
auto read = m_reader.read_from_file(file_path);
|
||||
auto& data = cdr(read);
|
||||
|
||||
for_each_in_list(data, [&](goos::Object& o) {
|
||||
try {
|
||||
if (car(o).as_symbol() == "defenum") {
|
||||
auto symbol_metadata = DefinitionMetadata();
|
||||
parse_defenum(cdr(o), &ts, &symbol_metadata);
|
||||
symbol_metadata.definition_info = m_reader.db.get_short_info_for(o);
|
||||
auto* rest = &cdr(o);
|
||||
const auto& enum_name = car(*rest).as_symbol();
|
||||
symbol_metadata_map[enum_name.name_ptr] = symbol_metadata;
|
||||
// so far, enums are never runtime types so there's no symbol for them.
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
auto info = m_reader.db.get_info_for(o);
|
||||
lg::error("{} when parsing decompiler type file:{}", e.what(), info);
|
||||
throw;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
TypeSpec DecompilerTypeSystem::parse_type_spec(const std::string& str) const {
|
||||
auto read = m_reader.read_from_string(str);
|
||||
auto data = cdr(read);
|
||||
|
||||
@@ -56,6 +56,7 @@ class DecompilerTypeSystem {
|
||||
const TypeSpec& type_spec,
|
||||
const DefinitionMetadata& symbol_metadata);
|
||||
void parse_type_defs(const std::vector<std::string>& file_path);
|
||||
void parse_enum_defs(const std::vector<std::string>& file_path);
|
||||
TypeSpec parse_type_spec(const std::string& str) const;
|
||||
void add_type_flags(const std::string& name, u64 flags);
|
||||
void add_type_parent(const std::string& child, const std::string& parent);
|
||||
@@ -94,7 +95,10 @@ class DecompilerTypeSystem {
|
||||
void reset() { current_method_type.clear(); }
|
||||
} type_prop_settings;
|
||||
|
||||
GameVersion version() const { return m_version; }
|
||||
|
||||
private:
|
||||
GameVersion m_version;
|
||||
mutable goos::Reader m_reader;
|
||||
};
|
||||
} // namespace decompiler
|
||||
@@ -179,7 +179,7 @@ goos::Object decompile_function_at_label(const DecompilerLabel& label,
|
||||
auto other_func = file->try_get_function_at_label(label);
|
||||
if (other_func && other_func->ir2.env.has_local_vars() && other_func->ir2.top_form &&
|
||||
other_func->ir2.expressions_succeeded) {
|
||||
auto out = final_output_lambda(*other_func);
|
||||
auto out = final_output_lambda(*other_func, file->version);
|
||||
if (in_static_pair) {
|
||||
return pretty_print::build_list("unquote", out);
|
||||
} else {
|
||||
@@ -967,6 +967,12 @@ const std::unordered_map<
|
||||
{"speeches", ArrayFieldDecompMeta(TypeSpec("bot-speech-info"), 16)},
|
||||
{"dirs", ArrayFieldDecompMeta(TypeSpec("vector"), 16)},
|
||||
{"speech-tunings", ArrayFieldDecompMeta(TypeSpec("bot-speech-tuning"), 16)}}},
|
||||
}},
|
||||
{GameVersion::Jak3,
|
||||
{
|
||||
{"ocean-near-indices",
|
||||
{{"data", ArrayFieldDecompMeta(TypeSpec("ocean-near-index"), 32)}}},
|
||||
{"ocean-mid-masks", {{"data", ArrayFieldDecompMeta(TypeSpec("ocean-mid-mask"), 8)}}},
|
||||
}}};
|
||||
|
||||
goos::Object decompile_structure(const TypeSpec& type,
|
||||
|
||||
@@ -13,7 +13,9 @@ namespace decompiler {
|
||||
bool allowable_base_type_for_symbol_to_string(const TypeSpec& ts);
|
||||
|
||||
constexpr PerGameVersion<int> SYMBOL_TO_STRING_MEM_OFFSET_DECOMP = {
|
||||
8167 * 8, jak2::SYM_TO_STRING_OFFSET, jak3::SYM_TO_STRING_OFFSET};
|
||||
8167 * 8, jak2::SYM_TO_STRING_OFFSET,
|
||||
-99999, // not supported this way!
|
||||
};
|
||||
|
||||
constexpr PerGameVersion<int> OFFSET_OF_NEXT_STATE_STORE = {72, 64, 68};
|
||||
} // namespace decompiler
|
||||
@@ -0,0 +1,44 @@
|
||||
# BLERC
|
||||
"blerc" = "merc blend shape" is the face animation program.
|
||||
|
||||
It works by updating the vertices used by merc.
|
||||
|
||||
It begine with a call to `(blerc-init)`, which resets the list of things to blerc.
|
||||
|
||||
Then, each process-drawable calls `merc-blend-shape` (if needed), which figures out the blend shape coefficients for the current frame, and passes it to `setup-blerc-chains`. This builds a DMA chain of all blercs.
|
||||
|
||||
However, this DMA chain doesn't get put in a VU1 bucket. Instead, after the full chain is build, `(blerc-execute)` will do a bunch of math and update the merc vertex data.
|
||||
|
||||
This was checked by running `(-> (the process-drawable (process-by-name "sidekick" *active-pool*)) draw mgeo effect 0 frag-geo)` and seeing that the `spad_from_dma_no_sadr_off` in `merc_blend_shape.cpp` was writing to this data.
|
||||
|
||||
There is a system to avoid doing blerc computations when not needed. Once blerc is disabled, it does a single final run with all 0's, which puts everything "back to normal", and then blerc no longer runs.
|
||||
|
||||
# Determining which fragments can be blerc'd
|
||||
In the PC port, we will need to update the vertices. We want to update as few vertices as possible at runtime because this will likely be slow. Additionally, we need metadata to figure out how to go from modified merc data back to PC-port format. If we know which vertices can possibly be modified by blerc, we can skip including the metadata for the rest. Only a small number of merc vertices are faces, so this could be a big win for data size.
|
||||
|
||||
As far as I can tell, there's a `merc-blend-ctrl` per each fragment. It's size is `2 + merc_ctrl.header.blend_target_count`. If the `blend-vtx-count` field of a merc-blend-ctrl is 0, then this fragment has no blerc.
|
||||
|
||||
Checking some common models:
|
||||
(showing number of effects, frags, lump4 bytes that have possible blerc)
|
||||
```
|
||||
BLERC: eichar-lod0, 3/4 e, 15/85 f, 1737/9984 v
|
||||
BLERC: sidekick-lod0, 3/4 e, 9/35 f, 957/3933 v
|
||||
```
|
||||
|
||||
# PC draw lists:
|
||||
The plan is to make 3 sets of draws:
|
||||
- Normal draw list
|
||||
- Draw list that touches no blerc vertices
|
||||
- Alternate draw list for blerc vertices
|
||||
|
||||
The first list is what is normally used. This may contain draws that mix together blerc and non-blerc vertices.
|
||||
|
||||
The second draw list can be used when blerc is active for this character for all the non-blerc vertices.
|
||||
|
||||
The third draw list will contain the blerc vertices, but will do indexing slightly differently. Instead of indexing into the giant array of all merc vertices, it will index into the yet-to-be-filled blerc index buffer for this character.
|
||||
|
||||
This approach gives us:
|
||||
- the same performance as before if blerc is off
|
||||
- easy way to do per-character blerc'd vertex uploads
|
||||
- possibility to do per-frame blerc'd vertex uploads with some clever indexing.
|
||||
- per-fragment granularity for blerc on/off
|
||||
@@ -0,0 +1,137 @@
|
||||
## Finding the Normals
|
||||
We're going to assume that the generic tie math in Jak 1 is the same as ETIE as Jak 2. This could be wrong, but it should be easy to verify.
|
||||
|
||||
The tricky part is finding the normals. These are needed for ETIE, but not plain TIE.
|
||||
|
||||
For looking through the types, it seems like generic TIE uses the same normals as ETIE:
|
||||
```lisp
|
||||
(deftype generic-tie-normal (structure)
|
||||
((x int8 :offset-assert 0)
|
||||
(y int8 :offset-assert 1)
|
||||
(z int8 :offset-assert 2)
|
||||
(dummy int8 :offset-assert 3) ;; was 0 in ETIE normals.
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x4
|
||||
:flag-assert #x900000004
|
||||
)
|
||||
```
|
||||
|
||||
Searching around for normal
|
||||
```lisp
|
||||
(deftype generic-tie-header (structure)
|
||||
((effect uint8 :offset-assert 0)
|
||||
(interp-table-size uint8 :offset-assert 1)
|
||||
(num-bps uint8 :offset-assert 2)
|
||||
(num-ips uint8 :offset-assert 3)
|
||||
(tint-color uint32 :offset-assert 4)
|
||||
(index-table-offset uint16 :offset-assert 8)
|
||||
(kick-table-offset uint16 :offset-assert 10)
|
||||
(normal-table-offset uint16 :offset-assert 12) ;; here it is!
|
||||
(interp-table-offset uint16 :offset-assert 14)
|
||||
(gsf-header gsf-header :inline :offset-assert 16)
|
||||
)
|
||||
:method-count-assert 9
|
||||
:size-assert #x20
|
||||
:flag-assert #x900000020
|
||||
)
|
||||
```
|
||||
|
||||
My first guess is that the generic data for a TIE fragment is just a header, and these `uint16`s are byte-offsets for the normal data. I'd guess that there's a header per-fragment - they used `uint8`'s for `num-bps`/`num-ips` (base points, interpolated points). A single proto might have more than 255 points, but a fragment won't.
|
||||
|
||||
My guess is that `generic-ref` in a `tie-fragment` points to some data that starts with `generic-tie-header`.
|
||||
```lisp
|
||||
(deftype tie-fragment (drawable)
|
||||
((gif-ref (inline-array adgif-shader) :offset 4)
|
||||
(point-ref uint32 :offset 8)
|
||||
(color-index uint16 :offset 12)
|
||||
(base-colors uint8 :offset 14)
|
||||
(tex-count uint16 :offset-assert 32)
|
||||
(gif-count uint16 :offset-assert 34)
|
||||
(vertex-count uint16 :offset-assert 36)
|
||||
(color-count uint16 :offset-assert 38)
|
||||
(num-tris uint16 :offset-assert 40)
|
||||
(num-dverts uint16 :offset-assert 42)
|
||||
(dp-ref uint32 :offset-assert 44)
|
||||
(dp-qwc uint32 :offset-assert 48)
|
||||
(generic-ref uint32 :offset-assert 52) ;; the data we want
|
||||
(generic-count uint32 :offset-assert 56)
|
||||
(debug-lines (array vector-array) :offset-assert 60)
|
||||
)
|
||||
:method-count-assert 18
|
||||
:size-assert #x40
|
||||
:flag-assert #x1200000040
|
||||
)
|
||||
```
|
||||
|
||||
Extract the data from the file
|
||||
```cpp
|
||||
u16 generic_qwc = read_plain_data_field<u32>(ref, "generic-count", dts);
|
||||
if (generic_qwc) {
|
||||
generic_data.resize(16 * generic_qwc);
|
||||
auto generic_data_ref = deref_label(get_field_ref(ref, "generic-ref", dts));
|
||||
memcpy_plain_data((u8*)generic_data.data(), generic_data_ref, generic_qwc * 16);
|
||||
```
|
||||
|
||||
The data made sense. There were some cases where the `interp-table` and the `normal-table` appeared to be on top of each other, but this only occured when `num-ips` was 0 and `interp-table-size` was 0 too.
|
||||
|
||||
Treating `normal-table-offset` as a byte-offset from the start of the header seemed to work.
|
||||
|
||||
One fear I had is that the mesh for generic/non-generic is somehow different, so I sanity checked that `num-ips` + `num-bps` from the generic header matched the total unique vertex count from the TIE unpacker.
|
||||
|
||||
## Finding the Envmap shader
|
||||
We need an additional shader for the environment map draw. Fortunately, this seems the same as Jak 2 - there's a field in `prototype-bucket-tie` for it. I turned on that code for Jak 1, and it found envmap shaders on reasonable things.
|
||||
|
||||
## Finding the tint color
|
||||
This is a little trickier. In jak 2, the tint color was specified per bucket, but in Jak 1, it's specified per fragment. Luckily my data format for ETIE can support this, but `extract_tie.cpp` needs some refactoring to actually generate it.
|
||||
|
||||
## Normal Bugs
|
||||
|
||||
Some very small number of fragments appear totally wrong.
|
||||
|
||||
The most likely explanation is the normals are in the wrong order. The normals seems like valid normals, but looking at the mesh, they are clearly wrong.
|
||||
|
||||
I made the assumption that the order of normals would match the order of points, but could this be wrong?
|
||||
|
||||
There's this table called `index_table`:
|
||||
```
|
||||
0 2 32 33
|
||||
1 3 16 17
|
||||
34 35 4 5
|
||||
6 8 36 37
|
||||
7 9 18 20
|
||||
38 39 19 21
|
||||
10 11 40 41
|
||||
22 23 12 13
|
||||
42 43 24 25
|
||||
14 15 44 45
|
||||
26 27 28 29
|
||||
46 47 30 31
|
||||
```
|
||||
but going through extremely carefully showed nothing interesting... It all matches up perfectly
|
||||
|
||||
Next step: maybe the normal matrix is wrong... let's try to actually find the mystery scaling factor:
|
||||
|
||||
```
|
||||
vmulx.xyz vf16, vf10, vf14
|
||||
```
|
||||
the `vf14.x` here.
|
||||
|
||||
```
|
||||
lui t6, 16256
|
||||
mtc1 f1, t6 ;; 1.0
|
||||
|
||||
qmfc2.i s1, vf10
|
||||
mtc1 f12, s1
|
||||
dsra32 s2, s1, 0
|
||||
mtc1 f13, s2
|
||||
pextuw s2, r0, s2
|
||||
mtc1 f14, s2
|
||||
mula.s f12, f12
|
||||
madda.s f13, f13
|
||||
madd.s f15, f14, f14
|
||||
rsqrt.s f15, f1, f15
|
||||
mfc1 s1, f15
|
||||
qmtc2.i vf14, s1
|
||||
vmulx.xyz vf16, vf10, vf14
|
||||
```
|
||||
@@ -0,0 +1,513 @@
|
||||
```
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; .function setup-blerc-chains-for-one-fragment
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(setup-blerc-chains-for-one-fragment
|
||||
a0: num-targets
|
||||
a1: blend-shape-coeffs (s16 array)
|
||||
a2: dma-mem-ptr
|
||||
a3: blend-data
|
||||
t0: blend-ctrl
|
||||
t1: geo-data)
|
||||
|
||||
B0:
|
||||
L9:
|
||||
daddiu sp, sp, -128
|
||||
sd ra, 0(sp)
|
||||
sq s0, 16(sp)
|
||||
sq s1, 32(sp)
|
||||
sq s2, 48(sp)
|
||||
sq s3, 64(sp)
|
||||
sq s4, 80(sp)
|
||||
sq s5, 96(sp)
|
||||
sq gp, 112(sp)
|
||||
lb v1, 0(t0) ;; v1 = blend-vtx-count
|
||||
addiu t2, r0, 0 ;; t2 = 0
|
||||
por t7, r0, r0 ;; t7 = 0
|
||||
lw t3, *blerc-globals*(s7) ;; t3 = *blerc-globals*
|
||||
lw t3, 4(t3) ;; t3 = blec-globals.next
|
||||
or t4, v1, r0 ;; t4 = blend-vtx-count.
|
||||
;; link
|
||||
B1:
|
||||
L10:
|
||||
lui t7, 4096
|
||||
sll r0, r0, 0
|
||||
daddiu t7, t7, 1
|
||||
sll r0, r0, 0
|
||||
beq t3, r0, L11
|
||||
sq t7, 0(a2)
|
||||
|
||||
B2:
|
||||
sw a2, 12(t3)
|
||||
sll r0, r0, 0
|
||||
B3:
|
||||
L11:
|
||||
or t3, a2, r0
|
||||
daddu t6, t4, t4
|
||||
daddu t5, v1, v1
|
||||
daddu t6, t6, t4
|
||||
daddu t7, t5, v1
|
||||
daddu t5, t6, t6
|
||||
daddu t6, t7, t7
|
||||
daddu t7, t5, t5
|
||||
daddiu t6, t6, 15
|
||||
daddiu t5, t5, 15
|
||||
andi t6, t6, 65520
|
||||
dsrl t5, t5, 4
|
||||
daddu t8, t2, t2
|
||||
daddiu t7, t7, 15
|
||||
daddu t9, t8, t2
|
||||
dsrl t8, t7, 4
|
||||
daddu ra, t9, t9
|
||||
addiu t9, r0, 0
|
||||
daddu t7, ra, ra
|
||||
daddiu s3, a2, 32
|
||||
daddu s2, ra, a3
|
||||
daddu ra, t7, t1
|
||||
lui t7, 12288
|
||||
daddiu gp, a0, -1
|
||||
daddu t7, t7, t5
|
||||
or s5, a1, r0
|
||||
sq t7, 0(s3)
|
||||
daddiu s4, t0, 2
|
||||
sw s2, 4(s3)
|
||||
daddu s2, s2, t6
|
||||
daddiu s3, s3, 16
|
||||
sll r0, r0, 0
|
||||
B4:
|
||||
L12:
|
||||
lb s1, 0(s4)
|
||||
daddiu s4, s4, 1
|
||||
lh s0, 0(s5)
|
||||
daddiu s5, s5, 2
|
||||
beq s1, r0, L13
|
||||
sq t7, 0(s3)
|
||||
|
||||
B5:
|
||||
sw s2, 4(s3)
|
||||
daddu s2, s2, t6
|
||||
beq s0, r0, L13
|
||||
sw s0, 12(s3)
|
||||
|
||||
B6:
|
||||
daddiu s3, s3, 16
|
||||
daddiu t9, t9, 1
|
||||
B7:
|
||||
L13:
|
||||
bne gp, r0, L12
|
||||
daddiu gp, gp, -1
|
||||
|
||||
B8:
|
||||
sq t7, 0(s3)
|
||||
por t6, r0, r0
|
||||
sw ra, 4(s3)
|
||||
lui t6, 28672
|
||||
sb t8, 0(s3)
|
||||
sll r0, r0, 0
|
||||
sq t6, 16(s3)
|
||||
daddiu t6, s3, 32
|
||||
sw t9, 20(a2)
|
||||
sll r0, r0, 0
|
||||
sw t4, 16(a2)
|
||||
sll r0, r0, 0
|
||||
sw ra, 24(a2)
|
||||
sll r0, r0, 0
|
||||
sw t8, 28(a2)
|
||||
sll r0, r0, 0
|
||||
bne t4, v1, L14
|
||||
daddiu t5, t5, 1
|
||||
|
||||
B9:
|
||||
daddiu t7, t9, 3
|
||||
multu3 t5, t5, t7
|
||||
daddiu t5, t5, -457
|
||||
sll r0, r0, 0
|
||||
blez t5, L14
|
||||
sll r0, r0, 0
|
||||
|
||||
B10:
|
||||
beq r0, r0, L10
|
||||
addiu t4, r0, 24
|
||||
|
||||
B11:
|
||||
L14:
|
||||
or a2, t6, r0
|
||||
daddu t2, t2, t4
|
||||
beq t2, v1, L15
|
||||
daddu t5, t2, t4
|
||||
|
||||
B12:
|
||||
dsubu t5, t5, v1
|
||||
sll r0, r0, 0
|
||||
blez t5, L10
|
||||
sll r0, r0, 0
|
||||
|
||||
B13:
|
||||
beq r0, r0, L10
|
||||
dsubu t4, v1, t2
|
||||
|
||||
B14:
|
||||
L15:
|
||||
lw v1, *blerc-globals*(s7)
|
||||
sw t3, 4(v1)
|
||||
or v0, a2, r0
|
||||
ld ra, 0(sp)
|
||||
lq gp, 112(sp)
|
||||
lq s5, 96(sp)
|
||||
lq s4, 80(sp)
|
||||
lq s3, 64(sp)
|
||||
lq s2, 48(sp)
|
||||
lq s1, 32(sp)
|
||||
lq s0, 16(sp)
|
||||
jr ra
|
||||
daddiu sp, sp, 128
|
||||
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; .function blerc-execute
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;BAD PROLOGUE
|
||||
;; Warnings:
|
||||
;; INFO: Flagged as mips2c by config
|
||||
;; INFO: Assembly Function
|
||||
|
||||
B0:
|
||||
L37:
|
||||
daddiu sp, sp, -96
|
||||
sd ra, 0(sp)
|
||||
sq s2, 16(sp)
|
||||
sq s3, 32(sp)
|
||||
sq s4, 48(sp)
|
||||
sq s5, 64(sp)
|
||||
sq gp, 80(sp)
|
||||
lw v1, *blerc-globals*(s7)
|
||||
lwu s5, 0(v1)
|
||||
beq s5, r0, L56
|
||||
or v1, s7, r0
|
||||
|
||||
B1:
|
||||
addiu v1, r0, 0
|
||||
addiu gp, r0, 0
|
||||
addiu v1, r0, 0
|
||||
lw v1, *gsf-buffer*(s7)
|
||||
lw t9, flush-cache(s7)
|
||||
addiu a0, r0, 0
|
||||
jalr ra, t9
|
||||
sll v0, ra, 0
|
||||
|
||||
addiu v1, r0, 848
|
||||
lui a0, 28672
|
||||
daddu a1, v1, a0
|
||||
lw v1, *blerc-globals*(s7)
|
||||
daddu v1, r0, v1
|
||||
sll r0, r0, 0
|
||||
lui a0, 4096
|
||||
sll r0, r0, 0
|
||||
ori a0, a0, 54272
|
||||
andi a1, a1, 16383
|
||||
B2:
|
||||
L38:
|
||||
lw a2, 0(a0)
|
||||
sll r0, r0, 0
|
||||
sll r0, r0, 0
|
||||
sll r0, r0, 0
|
||||
andi a2, a2, 256
|
||||
sll r0, r0, 0
|
||||
bne a2, r0, L38
|
||||
lw a2, 0(v1)
|
||||
|
||||
B3:
|
||||
beq a2, r0, L39
|
||||
sw a1, 128(a0)
|
||||
|
||||
B4:
|
||||
addiu v1, r0, 324
|
||||
sw a2, 48(a0)
|
||||
sw r0, 32(a0)
|
||||
sync.l
|
||||
sw v1, 0(a0)
|
||||
sync.l
|
||||
B5:
|
||||
L39:
|
||||
or v1, r0, r0
|
||||
beq r0, r0, L55
|
||||
sll r0, r0, 0
|
||||
|
||||
B6:
|
||||
L40:
|
||||
bne gp, r0, L41
|
||||
sll r0, r0, 0
|
||||
|
||||
B7:
|
||||
lui v1, 28672
|
||||
daddu a0, r0, v1
|
||||
beq r0, r0, L42
|
||||
sll r0, r0, 0
|
||||
|
||||
B8:
|
||||
L41:
|
||||
addiu v1, r0, 8192
|
||||
lui a0, 28672
|
||||
daddu a0, v1, a0
|
||||
B9:
|
||||
L42:
|
||||
bne gp, r0, L43
|
||||
sll r0, r0, 0
|
||||
|
||||
B10:
|
||||
addiu v1, r0, 8192
|
||||
lui a1, 28672
|
||||
daddu a1, v1, a1
|
||||
beq r0, r0, L44
|
||||
sll r0, r0, 0
|
||||
|
||||
B11:
|
||||
L43:
|
||||
lui v1, 28672
|
||||
daddu a1, r0, v1
|
||||
B12:
|
||||
L44:
|
||||
daddiu v1, a0, 848
|
||||
daddu a2, r0, a0
|
||||
daddiu a3, a1, 848
|
||||
daddiu a1, v1, 12
|
||||
sll r0, r0, 0
|
||||
lui a2, 4096
|
||||
sll r0, r0, 0
|
||||
ori a2, a2, 54272
|
||||
andi a3, a3, 16383
|
||||
B13:
|
||||
L45:
|
||||
lw t0, 0(a2)
|
||||
sll r0, r0, 0
|
||||
sll r0, r0, 0
|
||||
sll r0, r0, 0
|
||||
andi t0, t0, 256
|
||||
sll r0, r0, 0
|
||||
bne t0, r0, L45
|
||||
lw t0, 0(a1)
|
||||
|
||||
B14:
|
||||
beq t0, r0, L46
|
||||
sw a3, 128(a2)
|
||||
|
||||
B15:
|
||||
addiu a1, r0, 324
|
||||
sw t0, 48(a2)
|
||||
sw r0, 32(a2)
|
||||
sync.l
|
||||
sw a1, 0(a2)
|
||||
sync.l
|
||||
B16:
|
||||
L46:
|
||||
;; blend ctrl
|
||||
;; blend data
|
||||
;; coeffs.
|
||||
;;
|
||||
or a1, r0, r0
|
||||
or a2, a0, r0 ;; likely the blerc-block.
|
||||
lw a3, *gsf-buffer*(s7)
|
||||
daddiu t2, a2, 880 ;; t2 is whatever's after blerc-block
|
||||
lb t1, 0(t2) ;; size of whatever's after
|
||||
sll r0, r0, 0
|
||||
or t0, a2, r0 ;; t0 is the blerc block
|
||||
lw a1, 868(a2) ;; a1 = block.header.overlap
|
||||
daddiu t3, t1, 1 ;; some counts??
|
||||
or t1, a3, r0 ;; t1 = ee buffer.
|
||||
sll t8, t3, 4 ;; t8 = some count (stride)
|
||||
sll t3, a1, 4 ;; t3 = overlap * 16
|
||||
daddu t9, t3, a3 ;; t9 = &buffer[overlap] (qws)
|
||||
daddu t3, t2, t8 ;; t3 = &dummy[unk_count + 1] (qws)
|
||||
beq a1, r0, L49
|
||||
daddiu ra, t2, 16 ;; ra = after block ptr (+1 qw to skip a header I guess)
|
||||
|
||||
;; this block expands "overlap"s to
|
||||
B17:
|
||||
lh t5, 12(t3)
|
||||
daddu t2, t3, t8
|
||||
beq r0, r0, L48
|
||||
sll r0, r0, 0
|
||||
|
||||
B18:
|
||||
L47:
|
||||
lh t5, 12(t2)
|
||||
daddu t2, t2, t8
|
||||
sq t6, 0(t1)
|
||||
daddiu t1, t1, 16
|
||||
B19:
|
||||
L48:
|
||||
pcpyh t5, t5
|
||||
mfc1 r0, f31
|
||||
bne t1, t9, L47
|
||||
pcpyld t6, t5, t5
|
||||
|
||||
B20:
|
||||
dsubu t3, t2, t8
|
||||
sll r0, r0, 0
|
||||
B21:
|
||||
L49:
|
||||
addiu t1, r0, 255 ;; cs
|
||||
addiu t2, r0, 8192 ;; cs
|
||||
lb s5, 0(t3)
|
||||
daddiu s4, t3, 16
|
||||
pcpyh t1, t1
|
||||
mfc1 r0, f31
|
||||
pcpyld t1, t1, t1
|
||||
mfc1 r0, f31
|
||||
pcpyh t2, t2
|
||||
mfc1 r0, f31
|
||||
pcpyld t2, t2, t2 ;; t2 = 8192's
|
||||
mfc1 r0, f31
|
||||
por t3, t1, r0 ;; t3 = 255's
|
||||
mfc1 r0, f31
|
||||
por t4, r0, r0
|
||||
mfc1 r0, f31
|
||||
B22:
|
||||
L50:
|
||||
ld t6, 0(ra)
|
||||
daddu s2, ra, t8
|
||||
daddiu ra, ra, 8
|
||||
or s3, a3, r0
|
||||
pextlb t6, r0, t6
|
||||
mfc1 r0, f31
|
||||
pmulth t7, t6, t2
|
||||
ld t5, 0(s2)
|
||||
daddiu s5, s5, -1
|
||||
sll r0, r0, 0
|
||||
beq r0, r0, L52
|
||||
daddu s2, s2, t8
|
||||
|
||||
B23:
|
||||
L51:
|
||||
pmaddh t7, t5, t6
|
||||
ld t5, 0(s2)
|
||||
daddu s2, s2, t8
|
||||
daddiu s3, s3, 16
|
||||
B24:
|
||||
L52:
|
||||
lq t6, 0(s3)
|
||||
pextlb t5, t5, r0
|
||||
bne s3, t9, L51
|
||||
psrah t5, t5, 8
|
||||
|
||||
B25:
|
||||
pmfhl.uw t5
|
||||
mfc1 r0, f31
|
||||
psraw t7, t7, 13
|
||||
mfc1 r0, f31
|
||||
psraw t5, t5, 13
|
||||
mfc1 r0, f31
|
||||
pinteh t5, t5, t7
|
||||
mfc1 r0, f31
|
||||
pminh t3, t3, t5
|
||||
mfc1 r0, f31
|
||||
pmaxh t4, t4, t5
|
||||
mfc1 r0, f31
|
||||
pminh t5, t5, t1
|
||||
mfc1 r0, f31
|
||||
pmaxh t5, t5, r0
|
||||
lq t7, 0(s4)
|
||||
ppacb t5, r0, t5
|
||||
mfc1 r0, f31
|
||||
ppach t7, r0, t7
|
||||
mfc1 r0, f31
|
||||
pextlh t5, t5, t7
|
||||
mfc1 r0, f31
|
||||
sq t5, 0(t0)
|
||||
daddiu t0, t0, 16
|
||||
bne s5, r0, L50
|
||||
daddiu s4, s4, 16
|
||||
|
||||
B26:
|
||||
lw a3, *stats-blerc*(s7)
|
||||
beq a3, s7, L53
|
||||
lw a3, *blerc-globals*(s7)
|
||||
|
||||
B27:
|
||||
lw t2, 12(a3)
|
||||
lw t1, 16(a3)
|
||||
lw t0, 20(a3)
|
||||
lw a2, 864(a2)
|
||||
multu3 a1, a1, a2
|
||||
daddiu t2, t2, 1
|
||||
daddu a2, t1, a2
|
||||
daddu a1, t0, a1
|
||||
sw t2, 12(a3)
|
||||
sw a2, 16(a3)
|
||||
sw a1, 20(a3)
|
||||
pcpyud a1, t3, r0
|
||||
pminh t3, t3, a1
|
||||
dsrl32 a1, t3, 0
|
||||
pminh t3, t3, a1
|
||||
dsrl t3, t3, 16
|
||||
lh a1, 8(a3)
|
||||
pminh t3, t3, a1
|
||||
sh t3, 8(a3)
|
||||
pcpyud a1, t4, r0
|
||||
pmaxh t4, t4, a1
|
||||
dsrl32 a1, t4, 0
|
||||
pmaxh t4, t4, a1
|
||||
dsrl t4, t4, 16
|
||||
lh a1, 10(a3)
|
||||
pmaxh t4, t4, a1
|
||||
sh t4, 10(a3)
|
||||
B28:
|
||||
L53:
|
||||
or a1, r0, r0
|
||||
lwu a1, 872(a0)
|
||||
or a3, a0, r0
|
||||
lwu a0, 876(a0)
|
||||
lui a2, 4096
|
||||
sll r0, r0, 0
|
||||
ori a2, a2, 53248
|
||||
andi a3, a3, 16383
|
||||
B29:
|
||||
L54:
|
||||
lw t0, 0(a2)
|
||||
sll r0, r0, 0
|
||||
sll r0, r0, 0
|
||||
sll r0, r0, 0
|
||||
andi t0, t0, 256
|
||||
sll r0, r0, 0
|
||||
bne t0, r0, L54
|
||||
sll r0, r0, 0
|
||||
|
||||
B30:
|
||||
sw a3, 128(a2)
|
||||
addiu a3, r0, 256
|
||||
sw a1, 16(a2)
|
||||
sll r0, r0, 0
|
||||
sw a0, 32(a2)
|
||||
sync.l
|
||||
sw a3, 0(a2)
|
||||
sync.l
|
||||
or a0, r0, r0
|
||||
addiu a0, r0, 1
|
||||
dsubu gp, a0, gp
|
||||
lwu s5, 12(v1)
|
||||
or v1, s5, r0
|
||||
B31:
|
||||
L55:
|
||||
bne s5, r0, L40
|
||||
sll r0, r0, 0
|
||||
|
||||
B32:
|
||||
or v1, s7, r0
|
||||
B33:
|
||||
L56:
|
||||
or v0, r0, r0
|
||||
ld ra, 0(sp)
|
||||
lq gp, 80(sp)
|
||||
lq s5, 64(sp)
|
||||
lq s4, 48(sp)
|
||||
lq s3, 32(sp)
|
||||
lq s2, 16(sp)
|
||||
jr ra
|
||||
daddiu sp, sp, 96
|
||||
|
||||
sll r0, r0, 0
|
||||
sll r0, r0, 0
|
||||
sll r0, r0, 0
|
||||
```
|
||||
@@ -0,0 +1,261 @@
|
||||
# Generic
|
||||
What do we expect to fix by adding generic?
|
||||
|
||||
- "warp" effect (distortion effect that samples the framebuffer)
|
||||
- "death" effect (get transformed vertices in world for spawning death effect particles)
|
||||
- "ripple query" feature (get transformed vertices in world, kinda like depth)
|
||||
- "hud drawing" for the orb/metal head gem
|
||||
|
||||
# Part 1: redirecting stuff to generic
|
||||
Right now, we send everything to PC merc all the time, completely ignoring the original decision. I added code to redirect stuff back to generic when any of the above features are used. I noticed that warp stuff often contained two merc "effects" (really just chunks of frags drawn with the same renderer). One has `warp`, and the other has `force-mercneric`. So I redirected both of these to mercneric for now, though it's possible that the `force-mercneric` one can work with PC merc. (doesn't seem like a big deal either way...).
|
||||
|
||||
This seemed to work - lots of broken merc stuff is correclty redirected.
|
||||
|
||||
I also checked for the same sort of issue that we had with jak 1's "transparent sculptor visor". They have a trick to draw transparent stuff in a texture bucket that normally doesn't have transparency - they set `force-mercneric` and set bit `0b10` in the effect bits, which changes the blending mode for this effect. This same thing is possible in jak 2, and I added support for it as well. I couldn't find any cases where this actually mattered, but it doesn't hurt.
|
||||
|
||||
# Part 2: Generic Buffer Setup
|
||||
Like with many renderers, the bucket setup is only done if the renderer is actually used.
|
||||
This path is:
|
||||
- `swap-display` is called in `main.gc`
|
||||
- this calls `display-frame-finish`
|
||||
- this calls `generic-vu1-init-buffers`
|
||||
- this calls a function to initialize each generic bucket. For warp, it does
|
||||
```
|
||||
;; s5-0 is the usual gs-zbuf with depth writes enabled
|
||||
(generic-vu1-init-buf-special (bucket-id gmerc-warp) s5-0)
|
||||
```
|
||||
|
||||
```
|
||||
(defun generic-vu1-init-buf-special ((arg0 bucket-id) (arg1 gs-zbuf))
|
||||
"At the beginning of this bucket's chain, insert DMA data for fx-copy-buf and initializing generic."
|
||||
(let ((s5-0 (-> *display* frames (-> *display* on-screen) bucket-group arg0)))
|
||||
(when (!= s5-0 (-> s5-0 last))
|
||||
(let* ((s4-0 (-> *display* frames (-> *display* on-screen) global-buf))
|
||||
(s3-1 (-> s4-0 base))
|
||||
)
|
||||
;; generate DMA data for copying the framebuffer
|
||||
(fx-copy-buf s4-0)
|
||||
;; generate DMA data for initializing generic VU1.
|
||||
(generic-init-buf s4-0 arg1)
|
||||
|
||||
(let ((v1-12 (the-as dma-packet (-> s4-0 base))))
|
||||
(set! (-> v1-12 dma) (new 'static 'dma-tag :id (dma-tag-id next) :addr (-> s5-0 next)))
|
||||
(set! (-> v1-12 vif0) (new 'static 'vif-tag))
|
||||
(set! (-> v1-12 vif1) (new 'static 'vif-tag))
|
||||
(set! (-> s4-0 base) (the-as pointer (&+ v1-12 16)))
|
||||
)
|
||||
(set! (-> s5-0 next) (the-as uint s3-1))
|
||||
)
|
||||
)
|
||||
)
|
||||
0
|
||||
(none)
|
||||
)
|
||||
```
|
||||
|
||||
The import part is
|
||||
```
|
||||
;; generate DMA data for copying the framebuffer
|
||||
(fx-copy-buf s4-0)
|
||||
;; generate DMA data for initializing generic VU1.
|
||||
(generic-init-buf s4-0 arg1)
|
||||
```
|
||||
The `fx-copy-buf` function needs to be decompiled. There's nothing too interesting, other than it copies the screen in chunks, rather than one giant sprite. The offsets and stuff are a bit confusing, but we might be able to guess our way through it.
|
||||
|
||||
For now, I'm going to leave out this function, and we'll just remember to do the copy on the C++ at the start of this bucket.
|
||||
|
||||
# Part 3: Submitting merc models to generic
|
||||
In part 1, we set things up so the main `foreground-draw` functions sends models to `foreground-generic-merc`, which isn't decompiled yet. If this works like Jak 1, this doesn't actually do the EE side of generic yet - it just adds them to a list.
|
||||
|
||||
The next step was to mips2c/decompile `foreground-generic-merc` and the functions it calls. Unfortunately, the main function can't easily be decompiled. I suspect it's very similar to `draw-bones-generic-merc` where it fills out generic parameters based on settings. The death vertex and fragment adding loop are split into separate functions that we can decompile this time:
|
||||
|
||||
```
|
||||
(defun foreground-generic-merc-death ((arg0 draw-control) (arg1 generic-merc-ctrl))
|
||||
"Modify a generic-merc-ctrl to set up merc-death effect."
|
||||
|
||||
;; possibly disable drawing if requested
|
||||
(when (and (>= (the-as int (- (-> arg0 death-timer-org) (-> arg0 death-timer)))
|
||||
(the-as int (-> arg0 death-draw-overlap))
|
||||
)
|
||||
(!= (-> arg0 death-draw-overlap) 255)
|
||||
)
|
||||
(set! (-> arg1 header display-triangles) (the-as uint 0))
|
||||
0
|
||||
)
|
||||
|
||||
;; update the vertices that we're querying.
|
||||
(when (not (paused?))
|
||||
(let ((v1-6 (+ (-> arg0 death-vertex-skip) (rand-vu-int-count (the-as int (-> arg0 death-vertex-skip))))))
|
||||
(set! (-> arg1 header death-vertex-skip) v1-6)
|
||||
(set! (-> arg1 header death-effect) (-> arg0 death-effect))
|
||||
(set! (-> arg1 header death-start-vertex)
|
||||
(/ (* v1-6 (- (-> arg0 death-timer-org) (-> arg0 death-timer))) (-> arg0 death-timer-org))
|
||||
)
|
||||
)
|
||||
)
|
||||
(none)
|
||||
)
|
||||
|
||||
(defun foreground-generic-merc-add-fragments ((arg0 merc-effect) (arg1 pointer) (arg2 mercneric-chain))
|
||||
"Add fragments from a merc-effect to the generic chain."
|
||||
(let ((v1-0 (-> arg0 frag-geo))
|
||||
(a3-0 (the-as structure (-> arg0 frag-ctrl)))
|
||||
(a0-1 (-> arg0 frag-count))
|
||||
)
|
||||
|
||||
;; loop over fragments, adding matrix refs.
|
||||
(dotimes (t0-0 (the-as int a0-1))
|
||||
(let ((t1-2 (+ (* (-> (the-as merc-fragment-control a3-0) mat-xfer-count) 2) 4))
|
||||
(t2-0 (-> v1-0 header mm-quadword-size))
|
||||
)
|
||||
(set! (-> (the-as dma-packet arg1) dma)
|
||||
(new 'static 'dma-tag :id (dma-tag-id ref) :addr (the-as int v1-0) :qwc t2-0)
|
||||
)
|
||||
(set! (-> (the-as dma-packet arg1) vif0) (new 'static 'vif-tag))
|
||||
(set! (-> (the-as dma-packet arg1) vif1) (new 'static 'vif-tag))
|
||||
(when (nonzero? t0-0)
|
||||
(set! (-> (the-as (pointer int32) (-> arg2 next)) 0) (the-as int arg1))
|
||||
(set! (-> arg2 next) (the-as uint (&+ arg1 12)))
|
||||
)
|
||||
(let ((a1-1 (the-as object (&+ arg1 16))))
|
||||
(dotimes (t3-6 (the-as int (-> (the-as merc-fragment-control a3-0) mat-xfer-count)))
|
||||
(let ((t5-4
|
||||
(-> (scratchpad-object foreground-work)
|
||||
regs
|
||||
mtxs
|
||||
(-> (the-as merc-fragment-control a3-0) mat-dest-data t3-6 matrix-number)
|
||||
)
|
||||
)
|
||||
)
|
||||
(set! (-> (the-as dma-packet a1-1) dma)
|
||||
(new 'static 'dma-tag :qwc #x7 :id (dma-tag-id ref) :addr (the-as int t5-4))
|
||||
)
|
||||
)
|
||||
(set! (-> (the-as dma-packet a1-1) vif0) (new 'static 'vif-tag))
|
||||
(set! (-> (the-as dma-packet a1-1) vif1) (new 'static 'vif-tag))
|
||||
(set! a1-1 (&+ (the-as pointer a1-1) 16))
|
||||
)
|
||||
(set! (-> (the-as dma-packet a1-1) dma) (new 'static 'dma-tag :id (dma-tag-id end)))
|
||||
(set! (-> (the-as dma-packet a1-1) vif0) (new 'static 'vif-tag))
|
||||
(set! (-> (the-as dma-packet a1-1) vif1) (new 'static 'vif-tag))
|
||||
(set! arg1 (&+ (the-as pointer a1-1) 16))
|
||||
)
|
||||
(set! a3-0 (&+ a3-0 t1-2))
|
||||
(set! v1-0 (the-as merc-fragment (+ (the-as uint v1-0) (* t2-0 16))))
|
||||
)
|
||||
)
|
||||
)
|
||||
arg1
|
||||
)
|
||||
```
|
||||
It's overall very similar, but the way of finding the matrices is little different, but it all makes sense. The generic chain will be processed later, and it will dma these matrices to the scratchpad for transforming generic merc data.
|
||||
|
||||
# Part 4: Running Generic Merc EE processing
|
||||
Part 3 just adds fragments to a list. We actually have to process these fragments on the EE before drawing them with VU1. Assuming it's like Jak 1, the EE step transforms vertices to world frame and computes stuff like envmap coordinates. The VU1 part does the perspective tranformation and clipping.
|
||||
|
||||
This is run from `generic-merc-execute-all`, called from `drawable.gc`.
|
||||
|
||||
```
|
||||
(defun generic-merc-execute-all ((arg0 dma-buffer))
|
||||
"Run EE processing on all generic merc chains."
|
||||
(let ((s4-0 (-> *foreground* foreground-grid))
|
||||
(gp-0 (-> *display* frames (-> *display* on-screen) global-buf base))
|
||||
)
|
||||
|
||||
(with-profiler 'generic-merc *profile-generic-merc-color*
|
||||
;; reset profiling
|
||||
(reset! (-> *perf-stats* data (perf-stat-bucket mercneric)))
|
||||
(set! (-> (scratchpad-object generic-work) saves to-vu0-waits) (the-as uint 0))
|
||||
(set! (-> (scratchpad-object generic-work) saves to-spr-waits) (the-as uint 0))
|
||||
(set! (-> (scratchpad-object generic-work) saves from-spr-waits) (the-as uint 0))
|
||||
(flush-cache 0)
|
||||
|
||||
;; init generic
|
||||
(generic-initialize-without-sync (-> *math-camera* perspective) *default-lights*)
|
||||
(generic-merc-init-asm)
|
||||
(set! (-> (scratchpad-object generic-work) in-buf merc shadow write-limit) (the-as int (&+ (-> arg0 end) -262144)))
|
||||
|
||||
;; loop over grid of chains (levels x textures) and do the chain.
|
||||
(dotimes (s3-1 7)
|
||||
(dotimes (s2-1 7)
|
||||
(generic-merc-do-chain (-> s4-0 level-buckets s3-1 data s2-1 mercneric) arg0)
|
||||
)
|
||||
)
|
||||
|
||||
;; do separate warp chain
|
||||
(generic-merc-do-chain (-> s4-0 warp-chain) arg0)
|
||||
|
||||
;; finish profiling
|
||||
(read! (-> *perf-stats* data (perf-stat-bucket mercneric)))
|
||||
(update-wait-stats
|
||||
(-> *perf-stats* data 38)
|
||||
(-> (scratchpad-object generic-work) saves to-vu0-waits)
|
||||
(-> (scratchpad-object generic-work) saves to-spr-waits)
|
||||
(-> (scratchpad-object generic-work) saves from-spr-waits)
|
||||
)
|
||||
)
|
||||
|
||||
;; update dma memory usage stats.
|
||||
(let ((v1-66 *dma-mem-usage*))
|
||||
(when (nonzero? v1-66)
|
||||
(set! (-> v1-66 length) (max 90 (-> v1-66 length)))
|
||||
(set! (-> v1-66 data 89 name) "pris-generic")
|
||||
(+! (-> v1-66 data 89 count) 1)
|
||||
(+! (-> v1-66 data 89 used)
|
||||
(&- (-> *display* frames (-> *display* on-screen) global-buf base) (the-as uint gp-0))
|
||||
)
|
||||
(set! (-> v1-66 data 89 total) (-> v1-66 data 89 used))
|
||||
)
|
||||
)
|
||||
)
|
||||
(none)
|
||||
)
|
||||
```
|
||||
|
||||
This function doesn't look too bad...
|
||||
|
||||
|
||||
|
||||
# Part 5: Decompiling `generic-merc` stuff
|
||||
|
||||
- `generic-merc-init-asm`
|
||||
Nothing interesting, dma sync patched out.
|
||||
|
||||
- `mercneric-convert`
|
||||
The worst function. Copied all the vu0 stuff from jak 1.
|
||||
|
||||
- `high-speed-reject`
|
||||
Copied vu0 stuff from jak1
|
||||
|
||||
- `generic-translucent`
|
||||
New for jak 2, easy.
|
||||
|
||||
- `generic-merc-query`
|
||||
New for jak 2, easy. (maybe no mips2c?)
|
||||
|
||||
- `generic-merc-death`
|
||||
New for jak 2, easy. (maybe no mips2c?)
|
||||
|
||||
- `generic-merc-execute-asm`
|
||||
Did the same direct-call patch for the `mercneric-convert` call. Not sure why I did this originally, but it can only help.
|
||||
|
||||
- `generic-merc-do-chain`
|
||||
New for jak 2, easy (patched out dma sync).
|
||||
|
||||
|
||||
|
||||
|
||||
# Part 6: Decompiling `generic-effect` stuff
|
||||
- `generic-work-init`
|
||||
Not mips2c. Just copies stuff to generic-work.
|
||||
|
||||
- `generic-light-proc`
|
||||
|
||||
- `generic-warp-source`
|
||||
- `generic-warp-envmap-dest`
|
||||
- `generic-warp-dest`
|
||||
- `generic-prepare-dma-single` (`generic-effect`)
|
||||
- `generic-prepare-dma-double` (`generic-effect`)
|
||||
|
||||
- `generic-envmap-proc`
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
# Shrub EE code notes
|
||||
|
||||
## Looking through village1-vis.asm
|
||||
The "prototype" main class is `prototype-bucket-shrub`. These are stored in a `prototype-inline-array-shrub`.
|
||||
|
||||
Example of a `prototype-bucket-shrub`:
|
||||
```
|
||||
.type prototype-bucket-shrub
|
||||
.word L22404
|
||||
.word 0x0
|
||||
.word 0x20025
|
||||
.word L4630
|
||||
.word L4604
|
||||
.word L4617
|
||||
.word L4641
|
||||
.word 0x48a00000
|
||||
.word 0x48200000
|
||||
```
|
||||
|
||||
The `.word L22404` is a string `"palmplant-top.mb"`.
|
||||
The four `L4630`, `L4604`, `L4617`, `L4641` are the 4 `geometry`. In this case, it looks like each is a different kind, but I don't think we can make any assumptions about this.
|
||||
|
||||
### Highest Detail `prototype-generic-shrub`
|
||||
For now, let's ignore this because we don't have a generic renderer. It also really looks like no shrubs ever draw with generic in-game, but I could be wrong. It looks like every single shrub has this as their first geomery.
|
||||
|
||||
### 2nd Highest `prototype-shrubbery`
|
||||
I think this is the "normal" shrub. Each prototype is made up of one or more `shrubbery`. Again, every shrub has this.
|
||||
|
||||
### 3rd Highest `prototype-trans-shrubbery`
|
||||
Based on PCSX2, it looks like these are usually lower-res models that fade out as you move away. Like the 2nd, they are made of `shrubbery`, and every shrub has one.
|
||||
|
||||
### 4th Highest `billboard`
|
||||
These are the lowest res, always face toward the camera. Each `billboard` is just a single thing - no sub-parts. I suspect that each prototype can become a single rectangle "billboard", no matter how complicated the original shrub is.
|
||||
|
||||
I think we should work on `prototype-shrubbery` (and possibly the transparent one) first. Maybe we can leave out the billboard and claim that we're "increasing the level of detail" :).
|
||||
|
||||
## Looking through `shrubbery.gc` decomp
|
||||
Doing reverse order in the `ir2.asm` file.
|
||||
|
||||
### `login billboard`
|
||||
No surprise here, billboard is a single rectangle, it can have only one texture, and there's exactly one `adgif-shader-login`.
|
||||
|
||||
### `mem-usage-shrub-walk`
|
||||
This function recursively iterates over a `draw-node` tree, computing memory usage, and is a good example of how these `draw-node` trees work. Each `draw-node` has a sphere. Inside this sphere are between 1 and 8 "children", which are in an `inline-array`. The children are usually `draw-node`, except for the leaf nodes, which are some other drawable type. In this case, they are `instance-shrubbery`. This is used for frustum culling. If a `draw-node` sphere is outside of the view of the camera, you can just skip all instances in that `draw-node`.
|
||||
|
||||
Unlike a normal tree, they rarely refer to a single `draw-node`, but instead a group of between 1 and 8 draw-nodes. These are passed around as a `draw-node` (the first in the group) and an integer (the number in the group). This might seem weird, but simplifies the iteration logic. (if you don't know the type/size of the leaf node, you can't iterate over an inline-array of them, but you could call some virtual function that expects the object to be the first one in an `inline-array` with a size argument.)
|
||||
|
||||
This is how to recursively iterate over `draw-node` tree:
|
||||
```lisp
|
||||
(dotimes (s1-0 arg1)
|
||||
(let ((a1-2 (-> s2-0 child-count)))
|
||||
(cond
|
||||
((logtest? (-> s2-0 flags) 1) ;; flag means that we aren't a leaf.
|
||||
(mem-usage-shrub-walk (the-as draw-node (-> s2-0 child)) (the-as int a1-2) arg2 arg3)
|
||||
)
|
||||
(else
|
||||
;; you are at an inline-array of leaves.
|
||||
;; (-> s2-0 child) is an inline-array of a1-2 leaves
|
||||
;; a1-2 is between 1 and 8.
|
||||
)
|
||||
)
|
||||
)
|
||||
;; move on to the next child draw node.
|
||||
(&+! s2-0 32)
|
||||
)
|
||||
```
|
||||
|
||||
NOTE: `arg1` should be an int here.
|
||||
|
||||
We learned here that `shrub` does use the `draw-node` BVH system. (this was unclear because `shrub` does not appear to use the compressed visibility string based vis system, which is often used simultaneously with `draw-node`).
|
||||
|
||||
### `login generic-shrub-fragment`
|
||||
`generic-shrub-fragment`'s have a variable number of textures. The `cnt-qwc` field refers to the total size of the `textures` array, as each `adgif-shader` is 5 qw.
|
||||
|
||||
### `login prototype-shrubbery`
|
||||
From village1-vis, we know this is just logging in `shrubbery`s.
|
||||
|
||||
### `asize-of prototype-shrubbery`
|
||||
The size calculation makes sense for an inline-array of `shrubbery`, with 1 `shrubbery` being inside the type, and the rest running off the end of the array.
|
||||
|
||||
### `login prototype-generic-shrub`
|
||||
No surprises. Confirms that these aren't inline arrays (and we could tell from village1-vis anyway)
|
||||
|
||||
### `login shrubbery`
|
||||
Gives us some idea of the layout of the "header". The first `u32` is the number of textures / 2. Each `shrubbery` may have multiple textures.
|
||||
|
||||
### `login drawable-tree-instance-shrub`
|
||||
Nothing interesting
|
||||
|
||||
### `shrub-num-tris`
|
||||
This tells us the number of triangles in a `shrubbery` is `header[2] - 2*header[1]`. One of the most popular GS formats is "triangle strip". The number of triangles in a triangle strip is `num_verts - 2`. So, very likely `header[2]` is the total number of vertices, and `header[1]` is the number of strips
|
||||
|
||||
### `shrub-make-perspective-matrix`
|
||||
This probably makes the matrix used to transform shrubbery. I'm not sure why yet, but they take the normal transformation (`camera-temp`) and modify it a bit. We may be able to get away with ignoring this. Ideally we just get the shrub positions (in the world coordinate system, just like with TIE/TFRAG), and then use the same logic we used for TIE/TFRAG.
|
||||
|
||||
### `shrub-init-view-data`.
|
||||
Note: change `texture-giftag` in `shrub-view-data` to a `gs-gif-tag`.
|
||||
|
||||
This populates fields of a `shrub-view-data`, which will probably end up in VU memory.
|
||||
|
||||
There's two things here that are suspicious. First:
|
||||
```lisp
|
||||
(set! (-> arg0 texture-giftag tag) (new 'static 'gif-tag64 :nloop #x1 :nreg #x4))
|
||||
(set! (-> arg0 texture-giftag regs) (new 'static 'gif-tag-regs
|
||||
:regs0 (gif-reg-id a+d)
|
||||
:regs1 (gif-reg-id a+d)
|
||||
:regs2 (gif-reg-id a+d)
|
||||
:regs3 (gif-reg-id a+d)
|
||||
)
|
||||
)
|
||||
```
|
||||
usually an `adgif-shader` is 5 qw's of a+d data. This sets up 4. The fifth one is usually `gs-alpha`, and it seems reasonable that they could set this once, then not bother setting it again.
|
||||
|
||||
Second, they put `#x40a00000` in the 3rd word of the giftag:
|
||||
```
|
||||
(set! (-> arg0 texture-giftag word 3) (the-as uint #x40a00000))
|
||||
```
|
||||
as far as I can tell the GIF will ignore this. They might use it as a constant `5.0`. But it seems weird to put it here.
|
||||
|
||||
If you change the `score` so it uses the named fields, the rest of the constants are:
|
||||
```
|
||||
(set! (-> arg0 tex-start-ptr) (the-as int 25167696.0))
|
||||
(set! (-> arg0 mtx-buf-ptr) (the-as int 8388608.0))
|
||||
(set! (-> arg0 fog-0) (-> *math-camera* pfog0))
|
||||
(set! (-> arg0 fog-1) (-> *math-camera* pfog1))
|
||||
(set! (-> arg0 fog-clamp x) (-> *math-camera* fog-min))
|
||||
(set! (-> arg0 fog-clamp y) (-> *math-camera* fog-max))
|
||||
```
|
||||
the fog stuff seems reasonable to me (it's involved in computing the perspective division and the GS fog coefficient, don't worry for now).
|
||||
|
||||
The `buf-ptr` stuff is very likely this awful trick they do. The VU doesn't have good instructions for common integer operations (like you'd use to mainpulate memory addresses), so they find floating point values, then when added/subtracted in certain ways, have the lower 16 bits of the float equal to the VU memory address. Gross. Maybe the `5.0` is also part of this.
|
||||
|
||||
|
||||
### `shrub-upload-view-data`
|
||||
Note: I changed the type casts:
|
||||
```
|
||||
"shrub-upload-view-data": [
|
||||
[[3, 16], "a0", "dma-packet"]
|
||||
],
|
||||
|
||||
```
|
||||
|
||||
and got a very typical upload.
|
||||
|
||||
```
|
||||
(defun shrub-upload-view-data ((arg0 dma-buffer))
|
||||
(let ((s5-0 3))
|
||||
(let* ((v1-0 arg0)
|
||||
(a0-1 (the-as object (-> v1-0 base)))
|
||||
)
|
||||
(set! (-> (the-as dma-packet a0-1) dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc s5-0))
|
||||
(set! (-> (the-as dma-packet a0-1) vif0) (new 'static 'vif-tag :imm #x404 :cmd (vif-cmd stcycl)))
|
||||
(set! (-> (the-as dma-packet a0-1) vif1) (new 'static 'vif-tag :cmd (vif-cmd unpack-v4-32) :num s5-0))
|
||||
(set! (-> v1-0 base) (&+ (the-as pointer a0-1) 16))
|
||||
)
|
||||
(shrub-init-view-data (the-as shrub-view-data (-> arg0 base)))
|
||||
(&+! (-> arg0 base) (* s5-0 16))
|
||||
)
|
||||
#f
|
||||
)
|
||||
```
|
||||
|
||||
- `s5-0` this is the number of quadwords they will upload.
|
||||
- `dma-tag`: `cnt`, means the data will come after the tag (and the next thing comes after that). `qwc` makes sense
|
||||
- As part of a DMA tag, you get 2 VIF tags "for free". These are sent to the VIF.
|
||||
- `vif0`: the `stcycl` sets the `cl`/`wl` register of VIF to `0x404` which is the mode for just copying stuff like normal (doesn't skip data)
|
||||
- `vif1`: the `unpack` command means copy data to data memory. The `v4-32` is the mode for copying quadwords.
|
||||
|
||||
The `0x404 stcycl` and `v4-32` format is used if you just want to copy memory exactly, so it shows up a lot. The other formats can do weird unpacking stuff, but are less common.
|
||||
|
||||
|
||||
### `shrub-time`
|
||||
Not really sure what this is. I noticed in PCSX2 there's a `time:` that shows up in instance info. Maybe it computes the number of VU cycles.
|
||||
|
||||
|
||||
### `shrub-do-init-frame`
|
||||
This adds stuff to the DMA list to get the hardware ready for shrub.
|
||||
|
||||
Note:
|
||||
```
|
||||
"shrub-do-init-frame": [
|
||||
[[10, 21], "a0", "dma-packet"],
|
||||
[[24, 29], "a0", "dma-packet"],
|
||||
[33, "v1", "(pointer vif-tag)"],
|
||||
[[35, 41], "v1", "(pointer uint32)"],
|
||||
[42, "v1", "(pointer vif-tag)"],
|
||||
[[43, 51], "v1", "(pointer uint32)"],
|
||||
[52, "v1", "(pointer vif-tag)"],
|
||||
[54, "v1", "(pointer uint32)"]
|
||||
],
|
||||
```
|
||||
All the data gets sent to the VIF. You can check the VIFcode reference part of the manual to see how long the data for each vifcode is.
|
||||
|
||||
upload the shrub program. In the PC port we usually set the VU program definitions to have a size of 0, then this function will do nothing.
|
||||
```
|
||||
(dma-buffer-add-vu-function arg0 shrub-vu1-block 1)
|
||||
```
|
||||
|
||||
upload the shrub view data:
|
||||
```
|
||||
(shrub-upload-view-data arg0)
|
||||
```
|
||||
|
||||
Add a DMA tag. Note that `qwc` is zero so this one just sends the two `vif` tags that are part of the dma tag:
|
||||
```
|
||||
(set! (-> (the-as dma-packet a0-3) dma) (new 'static 'dma-tag :id (dma-tag-id cnt)))
|
||||
(set! (-> (the-as dma-packet a0-3) vif0) (new 'static 'vif-tag :cmd (vif-cmd mscalf) :msk #x1 :imm #x0))
|
||||
(set! (-> (the-as dma-packet a0-3) vif1) (new 'static 'vif-tag :cmd (vif-cmd flushe) :msk #x1))
|
||||
(set! (-> v1-0 base) (&+ (the-as pointer a0-3) 16))
|
||||
```
|
||||
The `mscalf` runs a VU1 program. The `imm` is 0, so it runs starting at the beginning of VU1 program memory. Let's ignore this for now. It's probably an initialization program that sets up the VU memory and registers. We'll look at it when we get to the actual drawing.
|
||||
|
||||
The `flushe` waits for that program to end.
|
||||
|
||||
Next it sets the `strow`/`stcol`/`stmask` registers of the VIF. These are used for unpacking settings.
|
||||
|
||||
### `shrub-init-frame`
|
||||
Calls `shrub-do-init-frame` then sets the `gs-test` register.
|
||||
|
||||
### `shrub-upload-model`
|
||||
Seems to upload a model
|
||||
```
|
||||
(function shrubbery dma-buffer int symbol)
|
||||
|
||||
and
|
||||
|
||||
|
||||
"shrub-upload-model": [
|
||||
[[17, 26], "a3", "dma-packet"],
|
||||
[[33, 41], "a0", "dma-packet"],
|
||||
[[47, 55], "a0", "dma-packet"]
|
||||
],
|
||||
```
|
||||
|
||||
The model data upload:
|
||||
```
|
||||
(set! (-> (the-as dma-packet a3-0) dma)
|
||||
(new 'static 'dma-tag
|
||||
:id (dma-tag-id ref)
|
||||
:addr (-> arg0 obj)
|
||||
:qwc (+ (-> arg0 obj-qwc) (-> arg0 vtx-qwc) (-> arg0 col-qwc) (-> arg0 stq-qwc))
|
||||
)
|
||||
)
|
||||
(set! (-> (the-as dma-packet a3-0) vif0) (new 'static 'vif-tag :cmd (vif-cmd base) :imm *shrub-state*))
|
||||
(set! (-> (the-as dma-packet a3-0) vif1) (new 'static 'vif-tag :cmd (vif-cmd offset)))
|
||||
(set! (-> v1-0 base) (&+ (the-as pointer a3-0) 16))
|
||||
)
|
||||
```
|
||||
this tells us that there is a static DMA chain, starting at the `obj` field of the `shrubbery`. This includes `obj`, `vtx`, `col`, `stq`. The fact that it's a `ref` likely means the DMA will do one big transfer of all that data, then come back to the DMA buffer we're filling.
|
||||
|
||||
The use of the `base` with `offset = 0` indicates they aren't using the normal VU double buffering (the weird float tricker earlier was also a clue). They have insane buffering schemes so you can have one model uploading, another model generating GIF tags, and a third model (no longer in VU1 memory) having its GIF tags being processed by the GS. Luckily we can mostly ignore this and just make non-buffered versions because there's no performance benefit to doing this on a PC.
|
||||
|
||||
Next, is:
|
||||
```
|
||||
(cond
|
||||
((= arg2 1)
|
||||
(let* ((v1-2 arg1)
|
||||
(a0-9 (the-as object (-> v1-2 base)))
|
||||
)
|
||||
(set! (-> (the-as dma-packet a0-9) dma) (new 'static 'dma-tag :id (dma-tag-id cnt)))
|
||||
(set! (-> (the-as dma-packet a0-9) vif0) (new 'static 'vif-tag))
|
||||
(set! (-> (the-as dma-packet a0-9) vif1) (new 'static 'vif-tag :cmd (vif-cmd mscal) :msk #x1 :imm #x11))
|
||||
(set! (-> v1-2 base) (&+ (the-as pointer a0-9) 16))
|
||||
)
|
||||
)
|
||||
(else
|
||||
(let* ((v1-3 arg1)
|
||||
(a0-11 (the-as object (-> v1-3 base)))
|
||||
)
|
||||
(set! (-> (the-as dma-packet a0-11) dma) (new 'static 'dma-tag :id (dma-tag-id cnt)))
|
||||
(set! (-> (the-as dma-packet a0-11) vif0) (new 'static 'vif-tag))
|
||||
(set! (-> (the-as dma-packet a0-11) vif1) (new 'static 'vif-tag :cmd (vif-cmd mscal) :msk #x1 :imm #x15))
|
||||
(set! (-> v1-3 base) (&+ (the-as pointer a0-11) 16))
|
||||
)
|
||||
)
|
||||
)
|
||||
```
|
||||
which adds a tag that runs a VU1 program. Either program starting at `0x11` or `0x15`, depending on the argument.
|
||||
|
||||
Then
|
||||
```
|
||||
(set! *shrub-state* (- 164 *shrub-state*))
|
||||
```
|
||||
Based on the use of `*shrub-state*`, I think it is a VU buffer management thing.
|
||||
|
||||
### `draw-inline-array-instance-shrub`
|
||||
asm. I'll come back to this later. I assume this runs _before_ the prototype draw, and that it will build lists of instances in each bucket, to be processed by the next function.
|
||||
|
||||
### `draw-prototype-inline-array-shrub`
|
||||
This one is tricky too, I'll come back later.
|
||||
|
||||
|
||||
### `draw-drawable-tree-instance-shrub`
|
||||
This is the main draw. It does:
|
||||
- setup `instance-shrub-work` (likely used in the instance asm function)
|
||||
- set the `next-clear` stuff to 0. This is just a shortcut fast way to reset lists of instances from the previous frame. Will make more sense once we see the previous two functions, I think.
|
||||
- call `draw-inline-array-instance-shrub`
|
||||
- call `draw-prototype-inline-array-shrub`
|
||||
- a whole bunch of performance counters we can skip
|
||||
|
||||
### `draw drawable-tree-instance-shrub`
|
||||
This connects the background system and the drawable/bsp system. When the draw engine executes, it calls this function, adding the drawable tree to `background-work`. When `finish-background` is called, it calls `draw-drawable-tree-instance-shrub` that does the real work
|
||||
|
||||
### `unpack-vis`
|
||||
Having this do nothing makes the shrub system not part of the occlusion culling system.
|
||||
|
||||
### `collect-stats`
|
||||
This shows that geometry 0 is `shrub-near`, geometry 1 is `shrub`, 2 is `trans-shrub`, and 3 is billboard.
|
||||
|
||||
It appears that near shrubs are drawn with the generic renderer (also looking at the prototype draw to confirm).
|
||||
|
||||
If this is the case, we can probably get away with ignoring geometry 0 and making a single shrub renderer that can handle the near case. From playing in PCSX2, "near" doesn't mean higher resolution, it just means the shrub is partially behind the camera, or close to that. If we port the rendering to opengl properly, we get this "for free".
|
||||
|
||||
|
||||
## Shrubbery Header
|
||||
|
||||
- `[0] u32` - number of textures divided by 2.
|
||||
- `[4] u32` - number of vertices to draw.
|
||||
- `[8] u32` - number of triangle strips.
|
||||
+13
-2
@@ -121,6 +121,19 @@ set(RUNTIME_SOURCE
|
||||
kernel/jak2/kprint.cpp
|
||||
kernel/jak2/kscheme.cpp
|
||||
kernel/jak2/ksound.cpp
|
||||
kernel/jak3/fileio.cpp
|
||||
kernel/jak3/kboot.cpp
|
||||
kernel/jak3/kdgo.cpp
|
||||
kernel/jak3/kdsnetm.cpp
|
||||
kernel/jak3/klink.cpp
|
||||
kernel/jak3/klisten.cpp
|
||||
kernel/jak3/kmachine.cpp
|
||||
kernel/jak3/kmalloc.cpp
|
||||
kernel/jak3/kmemcard.cpp
|
||||
kernel/jak3/kprint.cpp
|
||||
kernel/jak3/kscheme.cpp
|
||||
kernel/jak3/ksocket.cpp
|
||||
kernel/jak3/ksound.cpp
|
||||
mips2c/jak1_functions/bones.cpp
|
||||
mips2c/jak1_functions/collide_cache.cpp
|
||||
mips2c/jak1_functions/collide_edge_grab.cpp
|
||||
@@ -234,8 +247,6 @@ set(RUNTIME_SOURCE
|
||||
system/IOP_Kernel.cpp
|
||||
system/iop_thread.cpp
|
||||
system/SystemThread.cpp
|
||||
system/vm/dmac.cpp
|
||||
system/vm/vm.cpp
|
||||
tools/filter_menu/filter_menu.cpp
|
||||
tools/subtitle_editor/subtitle_editor_db.cpp
|
||||
tools/subtitle_editor/subtitle_editor_repl_client.cpp
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,4 +1,243 @@
|
||||
{
|
||||
"cutscenes": {},
|
||||
"other": {}
|
||||
"other": {
|
||||
"erol002": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 100,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
},
|
||||
{
|
||||
"frame_end": 162,
|
||||
"frame_start": 101,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
},
|
||||
{
|
||||
"frame_end": 277,
|
||||
"frame_start": 163,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
},
|
||||
{
|
||||
"frame_end": 348,
|
||||
"frame_start": 278,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
},
|
||||
{
|
||||
"frame_end": 425,
|
||||
"frame_start": 349,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
},
|
||||
{
|
||||
"frame_end": 588,
|
||||
"frame_start": 426,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
},
|
||||
{
|
||||
"frame_end": 815,
|
||||
"frame_start": 589,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "errol"
|
||||
}
|
||||
]
|
||||
},
|
||||
"jakfall": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 93,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "jak"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mtn-plat-buried-rocks-a": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 168,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mtn-step-plat-rocks-a": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 88,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mtn-step-plat-rocks-b": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 92,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mtn-step-plat-rocks-c": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 80,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sam001": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 120,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "youngsamos"
|
||||
},
|
||||
{
|
||||
"frame_end": 273,
|
||||
"frame_start": 121,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "youngsamos"
|
||||
},
|
||||
{
|
||||
"frame_end": 423,
|
||||
"frame_start": 274,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "youngsamos"
|
||||
},
|
||||
{
|
||||
"frame_end": 479,
|
||||
"frame_start": 424,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "youngsamos"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sigc001": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 140,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "sig"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sigc073": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 52,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "sig"
|
||||
},
|
||||
{
|
||||
"frame_end": 151,
|
||||
"frame_start": 53,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "sig"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tombplta": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 129,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tombpltb": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 350,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"wtrdrain": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 163,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"wtrfill": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 165,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "none"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ys002": {
|
||||
"lines": [
|
||||
{
|
||||
"frame_end": 55,
|
||||
"frame_start": 0,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "youngsamos"
|
||||
},
|
||||
{
|
||||
"frame_end": 93,
|
||||
"frame_start": 56,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "samos"
|
||||
},
|
||||
{
|
||||
"frame_end": 153,
|
||||
"frame_start": 94,
|
||||
"merge": false,
|
||||
"offscreen": true,
|
||||
"speaker": "samos"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 1302 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user