Compare commits

...
Author SHA1 Message Date
Matt Dallmeyer 1979f94e45 Rip collision based on config flag (#3348)
Added a new `rip_collision` flag to the decompiler config and wired it
up. Cleaned up the comments around these fields in the JSON too for
clarity

Also refactored a bunch of the related extract functions to read from
`config` object rather than pass down a bunch of booleans
2024-01-29 22:15:42 +01:00
water111 ba8d4c2903 [jak3] Drawable header decomp (#3347) 2024-01-28 14:23:41 -05:00
water111 bfe0a72ae7 [jak3] decompile (but not port) texture (#3346)
For now - just a plain decompilation, with no PC port changes. I think
it'll be easier to do those once we have a little bit more decompiled.
2024-01-27 16:30:18 -05:00
water111 8d0d05717f [jak3] misc. headers (#3345)
trail-h, minimap-h, bigmap-h, capture, memory-usage-h, blit-displays-h,
sky-h, rest of ocean-h
2024-01-27 14:06:21 -05:00
Ziemas 398d2ee5e1 cmake: Remove -Wmissing-include-dir (#3343)
I'm tired of it spamming and I couldn't figure out what adds to
non-existent fmt/include dir.
2024-01-27 13:10:00 -05:00
water111 5fe4d12f70 [jak3] dma-disasm, time-of-day-h, texture-anim-h, level-h (#3344) 2024-01-27 13:09:37 -05:00
water111 4bd5111280 [jak3] dma, dma-bucket, dma-buffer (#3331) 2024-01-27 11:44:08 -05:00
Hat Kid f045e6cef1 decomp3: font-h, display, profile, settings-h, camera-defs-h, text-h (#3335) 2024-01-27 11:27:34 -05:00
Hat Kid 17f5f74238 jak3: dump of all vu programs (#3340)
With the exception of `sprite` and the new `hfrag` renderer, everything
appears to be identical to Jak 2.
2024-01-27 11:38:03 +01:00
ManDude 9aa291313b fix custom screenshots and change screenshot directory (#3339) 2024-01-26 04:49:35 +00:00
OpenGOAL BotandOpenGOALBot 6f0d0fa417 CI: Periodic Controller Database Update (#3327)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-01-25 21:28:58 -05:00
Tyler Wilding 7ef2c2fac3 decomp: add a new config flag to disable var-name casts (#3338)
This is handy when you want to try comparing the decompiler's output
across games (ie. for checking if only naming differs)
2024-01-25 21:28:47 -05:00
Hat Kid 3eb6cfcb17 custom levels: add support for symbol, type, and string lumps (#3337) 2024-01-25 23:20:32 +01:00
Tyler Wilding 0236e36a53 formatter: fix multi-line form consolidation (#3336) 2024-01-25 16:46:15 -05:00
Hat Kid 0ea718a5ee decomp3: loader-h, capture-h, math-camera-h, math-camera, connect, gs, texture-h (#3333) 2024-01-25 15:44:26 +01:00
Hat Kid 3a2c57c091 decomp3: timer, display-h, decomp-h, file-io, pad (#3332) 2024-01-23 23:52:15 -05:00
water111 b130c2f439 [jak3] A few early files (#3330)
types-h, vu1-macros, gsound-h, dma-h, video-h, vu1-user-h, profile-h

The `gsound-h` is very simple, but the rest have decent docs and all the
macros we had from jak 2.

So far, barely any differences! (there's a few in gsound-h)
2024-01-22 21:09:48 -05:00
Ziemas 3dc27e37e5 decompiler: Extract Jak3 VAGs (#3328) 2024-01-22 20:47:06 -05:00
Hat Kid d4c21c784f decomp3: geometry, vector, timer-h, ocean table files and game-task related enums (#3329) 2024-01-22 20:45:53 -05:00
water111 01d5fc2bbb [jak3] Decomp for gkernel, gkernel-h, gstate, gstring (#3326)
I ported the kernel test from jak1/jak2 to jak 3, and it's passing!
2024-01-21 18:08:05 -05:00
water111 638bf1d3d9 [gltf] Support either u16 or float for colors (#3322)
It seems like this depends on the version of blender, so we should
support both.
2024-01-21 11:03:26 -05:00
Tyler Wilding 5ddf1e4b4d lsp: flag unnamed variables in IR files (#3325)
![image](https://github.com/open-goal/jak-project/assets/13153231/a020fbf6-65b9-4317-8a9d-5991f2d15e32)
2024-01-21 01:05:41 -05:00
Hat Kid 2bb1d53752 custom levels: cell-info and buzzer-info lumps (#3324)
Adds two new lump types: `cell-info` and `buzzer-info`.

`cell-info` takes a `game-task` enum value and defines an `eco-info`
lump for power cells.

`buzzer-info` takes a `game-task` enum value and an integer and
automatically calculates the required value for the buzzer task with the
formula `task + buzzer * (1 << 16)`.
2024-01-21 03:49:55 +01:00
ManDude 076f8aa6dd [jak2] fix music player option (#3323) 2024-01-20 23:28:21 +00:00
water111 1c0038294f [jak3] Decompile gcommon (#3321)
Decompile `gcommon`. I adjusted the spacing of docstring comments, and
removed some spammy decompiler warning prints.

I also added some random notes I had on VU programs from jak1/jak2. They
are not polished, but I think it's still worth including since we'll
have to go through them again for jak 3.
2024-01-20 12:33:39 -05:00
Hat Kid 9a4929ac0c decomp3: some engine files (#3319)
- `vector-h`
- `gravity-h`
- `bounding-box-h`
- `matrix-h`
- `quaternion-h`
- `euler-h`
- `transform-h`
- `geometry-h`
- `trigonometry-h`
- `transformq-h`
- `bounding-box`
- `matrix`
- `matrix-compose`
- `transform`
- `quaternion`
- `euler`
- `trigonometry`

Not a whole lot of changes, just a couple of new functions and one new
file (`matrix-compose`).
2024-01-20 10:42:51 -05:00
Ziemas 25c74f1740 j2-overlord: Fix typo (#3320) 2024-01-20 14:43:52 +01:00
Tyler Wilding 272cb32a45 lsp: handle line-endings appropriately (#3318) 2024-01-18 20:32:30 -05:00
Tyler Wilding c3e4baf697 formatter: support for a few more forms and fix some bugs, update tree-sitter grammar (#3317) 2024-01-18 20:09:40 -05:00
Hat Kid 85039fe2d6 jak3: fix all-types file order (#3316)
In #3300, `per_object` in `ObjectFileDB::ir2_analyze_all_types()` was
changed to an `unordered_map`, which messed with the object file order
in `all-types`. This fixes the issue by going through each object file
in order and then looking up the type info from the map instead of
iterating through the map.

This also removes the method IDs from the old method comments and adds a
stub for the `new` method if there is an old method comment for it, in
order to stay consistent with the rest of the method list.
2024-01-18 14:57:10 +01:00
Hat Kid b06d63ba83 custom levels: sort actors by aid and check for duplicates (#3315)
When giving entities custom actor IDs in your level JSON, it is possible
to break entity lookups by actor ID if the actors are not sorted by ID
because `entity-by-aid` expects them to be in order.

This sorts the actor list by ID before generating the level file and
also checks for any duplicates.
2024-01-18 10:29:30 +01:00
ManDude 13f1aa1785 [jak2] fully implement PLAYER set-param for VAG streams + fix regression (#3314)
At last...
2024-01-18 01:59:04 +00:00
ManDude ba7b0397b1 [pckernel] fix settings not being applied if file isn't found (#3313) 2024-01-17 15:43:53 +00:00
water111 4f537d4a71 [jak3] Set up ckernel (#3308)
This sets up the C Kernel for Jak 3, and makes it possible to build and
load code built with `goalc --jak3`.

There's not too much interesting here, other than they switched to a
system where symbol IDs (unique numbers less than 2^14) are generated at
compile time, and those get included in the object file itself.

This is kind of annoying, since it means all tools that produce a GOAL
object file need to work together to assign unique symbol IDs. And since
the symbol IDs can't conflict, and are only a number between 0 and 2^14,
you can't just hash and hope for no collisions.

We work around this by ignoring the IDs and re-assigning our own. I
think this is very similar to what the C Kernel did on early builds of
Jak 3 which supported loading old format level files, which didn't have
the IDs included.

As far as I can tell, this shouldn't cause any problems. It defeats all
of their fancy tricks to save memory by not storing the symbol string,
but we don't care.
2024-01-16 19:24:02 -05:00
James AldridgeandJamesAldridge ed6639ee60 fix zydis alignment issue during build for intel macs (#3312)
Fix zydis alignment issues when building on Intel macOS builds was
discussed with zydis devs https://github.com/zyantific/zydis/issues/474

Verified locally that I can run open goal with the change.

Co-authored-by: JamesAldridge <[email protected]>
2024-01-16 19:01:55 -05:00
ManDude 1dba36c614 fix jak3 jp strings (#3311) 2024-01-16 11:09:17 +00:00
Tyler Wilding 4101d5d80e tests: add jak3 typeconsistency test and ensure offline tests are working (#3310) 2024-01-16 00:15:33 -05:00
jabermonyandTyler Wilding 07427799a6 Jak3 Build Environment (#3098)
This sets out the bones of a Jak 3 build, many things are stubbed out,
guessed, or copied from Jak 2 but it should at least be good enough to:
run `task set-game-jak3`
launch the repl
run builds from the repl

build outputs themselves are untested but the build itself runs without
errors

---------

Co-authored-by: Tyler Wilding <[email protected]>
2024-01-15 20:37:16 -05:00
Tyler Wilding 637b043293 deps: update zydis to latest commit (#3306)
Updates Zydis to it's latest commit, this should fix building the
project on intel macs with a more recent version of macOS. This likely
needs some sanity checks that the debugger stuff still works as
expected.
2024-01-15 16:56:14 -05:00
ManDude 46db6a36da [pckernel] use pc-get-resolution to fetch initial fullscreen resolution (#3307)
This is the more correct way of doing what that code is trying to do.
Fixes #3296

Also fixed some type inconsistencies with related code, probably wasn't
causing issues though.

May also fix the "black screen on startup" issues people keep having,
but that would simply be a nice bonus and isn't the aim of this PR.
2024-01-15 18:53:49 +00:00
Hat Kid 619f39d3b7 custom levels: enum lump support (#3305)
This adds support for using enums in lumps using the new lump types
`enum-int32` and `enum-uint32`. Also adds these other new lump types:

- `water-height` (takes 3 meter floats, an enum and another optional
meter float)
- `eco-info` (takes an enum and an int)
- `vector3m` (3 meter floats + `w` set to 1.0)
2024-01-15 12:46:42 +01:00
Matt Dallmeyer 2071c98b55 Fix cases of string formatting with non string literals (#3304)
The logger used in `goalc` tries to print an already-formatted string
`message` using `fmt::print(message);` Usually this doesn't cause
problems, but if you try to print, for example, an exception that has
special characters (notably `{`) it will try to do another round of
formatting/replacements, despite not having any args to replace with,
which ends up throwing another exception. This is why errors when
parsing custom level JSON cause the REPL to exit.

I've hopefully identified all the various instances of this across the
codebase
2024-01-14 12:02:08 +00:00
ManDude 7a8aa71204 [jak2] implement statistics tracker (#3288)
Currently only tracks enemy kills, and how they were killed. There is
currently no menu for this, but I've already added most of the text for
it. Also did a bunch of misc decompilation fixes and renamed some
methods.

Fixes #3277 
Fixes #3278
2024-01-11 22:49:41 +00:00
Tyler Wilding a80cff9a4c game: Fix issues related to remapping with SDL axii's (ie. triggers) (#3294)
This was just not implemented end to end. There are still two notable
issues, one that I can live with, one I need to narrow down eventually:
1. Rebinding confirm buttons with trigger (ie. X) behaviour is not 100%
as it should be. I fixed it enough that I can live with it but it's
still not proper. The difficulty is that unlike a button it will
re-trigger the pressed state on the journey back to neutral (aka
unpressed).
2. If you change the bind for the confirm button, then reset your
bindings, the next confirm input is eaten. This is unrelated to these
changes but I briefly looked into it and was unable to find the root
cause.
2024-01-09 16:50:58 -05:00
Tyler Wilding 4cccaf2645 d/j3: all-types: guess at associated process for non-virtual states and fix some issues along the way (#3300)
This will make a best effort attempt at guessing which process a
non-virtual state belongs to:
![Screenshot 2024-01-08
195309](https://github.com/open-goal/jak-project/assets/13153231/69132f10-823d-4df5-b2d6-662d4dd754a0)

I also noticed some issues while working on this, mainly around how
virtual states were being output. They were being duplicated, for
example:
![Screenshot 2024-01-08
184733](https://github.com/open-goal/jak-project/assets/13153231/1edb0f1a-3ac7-46cb-96cd-cf93d42fb01f)
or
![Screenshot 2024-01-08
193730](https://github.com/open-goal/jak-project/assets/13153231/45673653-4000-45bb-af00-9baa6e2a70ae)

I think I've fixed that, but @Hat-Kid I defer to you to see if i've done
something terrible.
![Screenshot 2024-01-08
194513](https://github.com/open-goal/jak-project/assets/13153231/75543d2e-69da-4bbd-b143-2f824b9d8dde)
2024-01-09 16:50:05 -05:00
Matt Dallmeyer 9d680a0aba Support extracting collision to obj for jak2/3 formats (#3292)
![image](https://github.com/open-goal/jak-project/assets/2515356/b4d43254-4fc4-4f66-92d1-0d61e471b90e)

![image](https://github.com/open-goal/jak-project/assets/2515356/d2fa9fb8-5f51-43c5-8e0e-b51b64499b72)
2024-01-05 09:36:09 +01:00
dependabot[bot] b0713641e7 build(deps): bump actions/download-artifact from 3 to 4 (#3283)
Bumps
[actions/download-artifact](https://github.com/actions/download-artifact)
from 3 to 4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/download-artifact/releases">actions/download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.0</h2>
<h2>What's Changed</h2>
<p>The release of upload-artifact@v4 and download-artifact@v4 are major
changes to the backend architecture of Artifacts. They have numerous
performance and behavioral improvements.</p>
<p>For more information, see the <a
href="https://github.com/actions/toolkit/tree/main/packages/artifact"><code>@​actions/artifact</code></a>
documentation.</p>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/bflad"><code>@​bflad</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/download-artifact/pull/194">actions/download-artifact#194</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/download-artifact/compare/v3...v4.0.0">https://github.com/actions/download-artifact/compare/v3...v4.0.0</a></p>
<h2>v3.0.2</h2>
<ul>
<li>Bump <code>@actions/artifact</code> to v1.1.1 - <a
href="https://redirect.github.com/actions/download-artifact/pull/195">actions/download-artifact#195</a></li>
<li>Fixed a bug in Node16 where if an HTTP download finished too quickly
(&lt;1ms, e.g. when it's mocked) we attempt to delete a temp file that
has not been created yet <a
href="hhttps://redirect.github.com/actions/toolkit/pull/1278">actions/toolkit#1278</a></li>
</ul>
<h2>v3.0.1</h2>
<ul>
<li><a
href="https://redirect.github.com/actions/download-artifact/pull/178">Bump
<code>@​actions/core</code> to 1.10.0</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/download-artifact/commit/f44cd7b40bfd40b6aa1cc1b9b5b7bf03d3c67110"><code>f44cd7b</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/259">#259</a>
from actions/robherley/glob-downloads</li>
<li><a
href="https://github.com/actions/download-artifact/commit/3181fe853d2c9a606cd326853bf4c5b8ced5df02"><code>3181fe8</code></a>
add some migration docs</li>
<li><a
href="https://github.com/actions/download-artifact/commit/aaaac7b403f278b6b7eebdca69ca1658616f1c57"><code>aaaac7b</code></a>
licensed cache</li>
<li><a
href="https://github.com/actions/download-artifact/commit/7c9182f0e18dadedfbca3189ab7a22a416aa6714"><code>7c9182f</code></a>
update readme</li>
<li><a
href="https://github.com/actions/download-artifact/commit/b94e7015566b40b2de5eeeda514f239968da2dd7"><code>b94e701</code></a>
licensed cache</li>
<li><a
href="https://github.com/actions/download-artifact/commit/0b55470e40ab7435f445813ebc18b1107ecf7e32"><code>0b55470</code></a>
add test case for globbed downloads to same directory</li>
<li><a
href="https://github.com/actions/download-artifact/commit/0b51c2ef9042b581aded9711127e4a6d5f71c550"><code>0b51c2e</code></a>
update prettier/eslint versions</li>
<li><a
href="https://github.com/actions/download-artifact/commit/c4c6db724f9510b2b3cff5ebcc417c87a2b2fa97"><code>c4c6db7</code></a>
support globbing artifact list &amp; merging download directory</li>
<li><a
href="https://github.com/actions/download-artifact/commit/1bd0606e08fcaa4c28afc1fc7d45830ab5482dac"><code>1bd0606</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/252">#252</a>
from stchr/patch-1</li>
<li><a
href="https://github.com/actions/download-artifact/commit/eff4d42b1f6ff704c7a0f37152ed8793673560ef"><code>eff4d42</code></a>
fix default for run-id</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/download-artifact/compare/v3...v4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/download-artifact&package-manager=github_actions&previous-version=3&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-04 01:32:49 -05:00
dependabot[bot] aa68b80da2 build(deps): bump actions/upload-artifact from 3 to 4 (#3284)
Bumps
[actions/upload-artifact](https://github.com/actions/upload-artifact)
from 3 to 4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.0</h2>
<h2>What's Changed</h2>
<p>The release of upload-artifact@v4 and download-artifact@v4 are major
changes to the backend architecture of Artifacts. They have numerous
performance and behavioral improvements.</p>
<p>For more information, see the <a
href="https://github.com/actions/toolkit/tree/main/packages/artifact"><code>@​actions/artifact</code></a>
documentation.</p>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/vmjoseph"><code>@​vmjoseph</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/464">actions/upload-artifact#464</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v3...v4.0.0">https://github.com/actions/upload-artifact/compare/v3...v4.0.0</a></p>
<h2>v3.1.3</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(github): remove trailing whitespaces by <a
href="https://github.com/ljmf00"><code>@​ljmf00</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/313">actions/upload-artifact#313</a></li>
<li>Bump <code>@​actions/artifact</code> version to v1.1.2 by <a
href="https://github.com/bethanyj28"><code>@​bethanyj28</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/436">actions/upload-artifact#436</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v3...v3.1.3">https://github.com/actions/upload-artifact/compare/v3...v3.1.3</a></p>
<h2>v3.1.2</h2>
<ul>
<li>Update all <code>@actions/*</code> NPM packages to their latest
versions- <a
href="https://redirect.github.com/actions/upload-artifact/issues/374">#374</a></li>
<li>Update all dev dependencies to their most recent versions - <a
href="https://redirect.github.com/actions/upload-artifact/issues/375">#375</a></li>
</ul>
<h2>v3.1.1</h2>
<ul>
<li>Update actions/core package to latest version to remove
<code>set-output</code> deprecation warning <a
href="https://redirect.github.com/actions/upload-artifact/issues/351">#351</a></li>
</ul>
<h2>v3.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump <code>@​actions/artifact</code> to v1.1.0 (<a
href="https://redirect.github.com/actions/upload-artifact/pull/327">actions/upload-artifact#327</a>)
<ul>
<li>Adds checksum headers on artifact upload (<a
href="https://redirect.github.com/actions/toolkit/pull/1095">actions/toolkit#1095</a>)
(<a
href="https://redirect.github.com/actions/toolkit/pull/1063">actions/toolkit#1063</a>)</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/upload-artifact/commit/c7d193f32edcb7bfad88892161225aeda64e9392"><code>c7d193f</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/466">#466</a>
from actions/v4-beta</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/13131bb095770b4070a7477c3cd2d96e1c16d9f4"><code>13131bb</code></a>
licensed cache</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/4a6c273b9834f66a1d05c170dc3f80f9cdb9def1"><code>4a6c273</code></a>
Merge branch 'main' into v4-beta</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/f391bb91a3d3118aeca171c365bb319ece276b37"><code>f391bb9</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/465">#465</a>
from actions/robherley/v4-documentation</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/9653d03c4b74c32144e02dae644fea70e079d4b3"><code>9653d03</code></a>
Apply suggestions from code review</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/875b63076402f25ef9d52c294c86ba4f97810575"><code>875b630</code></a>
add limitations section</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/ecb21463e93740a6be75c3116242169bfdbcb15a"><code>ecb2146</code></a>
add compression example</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/5e7604f84a055838f64ed68bb9904751523081ae"><code>5e7604f</code></a>
trim some repeated info</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/d6437d07581fe318a364512e6cf6b1dca6b4f92c"><code>d6437d0</code></a>
naming</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/1b561557037b4957d7d184e9aac02bec86c771eb"><code>1b56155</code></a>
s/v4-beta/v4/g</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/upload-artifact/compare/v3...v4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=3&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-04 01:32:40 -05:00
Ziemas 6901e80e7f j2-overlord: Clean up some VAG functions (#3287)
Some cleanup of vag related functions in overlord.
2024-01-02 16:30:56 +00:00
EvelynTSMG 12118e57cb Impr: Make mesh extract compatible with gLTF 2.0 (and Blender 4.0) (#3268)
:3
2024-01-01 16:30:48 -05:00
ManDude 349919f788 [jak2] implement pc cheats in menu (#3275)
Adds the opengoal cheats to the secrets menu. Only cheats that are fully
functional and unlockable are there right now, which is eight cheats.

This update will reset most Jak 2 settings.

Also fixes #3274 .
2023-12-28 11:14:10 +00:00
ManDude a01d78c7d4 [jak2] fix shadow origin using wrong joint (#3271)
Copypasta. Fixes #3269
2023-12-22 16:52:53 +00:00
Tyler Wilding 708c15788b g/j2: switch to OpenGOAL speedrun.com leaderboards (#3265)
Boards that have no runs yet look kinda awkward but i'd rather just wait
until those fill out (won't take long) rather than add another string to
be translated.
2023-12-19 19:06:55 -05:00
Tyler Wilding 6cfb89a78a g/j2: fix interleaving of local and external highscores (#3264)
Local scores weren't going above external scores even if they were
higher, a few test cases:

![Screenshot 2023-12-19
182412](https://github.com/open-goal/jak-project/assets/13153231/bf3c700d-0f23-441e-b537-88794532523b)
![Screenshot 2023-12-19
182446](https://github.com/open-goal/jak-project/assets/13153231/18d5d6eb-54b1-466e-8302-ca629677344f)
![Screenshot 2023-12-19
182442](https://github.com/open-goal/jak-project/assets/13153231/7de763a5-3587-416f-8755-1868049b92ed)
![Screenshot 2023-12-19
182421](https://github.com/open-goal/jak-project/assets/13153231/d44c1b5b-5f4f-4151-a1f0-e28d7612ed9d)
2023-12-19 18:58:25 -05:00
Tyler Wilding 99da5da441 g/j2: save window-size to pc-settings when it's changed (#3263)
Fixes #3262
2023-12-19 18:56:49 -05:00
RoyalForgottenandTyler Wilding c7af284c6b French subtitle_lines_fr-FR.json (#3259)
French subtitles complete + fixed some wrong texts

---------

Co-authored-by: Tyler Wilding <[email protected]>
2023-12-19 18:55:51 -05:00
Matt Dallmeyer 3e568cb95d Disable save_texture_pngs by default [jak1] (#3256) 2023-12-18 18:25:51 -05:00
tripp 4b9c1dde70 add ms to loader output (#3261) 2023-12-18 18:17:27 -05:00
OpenGOAL BotandOpenGOALBot 35daebcce7 CI: Periodic Controller Database Update (#3255)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2023-12-18 18:17:10 -05:00
ManDude 897e9c588b fix weird potential initialization bug with the music log (#3258) 2023-12-12 23:34:14 +00:00
water111 f17427bc26 [jak2] Fix unicode issue with GAME.CGO load (#3254)
Fix for https://github.com/open-goal/jak-project/issues/3244
2023-12-09 18:11:24 -05:00
Ziemas 168afa0e2e 989snd: sound bank loading overhaul (#3185) 2023-12-07 20:22:54 -05:00
Hat Kid 9b6f16f561 jak2: 90 fps menu option (#3245)
Closes #3223
2023-12-03 21:32:21 +01:00
ManDude 1808596679 save & load game territory setting (#3243) 2023-12-03 18:19:38 +00:00
ManDude 94b984326f [jak2] add game territory menu option (#3242) 2023-12-03 16:16:05 +00:00
ManDude 2795d3aa67 [jak2] fix health bar color fading (#3241)
Fixes #3237
2023-12-03 09:42:01 +00:00
ManDude be6a6dead4 [jak2] fix use-after-free bug in nav enemies (#3240)
Fixes #3153
2023-12-03 09:24:34 +00:00
ManDude 974f5931de [jak2] add resolutions menu (#3238) 2023-12-03 08:11:18 +00:00
Brent Hickey e119a66788 [jak2] Support STICK_DEADZONE (#3239)
fixes #3235
2023-12-03 08:11:10 +00:00
SuperSamusandMartino Fontana 37069e2f8e [jak2] Fix "Select controller" (#3191)
Co-authored-by: Martino Fontana <[email protected]>
2023-12-02 15:20:26 -05:00
Hat KidandTyler Wilding dfa6622544 jak2: add vehicle hijack lines PC cheat (#3205)
Co-authored-by: Tyler Wilding <[email protected]>
2023-12-02 15:17:54 -05:00
Luminar Light a3af37989b Allow replacing all instances of a texture with one texture (#3234)
There are art groups that are present in multiple levels, and that means
that also their textures are present in multiple levels. With texture
replacement, currently we need to make replacements for all instances if
we want it replaced everywhere, but this is not ideal, especially when
you make changes to your replacement texture and now you have to put it
in each folder again.

I added a way to replace all instances of a texture, by letting
texture-replacer people put their replacements into an '_all' folder. I
set up the logic in such a way that if you have a replacement for the
texture in its corresponding folder, it will take priority over a
replacement that you placed into the '_all' folder.

I personally found this very useful for replacing guard textures. The
guards appear in a lot of levels. But ideally you want them to look the
same everywhere. And that is why I looked into this and made a PR.

Oh and I changed what is printed in the 'Replacing ' part because it was
printing the path to our replacement, which didn't look nicely when
several textures got replaced by the same replacement from the '_all'
folder. So now it will print the original texture's page and name, I
think this information is more useful anyway.
2023-12-02 12:17:47 -05:00
water111 a01182315b [jak2] Support per-proto shrub visibility (#3228)
Fixes the issue reported in
https://github.com/open-goal/jak-project/issues/3168,
https://github.com/open-goal/jak-project/issues/3189,
https://github.com/open-goal/jak-project/issues/3166,
https://github.com/open-goal/jak-project/issues/3152,
https://github.com/open-goal/jak-project/issues/3224 where a small part
of the pipes in the `strip-grenade` mission appear, but shouldn't.
2023-12-02 12:16:14 -05:00
ManDude e38fe70ac4 [jak2] split language and text language (#3233) 2023-11-29 23:28:53 +00:00
ManDude 956645bdb9 [jak2] adjust progress generic item sizes + add scrolling effect (#3231)
Makes most of the options larger to reduce the amount of dead space and
adds a smooth scrolling effect instead of having "pages".


![imagem](https://github.com/open-goal/jak-project/assets/7569514/fc483dea-226c-44ff-96e0-680e89a6df81)

Button remap menu has no scrolling. Fixes #2984
2023-11-29 18:27:02 +00:00
1302 changed files with 351883 additions and 29726 deletions

No files matched your search

+1 -1
View File
@@ -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
+1 -1
View File
@@ -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 }}
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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 }}
+1 -1
View File
@@ -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/
+1 -1
View File
@@ -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
View File
@@ -1 +0,0 @@
endOfLine: "auto"
+11
View File
@@ -0,0 +1,11 @@
{
"endOfLine": "auto",
"overrides": [
{
"files": ["**/*.jsonc"],
"options": {
"parser": "json"
}
}
]
}
+25
View File
@@ -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",
+1 -1
View File
@@ -5,7 +5,7 @@
"comments": true,
"strings": true
},
"editor.wordBasedSuggestions": true,
"editor.wordBasedSuggestions": "matchingDocuments",
"editor.snippetSuggestions": "top"
},
"python.formatting.provider": "black",
-2
View File
@@ -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 \
+10
View File
@@ -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
View File
@@ -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'
+20 -3
View File
@@ -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) {
+4
View File
@@ -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) {
+7 -1
View File
@@ -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();
+39 -7
View File
@@ -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] =
+35 -9
View File
@@ -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") {
+16 -4
View File
@@ -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 = {});
};
+13 -1
View File
@@ -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)},
+2 -2
View File
@@ -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 =
+1 -7
View File
@@ -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;
}
}
+1 -1
View File
@@ -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);
+7 -2
View File
@@ -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);
+3 -3
View File
@@ -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();
}
+2 -2
View File
@@ -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;
};
+15
View File
@@ -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
View File
@@ -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;
+174
View File
@@ -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;
}
+7 -1
View File
@@ -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) {
+2 -2
View File
@@ -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();
}
+10 -7
View File
@@ -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;
};
+32 -6
View File
@@ -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
+2
View File
@@ -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
+1 -1
View File
@@ -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),
+1 -1
View File
@@ -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);
+16
View File
@@ -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;
+2
View File
@@ -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);
+9 -2
View File
@@ -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() {
+1
View File
@@ -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
+36 -11
View File
@@ -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": {
+26 -9
View File
@@ -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": {
+2 -2
View File
@@ -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"));
+1 -1
View File
@@ -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,
+4 -4
View File
@@ -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);
+5 -5
View File
@@ -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++;
}
+2 -1
View File
@@ -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?
+80 -19
View File
@@ -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);
}
}
+2 -1
View File
@@ -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);
+1 -1
View File
@@ -20,7 +20,7 @@ enum class VuInstrK {
// ADDAq,
ADDAbc,
SUB,
// SUBi, // 10
SUBi, // 10
// SUBq,
SUBbc,
// SUBA,
+81 -59
View File
@@ -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;
+3 -1
View File
@@ -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;
}
+1 -1
View File
@@ -172,7 +172,7 @@ bool convert_to_expressions(
"statement.",
f.name());
f.warnings.warning(warn);
lg::warn(warn);
lg::warn("{}", warn);
}
}
+34 -11
View File
@@ -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);
}
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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;
}
+1
View File
@@ -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")}),
+1 -1
View File
@@ -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
View File
@@ -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");
+3
View File
@@ -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,
+2 -2
View 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))
+9 -7
View File
@@ -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
+157 -90
View File
@@ -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)
+7 -5
View File
@@ -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"]]
}
+25 -1
View File
@@ -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"]
}
}
}
File diff suppressed because it is too large. Load diff
+17 -6
View File
@@ -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)"]
]
}
+10 -2
View File
@@ -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.
+284 -276
View File
@@ -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"]]
}
+264 -1
View File
@@ -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"]
]
}
+877 -1
View File
@@ -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"
]
}
}
+15 -12
View File
@@ -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);
}
}
+84 -63
View File
@@ -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;
}
+1 -2
View File
@@ -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
+13 -18
View File
@@ -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,
+14 -2
View File
@@ -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
View File
@@ -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));
+1 -1
View File
@@ -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
+24 -1
View File
@@ -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);
+4
View File
@@ -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
+7 -1
View File
@@ -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,
+3 -1
View File
@@ -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
+44
View File
@@ -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
```
+513
View File
@@ -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
```
+261
View File
@@ -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`
+319
View File
@@ -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
View File
@@ -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