Compare commits

...
129 Commits
Author SHA1 Message Date
water111andwater111 48cb9bb787 [decompiler] as-type and font method support (#3855)
Add support for `as-type` macro, and detecting inline font methods. This
works in all three games but I've only updated jak 3's goal_src for now.
Eventually I will go back and work through the others, but I want to get
more decompiler features in first.


![image](https://github.com/user-attachments/assets/5c31bf85-97b4-437c-bc4b-dc054e60551e)

---------

Co-authored-by: water111 <[email protected]>
2025-02-01 21:23:11 -05:00
dependabot[bot] d5590ab638 build(deps): bump hendrikmuhs/ccache-action from 1.2.14 to 1.2.16 (#3854)
Bumps
[hendrikmuhs/ccache-action](https://github.com/hendrikmuhs/ccache-action)
from 1.2.14 to 1.2.16.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/hendrikmuhs/ccache-action/releases">hendrikmuhs/ccache-action's
releases</a>.</em></p>
<blockquote>
<h2>v1.2.16</h2>
<h2>What's Changed</h2>
<ul>
<li>Change Bash to Shell everywhere by <a
href="https://github.com/hansfn"><code>@​hansfn</code></a> in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/223">hendrikmuhs/ccache-action#223</a></li>
<li>Add option to add stats to Job Summary page by <a
href="https://github.com/planetmarshall"><code>@​planetmarshall</code></a>
in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/263">hendrikmuhs/ccache-action#263</a></li>
<li>Evict old files from the cache prior to saving by <a
href="https://github.com/planetmarshall"><code>@​planetmarshall</code></a>
in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/270">hendrikmuhs/ccache-action#270</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/planetmarshall"><code>@​planetmarshall</code></a>
made their first contribution in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/263">hendrikmuhs/ccache-action#263</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/hendrikmuhs/ccache-action/compare/v1...v1.2.16">https://github.com/hendrikmuhs/ccache-action/compare/v1...v1.2.16</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/53911442209d5c18de8a31615e0923161e435875"><code>5391144</code></a>
Revert <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/273">#273</a>
(<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/276">#276</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/10832139bf774c2772bd272b9965661f650cc03d"><code>1083213</code></a>
update code</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/f2e06a04a5f6407f80d5b08979a45824a2c95674"><code>f2e06a0</code></a>
Bump <code>@​actions/cache</code> from 3.3.0 to 4.0.0 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/268">#268</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/d10405245044a4399effebdfc1ae28cbaa1231f9"><code>d104052</code></a>
Bump typescript from 5.7.2 to 5.7.3 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/275">#275</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/f5df2923b5a63919a669a730a8795f719f700bdc"><code>f5df292</code></a>
Use sudo (if available) when installing sccache (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/273">#273</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/d535f91810e6ff57acce500c7992765d9bc05a33"><code>d535f91</code></a>
Bump <code>@​types/node</code> from 22.10.2 to 22.10.5 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/272">#272</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/e7a0524ab2c2f3d668e20aced36205fa717e29b9"><code>e7a0524</code></a>
Evict old files from the cache prior to saving (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/270">#270</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/c7704b4bd5fc9171d8e26073444d7779d90cde3c"><code>c7704b4</code></a>
Bump <code>@​types/node</code> from 22.10.1 to 22.10.2 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/269">#269</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/6f387851dc686da4ddc9833a1d7085535bd4d02f"><code>6f38785</code></a>
Add option to add stats to Job Summary page (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/263">#263</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/5f65b4d9dc6aafa5e9aedece06f7c06f2974af86"><code>5f65b4d</code></a>
Bump <code>@​types/node</code> from 22.10.0 to 22.10.1 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/267">#267</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/hendrikmuhs/ccache-action/compare/v1.2.14...v1.2.16">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=hendrikmuhs/ccache-action&package-manager=github_actions&previous-version=1.2.14&new-version=1.2.16)](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>
2025-02-01 15:22:08 -05:00
Hat Kid 710f3ac117 custom levels: etie and build actor support for jak2/3 (#3851)
Custom levels for Jak 2/3 now support envmapped TIE geometry. The TIE
extract was also changed to ignore materials that have the specular flag
set, but are missing a roughness texture.

Jak 2/3 now also support the `build-actor` tool.

The `build-custom-level` and `build-actor` macros now have a few new
options:

- Both now have a `force-run` option (`#f` by default) that, when set to
`#t`, will always run level/art group generation even if the output
files are up to date.
- `build-custom-level` has a `gen-fr3` option (`#t` by default) that,
when set to `#f`, will skip generating the FR3 file for the custom level
and only generate the GOAL level file to skip the potentially slow
process of finding and adding art groups and textures. Useful for when
you want to temporarily edit only the GOAL side of the level (such as
entity placement, etc.).
- `build-actor` has a `texture-bucket` option (default 0) which will
determine what DMA sink group the model will be placed in, which is
useful to determine the draw order of the model. Previously, this was
omitted, resulting in shadows not drawing over custom actors because the
actors were put in a bucket that is drawn after shadows (this behavior
can be restored with `:texture-bucket #f`).
2025-02-01 18:04:26 +01:00
OpenGOAL BotandOpenGOALBot 23b86d95c3 CI: Periodic Controller Database Update (#3847)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2025-01-28 09:19:17 -05:00
water111andwater111 7348e6a4ff [decompiler] Update vector ops, reduce casts (#3849)
Update the decompiler to use the new vf macros.

Also, fix a bunch of silly casting issues where accessing inline fields
with an offset of 0 would be better than a cast:

![image](https://github.com/user-attachments/assets/885bbb07-634f-47b8-99f5-5a947941cdde)

---------

Co-authored-by: water111 <[email protected]>
2025-01-20 16:32:58 -05:00
water111andwater111 98d6618a8b [decompiler] Detect vector*! (#3846)
Detect use of `vector*!`, which is inlined in jak 2 and jak 3.

---------

Co-authored-by: water111 <[email protected]>
2025-01-20 12:21:28 -05:00
water111andwater111 3ee2b4423c [decompiler] Cleanup for Jak 3 (#3845)
This PR does a few cleanups:
- improve method names/comments/flags for `enemy.gc` and a few other
files
- fix `new-stack-matrix0` not working for jak 3
- add `matrix-copy!` detection for jak 3
- add `vector-copy!` detection

---------

Co-authored-by: water111 <[email protected]>
2025-01-20 10:31:29 -05:00
water111andwater111 341f6117d5 Fix camera-other (#3843)
There's a feature to draw levels with a different camera matrix. This
uses `camera-temp-other`, `camera-rot-other`, etc instead of
`camera-temp`, `camera-rot`... I assumed that `trans-other` was the
"other" version of `trans`, but it turns out this isn't true -
`trans-other` is combined with `quat-other` and the original camera
matrix.

This fixes the issue by using the translation part of
`inv-camera-rot-other` for othercam levels only. (it works in all cases,
but I didn't want to use it for normal levels since I think it will be
less accurate)

Co-authored-by: water111 <[email protected]>
2025-01-18 17:44:38 -05:00
water111andwater111 ee0600cdbf [jak3] Improve overlord file size handling (#3828)
Try to avoid crashes/corruption if a file changes size after you've
started the game.

Co-authored-by: water111 <[email protected]>
2025-01-18 16:07:14 -05:00
water111andwater111 a29fca982b [jak1] Fix wind (#3837)
I accidentally broke this with the camera matrix improvements, but it's
fixed now.


![image](https://github.com/user-attachments/assets/144ac770-d7bf-414a-8814-062bbe51c39e)

---------

Co-authored-by: water111 <[email protected]>
2025-01-18 16:07:01 -05:00
OpenGOAL BotandOpenGOALBot 9c9af5b488 CI: Periodic Controller Database Update (#3839)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2025-01-14 00:49:12 -05:00
Tyler Wilding f6fad0630f macos: don't assume that all macOS major versions are simple numeric values (#3836)
Related to https://github.com/open-goal/launcher/pull/664
Likely Fixes https://github.com/open-goal/launcher/issues/663
2025-01-11 15:50:13 -05:00
OpenGOAL BotandOpenGOALBot 434484e5b5 CI: Periodic Controller Database Update (#3831)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2025-01-11 12:16:14 -05:00
Tyler Wilding 6f093f98ff gsrc: Add convenience macros for masking VF operations (#3824)
Migrates all code, there should be no change in the compilation output
(linter should check this)

At first i was considering making these builtins, which short of a bunch
of code generation, would require some sort of dynamic definition in
`Atoms.cpp`. This isn't hard but, i figured it would be better to keep
it simple and just generate the OG macros.

Fixes https://github.com/open-goal/jak-project/issues/233
2025-01-11 12:16:05 -05:00
Hat Kid e836f09212 jak3: fix error with subtitle speaker names (#3832) 2025-01-07 11:33:05 +01:00
Hat Kid f883b075fd jak3: port anim-tester-x (#3830) 2025-01-05 20:36:26 +01:00
Aloqasandblahpy fe648ac7c5 jak3 pc subtitles (#3812)
transcribed subtitles for gameplay and model viewer dialogue

---------

Co-authored-by: blahpy <[email protected]>
2025-01-05 20:27:48 +01:00
water111andwater111 b2c163999d [jak3] Fix cloth nans (#3827)
Kind of silly fix.

The cloth update function sometimes runs before the "setup" is done
(`need-setup` is set), which divides by zero in a bunch of places. This
fix prevents NaNs from spreading during this time.

Co-authored-by: water111 <[email protected]>
2025-01-05 13:00:01 -05:00
water111andwater111 79e4e36878 [gk] Increase print buffer, add size check (#3826)
This should fix the crash when entering the freedom HQ elevator. It was
caused by a large number of prints, one for each process in the city
being killed by `check-for-rougue-process`, which would overflow the
print buffer. So I increased the print buffer.

Detecting buffer overflow here is hard because lots of things are
allowed to write to it, including the user's GOAL print methods. I added
a basic check that will assert when there's 1k or less space in the
buffer. It won't catch every overflow, but it would have caught this
one.

Co-authored-by: water111 <[email protected]>
2025-01-05 11:05:09 -05:00
water111andwater111 e30dc9ecc7 [graphics] Improve some camera math (#3825)
I finally went through and worked out the math for the camera matrix,
and improved how it works for PC rendering. I was able to finally avoid
the double perspective divide issue, which I always thought would cause
accuracy issues.

This will help tfrag, tie (no envmap), shrub, and hfrag have less
z-fighting in cases where the camera and the thing you're looking at are
pretty close, but the entire level is far from the origin - like jak 3
temple. I was able to modify the camera matrix so we don't have to do
all the weird scaling/addition in the shader.

Here's a screenshot from the temple oracle checkpoint, cropped from 4k.
This used to have a lot of fighting issues.


![image](https://github.com/user-attachments/assets/4e11157f-ccf5-4f14-98a9-4a0b34da0cd2)

It doesn't help issues where the thing you're looking at is very far
away (jak 1 mountains, some jak 2 city stuff). It also doesn't help with
jak's skirt/scarf, since those use a different renderer.

There's definitely more to do here, but this is a good starting point
and proof that I can at least figure out the math.

Co-authored-by: water111 <[email protected]>
2025-01-05 09:57:48 -05:00
water111andwater111 e0acc2d15f [jak2, jak3] Unstretch moon and sun (#3822)
Fix the issue where the moon gets wide when using PC aspect ratios


![image](https://github.com/user-attachments/assets/db0ad274-5ee4-4ec3-92b6-650d295f8622)

Co-authored-by: water111 <[email protected]>
2025-01-04 12:39:23 -05:00
water111andwater111 2b226fedea [jak3] Update texture remap table (#3821)
Fix for https://github.com/open-goal/jak-project/issues/3820

Jak 2 and 3 use this annoying trick where they store multiple images in
the same texture by just changing the CLUT. This breaks some PC code
because those two textures will have the same TBP address. so there's a
table of remaps to fix this, generated by the decompiler. Unfortunately,
I generated that table before the decompiler loaded the .STR file with
these textures, so it was missing the remaps. This is automatically
generated in the texture folder when you run the decompiler - I just
copied it to the C++ file.


![image](https://github.com/user-attachments/assets/d3ca98d9-5d02-4055-bcb0-7e027a0a49b9)


![image](https://github.com/user-attachments/assets/9514bcbc-0523-466e-83cc-dd9cca7632ec)

Co-authored-by: water111 <[email protected]>
2025-01-04 12:24:57 -05:00
water111andwater111 266b423efa [jak3] Avoid language 255 issue (#3818)
In Jak 3, the default PC settings file would have a language of 255
because it runs before the first settings update. This would cause the
game to crash the second time it is started.

I also added this simple imgui window to see the names of streams in the
"SPU" memory, which has been useful for debugging

![image](https://github.com/user-attachments/assets/0a9d6af7-c423-4d8a-a461-faf45e350f33)

---------

Co-authored-by: water111 <[email protected]>
2025-01-04 11:39:28 -05:00
OpenGOAL BotandOpenGOALBot ea61985e21 CI: Periodic Controller Database Update (#3809)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-12-30 20:10:22 -05:00
Tyler Wilding e5a35f6ba0 fonts: add support for the rest of the czech alphabet (#3816)
Missed a few characters in the caron PR, but also adds support for the
rest of the czech alphabet that uses other diacritics.

![Screenshot 2024-12-30
174943](https://github.com/user-attachments/assets/10291b98-1232-47af-8391-95dca44adc07)
![Screenshot 2024-12-30
180032](https://github.com/user-attachments/assets/42f8d7a2-a798-425e-86ac-238bd589efa9)
2024-12-30 20:10:08 -05:00
Tyler Wilding d81b60736a fonts: support caron diacritics (#3815)
![Screenshot 2024-12-30
152831](https://github.com/user-attachments/assets/9b006764-00b8-4490-aeb5-02af39fa1724)
![Screenshot 2024-12-30
154346](https://github.com/user-attachments/assets/f27c9600-2d25-460d-afd6-2666d22a8ff7)
2024-12-30 17:34:26 -05:00
water111andwater111 0e55ff6108 [jak3] Fix issue where some vag streams never queue (#3805)
Accidentally incrementing `s` twice in the loop, so queued streams in
slot 1, and 3 were skipped by the overlord.
This would usually cause the audio to never start playing because the
game would wait for the audio to successfully get queued.

Co-authored-by: water111 <[email protected]>
2024-12-14 13:33:38 -05:00
Hat Kid 0e5aed329e jak3: fix missing shadow for wings (#3803) 2024-12-14 18:36:53 +01:00
water111andwater111 a3e8f0f91a [Jak3] Adjust overlord SPU dma to avoid audio hangs (#3804)
Change jak 3 SPU DMA to run the interrupt handler "immediately" (or at
least before `DMA_SendToSPUAndSync` returns).

This fixes an issue where audio can hang during fast cutscene playback.
I'm hoping it fixes more issues with looping/stuck audio as well, but
this needs more testing.

I originally wanted to do it this way, but thought that it didn't work -
from Jak 2 it seemed like things broke if the DMA was too fast. But, at
least for Jak 3, everything seems to work like this. This will remove a
huge source of non-deterministic timing in audio stuff and hopefully
make things easier to debug. It also means that a large portion of
streaming audio code will never have to run - from the game's point of
view there's always the next SPU buffer available.

If this works well, I might revisit jak 2 as well.

Co-authored-by: water111 <[email protected]>
2024-12-14 12:36:24 -05:00
water111andwater111 b3cdcf3a67 custom actor, fix animation compression (#3802)
Fix a missing scale factor when using the large mode in the animation
compressor. This would make some joints have a translation of near 0 if
the original animation had stuff moving a large distance

Co-authored-by: water111 <[email protected]>
2024-12-14 11:14:55 -05:00
OpenGOAL BotandOpenGOALBot 0edb88dc69 CI: Periodic Controller Database Update (#3779)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-12-10 16:53:36 -05:00
Hat Kid c476b84182 custom models: option to copy mod/eye draws from original model (#3800)
Two new flags were added to the Blender plugin to allow reusing the mod
and/or eye draws of the original model that is being replaced. Works
pretty well for eyes, but the blerc draws can cause some Z-fighting with
the non-moving parts of the model.

Also a small refactor to the merc replacement code to de-duplicate some
code by moving stuff to `gltf_util.cpp`.
2024-12-09 20:49:56 +01:00
water111andwater111 5458d865d4 [Custom Levels] Improve color palette generation (#3797)
A few improvements to color palette selection. These were made by
tracing some particularly bad colors through and seeing where it made
obviously bad decisions for splitting. I tested on crystal cave, and a
test GLBs from Kuitar that previously had issues with alpha.

- The previous approach to splitting was based on trying to keep a tree
of deduplicated colors balanced (same count in each leaf). This is not
really a good idea for generating color palettes. A better approach is
to try to minimize the volume of the child node, limiting how inaccurate
a color can be. Splitting is now chosen based on the average of the
_deduplicated channel values_, which in practice seems to work pretty
well for Kuitar's levels. Other approaches could work here too.
- The previous approach of alternating through dimensions to split on
was kept.
- The depth of the KD tree during the initial split was increased,
allowing it to use up to 8192 colors, instead of just 1024.
- In most cases, not all child nodes of the tree have colors in them,
meaning that a tree of depth 13 would have less than 8192 colors. If
this happens, child nodes are split until the color count reaches 8192.
The selection of which nodes to split is somewhat arbitrary, but is
breadth-first. The axis for splitting is the one with the largest range.
(which might be a better idea in general?)

On crystal-cave, the worst case color error was reduced from 221 to 9.

---------

Co-authored-by: water111 <[email protected]>
2024-12-08 12:31:48 -05:00
Hat KidandManDude 51d008f9ab decompiler: detect and turn inverse mult to div (#3795)
Co-authored-by: ManDude <[email protected]>
2024-12-07 23:10:49 +01:00
water111andwater111 a2f9d36332 Fix animation processing interpolation bug, crash on no merc material (#3794)
Fixes the issue with animations doing a full 180 degree rotation and
disappearing. The quaternions in the GLB export "flip", and when
interpolating animation frames in between a flip, we got bogus
quaternions.

Fixes https://github.com/open-goal/jak-project/issues/3786

Also fix a crash in `goalc` when using merc models without any
materials.

Co-authored-by: water111 <[email protected]>
2024-12-07 13:42:48 -05:00
ZedB0T 6e4e5d2bf7 Add option to hide the imgui bar with a click event (#3791)
Should cover edge cases where the bar is displayed and a keyboard type
device is not connected to the system (Steam deck/touch input based
device instead).

While it should probably be impossible to display the bar in the first
place on such devices it apparently isnt ->
https://www.reddit.com/r/jakanddaxter/comments/1h4mht1/how_to_remove_grey_bar_at_top_on_steamdeck/

And even ignoring the whole steamdeck/no keyboard thing adding another
way to hide it that is visible on the bar should help reduce people
asking about how to hide it. (And hopefully help people who dont
ask/dont know where to ask!)



https://github.com/user-attachments/assets/7f132781-675c-451e-8b39-2a78fa098b9e
2024-12-07 13:42:39 -05:00
water111andwater111 1029516f6d [sound] Add instance limits (#3769)
Add instance limits to the sound library, and a `dump-info` command to
`sndplay` to print out all the sounds/flags in an SBK file.

This is based on the decompiled 989snd library @Ziemas is working on
(https://github.com/Ziemas/dec989snd/blob/main/src/sndhand.c#L77)

Co-authored-by: water111 <[email protected]>
2024-12-07 13:41:45 -05:00
Hat Kid 8690104ba0 jak1: add merc version of draw-bones-hud (#3793)
Add a version of `draw-bones-hud` that uses merc to support drawing
foreground HUD elements that use custom models.
2024-12-06 20:25:20 +01:00
Hat Kid e18dbb6256 jak3: fix cloth disappearing after 600 orbs (#3790)
After collecting 600 orbs, cloth systems that didn't have any
`alt-tex-name`s defined would vanish because the `static-cloth-params`
macro doesn't default them to `#f`.
2024-12-02 17:43:41 +01:00
Hat Kid 477cefb6a5 model replacements: prevent duplicate processing (#3789)
Store a small database of which models have already been swapped out in
a level to prevent duplicate processing.

Also a small fix for cases where using a model replacement that has no
armature would cause merc nightmares due to only having a `max_bones` of
3.
2024-12-01 22:01:50 +01:00
Tyler Wilding 8feb46dc45 ci: hopefully fix MacOS CI in preparation for release (#3788)
Folder names were in common with the normal intel x86 build, the release
wasn't going to work. Hopefully with these changes it will but, still
technically untested. Don't have time to do so tonight.
2024-11-30 22:27:52 -05:00
Hat Kid 620168c45a custom models: ignore invalid envmap material (#3785)
If a model has a material with specular properties, but is missing a
roughness texture, warn and treat it as a normal draw instead of
erroring out.
2024-11-29 09:27:46 +01:00
massimilianodelliubaldini 4c2e1a8a90 Remove 128 character buffer causing long filenames to crash gk (#3771)
Several users have reported that ArchipelaGOAL is not launching
properly, even when using the OpenGOAL Launcher. The window pops up with
a black screen, and then quits. The only way they can run it is if they
double click gk.exe.

This comes down to the Launcher providing gk.exe with the `config_path`
parameter, which leads the program to find `archipelagoal-settings.gc`.
Here is an example from me:

```
D:\Applications\Games\OpenGOAL\features\jak1\mods\JakMods\_settings\archipelagoal\OpenGOAL\jak1\settings/Mods/archipelagoal-settings.gc
```

If a user's base OpenGOAL install directory is long enough, this path
becomes longer than 128 characters. This overflows the character buffer
in `kopen` which is used to open file streams. If you're only slightly
over the limit like myself, at 135 characters, you may not have noticed
a problem. But some users have paths a little longer, like 168
characters, and they report the issue is consistent.

Water111 suggested we remove the 128 character buffer and use the
filename data directly. This fix requires no changes to the Launcher,
just to the kernel, and every mod could stand to benefit from this fix.
2024-11-28 17:14:09 -05:00
Hat Kid ef719d2ab7 custom models: better error for invalid envmap material (#3784)
When a material in Blender has its IOR level changed to anything other
than the default value of 0.5, the `KHR_materials_specular` extension is
applied during the glTF export, which is what we use to check for
envmaps in custom models. If an envmap is undesired, but the IOR value
was accidentally changed, the program would assert during model
processing if there is no metallic roughness texture attached to the
material.

Since this is an easy mistake to make and is hard to spot, this adds a
better error message for such cases.
2024-11-27 19:14:23 +01:00
Hat Kid 7848ba05b8 jak3: fix music not pausing (#3783) 2024-11-27 15:46:41 +01:00
Hat Kid f6c55eba9f custom models: increase default joint count (#3782) 2024-11-27 04:21:33 +01:00
Hat Kid 6a06291e6e jak1, jak2: add get-texture macro (#3778)
Ports the `get-texture` macro added in Jak 3 to Jak 1 and 2.
2024-11-26 11:29:34 +01:00
Tyler Wilding 9b393e2ddb ci: update minimum macOS supported version to Ventura (13) (#3780)
macOS 12 has been end of life for 2 months, GitHub is removing support
for the images very soon (within a week or so).

https://endoflife.date/macos
2024-11-25 14:43:48 -05:00
Brendan Shanks 3f7aca3c72 Taskfile: Call 'python3' on non-Windows platforms (#3752) 2024-11-25 13:40:56 -05:00
Hat Kid c263bc2114 custom models: envmap support (#3777)
Custom models and model replacements now support environment mapping.

Also fixed some cases in Jak 3 where tfrags had missing textures
(defaulting to texture 0 from tpage 0, which in Jak 3 is the default eye
texture) and replaced them with more suitable alternatives.

Fixes #3776 


https://github.com/user-attachments/assets/7c11b0de-b254-40cb-9719-11238dfb3d43


![image](https://github.com/user-attachments/assets/4cc60b55-4965-4cb8-b29d-096560e7b3aa)


![image](https://github.com/user-attachments/assets/cb46d0d1-57d7-482c-b235-15d0e633f62c)
2024-11-23 14:32:55 +01:00
Hat Kid 2ff49b9905 jak3: fix ragdolls settling too early (#3775)
`none` methods strike again

Fixes #3774
2024-11-22 02:36:50 +01:00
Brendan Shanks 8f445bda3e Create separate x86_64 and ARM64 macOS targets. (#3760)
Create explicit x86_64 and ARM64 macOS build targets, so it's clear that
the CI is building x86_64 binaries (on both Intel and ARM64 build
machines). Also, use the `CMAKE_APPLE_SILICON_PROCESSOR` CMake variable
(which sets `CMAKE_SYSTEM_PROCESSOR`) so `BUILD_X86_ON_MACOS` is not
necessary.

And update the README.
2024-11-17 15:59:57 -05:00
water111andwater111 24ad5515f8 [jak3] workaround for intro crash on screen filter (#3770)
Simple workaround to put an effect in a different bucket. I don't think
there's a difference in the result, but this is just easier to handle on
the PC renderer side.

Co-authored-by: water111 <[email protected]>
2024-11-17 12:09:22 -05:00
Hat Kid 7543acfb8a jak3: speedrunner mode (#3761)
Base implementation of the popup menu and speedrunner mode in Jak 3.
Autosplitter is untested because I'm on Linux.

Also a couple of other misc changes:

- Model replacements can now have custom bone weights. Needs the "Use
Custom Bone Weights" property (provided by the OpenGOAL Blender plugin)
enabled in Blender.
- Better error message for lump syntax errors in custom level JSON
files.
2024-11-17 06:45:34 +01:00
water111andwater111 5e3cb8faa6 [jak3] Fix stack layout for car spawn (#3765)
Fix for cars spawning under ground or in weird places

Co-authored-by: water111 <[email protected]>
2024-11-16 17:52:14 -05:00
water111andwater111 321a113dd7 [jak3] Fix overlord soundbank unload, fix warnings (#3762)
Fix compiler warnings, and a bug where the `snd_handle` of
`SoundBankInfo` was never set, leading to sound banks never unloading.

The game relies on unloading soundbanks to make sure certain sounds
don't play, like the blue gun 1 fire noise when using blue gun 2.

---------

Co-authored-by: water111 <[email protected]>
2024-11-16 15:04:56 -05:00
OpenGOAL BotandOpenGOALBot 63676c70a5 CI: Periodic Controller Database Update (#3757)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-11-13 11:16:40 -05:00
Tyler Wilding 2c6d41c87a macOS: Fix issue causing only part of the window to be rendered to (#3756)
The fundamental issue is related to hiDPI / Retina displays, I don't
think our rendering code is setup properly to handle the scaling between
the two (which you can derive by comparing `SDL_GetWindowSize` and
`SDL_GL_GetDrawableSize`).

So rather than opening that can of worms, I just removed the window
flag.

Also fixed an unrelated issue for displaying resolution options when in
windowed mode, it was previously only adding options to the list if they
were invalid for full-screen.

Fixes #3099
2024-11-13 11:16:30 -05:00
Matt Dallmeyer 2a41bc615e [jak2] Fix bug where spinning into grind doesnt break clasps in dig1 (#3740)
if you sideflip into grind in the digsite mission, the clasps wont break
because it is considered a `board-spin` attack instead of `board`. This
extends the condition to allow for `board-spin` as well.

~~Should I wrap this in an `#if PC_PORT`?~~ done
2024-11-12 20:59:21 +01:00
water111andwater111 7553877e57 Fix crash in ocean-far with invalid DMA size (#3746)
DMA sizes are 16-bits, not 12-bits. This would cause rare crashes when
the ocean far renderer uses more than this.

I'm not really sure what the ocean far rendering is doing at this time,
but it happens as stuff is loading in.

There's a chance this fixes crashes in jak 2 as well, since we used to
see errors that would be explained by this.

Co-authored-by: water111 <[email protected]>
2024-11-12 19:38:51 +01:00
Hat Kid af5cb9b1cb jak3: subtitle3, vag-player (#3758) 2024-11-12 02:45:16 +01:00
Tyler Wilding b55a918902 deps: commit rapidjson with 8 year old fix (#3755)
Fixes https://github.com/open-goal/jak-project/issues/3753 hopefully

Rapidjson is never cutting a release, ever, and even if they did, the
discord-rpc library is deprecated so it would never consume it.

Instead of updating 8 years worth of changes and praying that works, I
just made the alleged fix from 8 years ago and changed discord-rpc's
cmake to not pull from the release.
2024-11-10 11:57:50 -05:00
Tyler Wilding f8058f2138 Support Apple Silicon via Rosetta2 on MacOS Sequoia and Above (#3754) 2024-11-10 11:06:56 -05:00
OpenGOAL BotandOpenGOALBot e3efede029 CI: Periodic Controller Database Update (#3749)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-11-09 12:05:01 -05:00
Brendan Shanks 4604636593 Fix sprite3_3d.vert on macOS (#3750)
Fixes a regression in #3722.

```
[18:34] [error] Failed to compile vertex shader sprite3_3d:
ERROR: 0:122: '&' does not operate on 'unsigned int' and 'int'
ERROR: 0:129: Use of undeclared identifier 'xy0_vf19'
ERROR: 0:129: Use of undeclared identifier 'xy0_vf19'
ERROR: 0:144: '&' does not operate on 'unsigned int' and 'int'
ERROR: 0:151: Use of undeclared identifier 'xy0_vf19'
ERROR: 0:151: Use of undeclared identifier 'xy0_vf19'
```
2024-11-06 22:30:01 -05:00
Brendan Shanks 8930141b72 docs: Remove instructions to add go-task tap to Homebrew. (#3751)
Homebrew has its own formula for go-task which is up-to-date and
working.
2024-11-06 22:27:15 -05:00
water111andwater111 1e530714b7 [jak3] Fix for precd extraction (#3744)
It looks like one of the tie models in this level has bad color data in
the lowest LOD. For now, just skip extracting the lowest lod for this
TIE only.

Co-authored-by: water111 <[email protected]>
2024-11-03 11:43:27 -05:00
Hat Kid cbb8add81c jak2: fix consite crash (#3743)
Since #3735, loading consite in Jak 2 crashes due to an assert in the
code that handles the PC clut blender DMA. The unused and
half-implemented `kor-transform` texture animation doesn't have any
blenders as the texture names are commented out in the C++ definition
(and it seems that these textures are defined multiple times within
different tpages in the same DGO, leading to errors during startup if
uncommented), leading to a mismatch between the actual qwc in GOAL and
the assumed DMA data size in C++.
2024-11-03 10:45:31 +00:00
Hat Kid 10d7dabfd7 game: move pc-encode-utf8-string to common kmachine code (#3742)
Also adds formatter rules for a couple of macros.
2024-11-03 01:28:48 +01:00
Alex ba9085fee0 [jak2] Correct behavior of hint subtitles toggle (#3741)
Re-uses the existing "hinttitles" toggle that's already there, and makes
it not depend on if the main subtitles are on or not.
2024-11-02 18:28:20 +00:00
OpenGOAL BotandOpenGOALBot 5e8ea23c30 CI: Periodic Controller Database Update (#3737)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-10-28 21:36:26 -04:00
ZedB0T 2f0a90b693 Update LICENSE, and add jak 2/3 iso_data folders (#3738)
- Updates the LICENSE
- Adds empty Jak 2/3 folders to iso_data following the pattern
established by the jak1 folder.
2024-10-29 00:29:19 +01:00
Hat Kid 348bf83b89 custom levels: add draco lib to support compressed glb files (#3723)
By adding the `draco` library as a dependency, `tinygltf` can support
GLB files compressed with the Draco compression algorithm which allows
for drastically reduced file sizes for custom levels (TFL's Crescent Top
GLB for example went from 135 MB to 37 MB).
2024-10-28 21:11:19 +01:00
water111andwater111 dff9ac163a [custom levels] A few bug fixes (#3736)
- Bug fix to KD tree splitting, should fix cases with bad vertex
colors/alphas.
- Normalize normals instead of asserting if they are the wrong length.
**the fact that blender exports normals incorrectly is a bug and I doubt
their implementation is correct if you've scaled things on only on
axis.**
- Automatically resize metallic texture (envmap strength) if it doesn't
match the size of the rgb texture instead of asserting

Co-authored-by: water111 <[email protected]>
2024-10-27 12:31:41 -04:00
water111andwater111 1962fbfb51 [jak2,3] Support loading clut blender animated textures to the pool (#3735)
Animated textures that use the clut blender can now upload them to the
texture pool, so they can get read by the eye renderer. This will also
fix darkjak's eyelids in jak 2.


![image](https://github.com/user-attachments/assets/5edbd20d-53c9-42c6-937d-6263823b8b45)

Co-authored-by: water111 <[email protected]>
2024-10-27 09:21:44 -04:00
water111andwater111 5bc61c5854 [jak3] Support texture anim in TIE (#3734)
Support animated textures in TIE. Apparently this is also used in jak 2
for robotank and we never noticed??


https://github.com/user-attachments/assets/bfa45a1a-4a96-4b25-817a-4327afcc7c98

Co-authored-by: water111 <[email protected]>
2024-10-26 15:47:34 -04:00
water111andwater111 510b23163f [jak3] Misc texture anim fixes (#3732)
- fix issue where animated textures that use the size-override feature,
and aren't being animated would show up as black - fix for black water
in spargus
- fix issue where animated texture uses another animated texture as an
input wouldn't get the animated version.
- fix math mistake in how animated texture rotations are handled. This
could cause textures to not rotate when a positions were rotated, but
textures (st's) weren't.
- fix definition of the ring texture to handle
set-alpha-texture-anim-layer-func



![image](https://github.com/user-attachments/assets/979748b0-7abf-46a5-bf9d-693fb0ef34fb)


![image](https://github.com/user-attachments/assets/3011662c-bfec-4ce9-ad72-8853b3784f77)



https://github.com/user-attachments/assets/0242a59d-62bd-4799-8f6f-2a0aba63649f

Co-authored-by: water111 <[email protected]>
2024-10-26 14:32:55 -04:00
OpenGOAL BotandOpenGOALBot cb51bd3f5b CI: Periodic Controller Database Update (#3726)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-10-21 20:49:38 -04:00
Tyler Wilding e76a4399e5 game: Update game's GPU test to output the GPU vendor info (#3717)
This is so I can get rid of wgpu from the launcher, where it's only
purpose is to figure out the GPU name for the support package.

The problem with it is that on some environments, it errors, but the
function cannot have it's errors gracefully handled (it panics and
crashes instead).

So I'm tired of it, do it ourselves.


![image](https://github.com/user-attachments/assets/fa8ae365-b3f7-4794-81ed-fde0c2ffc651)
2024-10-19 15:56:43 -04:00
Tyler Wilding e144406c16 g/j2: make the turret controls respect the camera settings (#3715)
Fixes #3664
2024-10-19 15:16:40 -04:00
water111andwater111 d82b6209b6 [jak3] Fix neosat particles and tentacle (#3722)
Fixes issue with not handling texture flipping flags in sprite renderer
(new jak 3 feature). As far as I can tell, there is no visible
difference because the textures that use this flag are symmetric.

Fix issue with not adding an `and` with `0xf` on the offset into the xy
table. This is added only in jak 3, where `vi07`'s upper bits are
sometimes nonzero, but doesn't hurt to have in all three games.
```
  iaddi vi09, vi00, 0xf      |  nop                      
  iand vi07, vi07, vi09      |  nop  
```

![image](https://github.com/user-attachments/assets/559d749a-957a-47dc-af6a-5b4b7d72a65b)

Fix issue with inf/nan causing the tentacle to not appear:

![image](https://github.com/user-attachments/assets/7c316cdf-7ff8-452d-b4af-ddb8d5ba4e44)

---------

Co-authored-by: water111 <[email protected]>
2024-10-19 14:05:42 -04:00
water111andwater111 eac11b5b93 [jak3] Fix target marker texture (#3721)
Fixes https://github.com/open-goal/jak-project/issues/3720.

The texture page and texture name appear multiple times with different
IDs, meaning that we insert the texture with the wrong ID. Fixed by
using IDs for common_tpage textures. Since this common_tpage feature is
only used for minimap stuff, I don't think it can mess up texture
animations.


![image](https://github.com/user-attachments/assets/0d5d45e9-b69a-48b5-86c9-b9c597f0872e)

Co-authored-by: water111 <[email protected]>
2024-10-19 11:21:30 -04:00
Tyler Wilding a6680cc26d game: fix game icon aspect ratio (#3718) 2024-10-18 23:02:19 -04:00
massimilianodelliubaldiniandTyler Wilding 7dbacc72d3 Parameterize the iso_data folder for goalc (#3692)
I hope this is everything I needed, and nothing I didn't.

## What's Changed

This update adds a command-line parameter to goalc, `--iso-path`.
Providing a path to a directory like
`D:\Files\Repositories\ArchipelaGOAL\iso_data\jak1` will inform the
compiler to use that directory instead.

## Why is this useful?

When combined with `--proj-path`, the compiler can be pointed to a
completely different project folder, given the `(mi)` command, and
immediately begin building from that directory, with everything it
needs. This eliminates the need to copy `iso_data` to multiple `data`
directories.

If a subsequent change to the Launcher is made, each mod could be passed
an --iso-path pointing to a single shared folder, allowing mods to each
run their own REPL _without_ requiring a copy of `iso_data` in a
subfolder.

## Independent testing required!

My local repositories are a little suspect, with a mod, a fork of
mod-base, and a fork of jak-project, all on the same drive. My
decompiler_out and iso_data folders are in the mod repo, not mod-base
nor jak-project. So what I did was make the change in the mod-base fork,
point `--proj-path and --iso-path` to the mod folders, and then ran
`(mi)`. The output showed a build starting with no errors.

Then I had to create this PR, which my fork of mod-base is unable to do,
so I created a patch file, forked jak-project, then applied the patch
there.

All this is to say that it would be preferable if someone could apply
this code to their own installation and see if it works. Even I wouldn't
take my own word for this.

---------

Co-authored-by: Tyler Wilding <[email protected]>
2024-10-18 00:03:14 -04:00
OpenGOAL BotandOpenGOALBot b50652ce54 CI: Periodic Controller Database Update (#3714)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-10-14 15:23:43 -04:00
Hat Kid c623190bff decompiler: fix secret-disable form in defskelgroup detection (#3713) 2024-10-14 02:07:08 +02:00
OpenGOAL BotandOpenGOALBot a7a7110550 CI: Periodic Controller Database Update (#3711)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-10-07 21:22:12 -04:00
water111andwater111 10008caad1 [jak3] Add merc fade and support for no texture flag (#3710)
Fixes https://github.com/open-goal/jak-project/issues/3709


https://github.com/user-attachments/assets/9fadf624-60b8-460f-9887-693712cc36c0

Co-authored-by: water111 <[email protected]>
2024-10-05 14:47:13 -04:00
water111andwater111 452f1329dd [jak3] fix envmap texture and strength (#3704)
Fix the envmap texture using the eye texture by default (will require a
re-extract to fix), fix envmap strength in all three games being off by
2x. (oops)

With envmap scale fix:

![image](https://github.com/user-attachments/assets/3b0ef8b7-cbdc-4402-8a12-af368538c16e)

without envmap scale fix (but with texture fix):

![image](https://github.com/user-attachments/assets/fd72d75b-f0bb-455c-a7c9-56916fbd4a67)

---------

Co-authored-by: water111 <[email protected]>
2024-10-05 12:53:57 -04:00
water111andwater111 b8c77c65f5 [jak3] Fix flashing with maker projectiles (#3702)
Fix https://github.com/open-goal/jak-project/issues/3701, and possibly
other issues where projectiles were invisible/messed up. The use of
`align16` with the -16 was subtracting 16 in cases when the pointer was
already aligned, causing a bad value to be loaded for the quaternion.

I also renamed some variables and did some manual cleanup on a method in
process-drawable, since this one comes up a lot during debugging.

Co-authored-by: water111 <[email protected]>
2024-10-05 11:40:03 -04:00
Tyler Wilding eb544bcfc0 extractor: add error code messages around 3990 (#3699)
Also added a new error code to make invalid folder paths hopefully more
clear/obvious.
2024-10-05 01:45:29 -04:00
Tyler Wilding cb4f7772bb github: switch to using issue types were applicable in issue forms (#3696) 2024-10-03 18:23:12 -04:00
Matt Dallmeyer 03cae68c7d [jak1] Patch "NG+ glitch" (#3690)
Fixes #3644 which I believe is the same underlying issue as "NG+ glitch"

To reproduce the issue in #3644 you can:
- choose Hub 2 100% in the speedrun fast reset menu
- hit the blue sage warp gate switch
- go deep enough into any adjacent level (e.g. basin) where `village2`
display is turned off
- reset speedrun in the fast reset menu
- tasks are reset but the switch will be pressed, giving the cutscene
early

You can also grab orbs/scout flies in `village2`, and they won't be
reset properly because of this same bug.

It happens because of the way entity perm status is managed across both
`level` vs `game-info` objects.
- when `village2` is deactivated (still loaded but display hidden), its
entity perms are copied to `game-info`'s `perm-list`
- this is how we persist `warp-gate-switch-7` being pressed if village2
is ever unloaded
- during the speedrun reset `reset-actors` is called:
- any active levels (loaded+displayed) have their entity perm statuses
reset
- because `village2` is not displayed yet, its entity perm statuses are
not touched
  - `game-info` is re-initialized, clearing out its `perm-list`
  - continue is set to `firecanyon-end`
    - this unloads `rolling` or whatever to make room for `firecanyon`
    - `village2` is already loaded, and just gets displayed
- at this point the game does copy entity perm status from `game-info`
back to the `village2` level
- but we reset the game, so it has no data about the warp-gate-switch,
leaving it pressed!
2024-10-01 22:17:32 -04:00
dependabot[bot] 6b7dd7ae22 build(deps): bump peter-evans/create-pull-request from 6 to 7 (#3694)
Bumps
[peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request)
from 6 to 7.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/peter-evans/create-pull-request/releases">peter-evans/create-pull-request's
releases</a>.</em></p>
<blockquote>
<h2>Create Pull Request v7.0.0</h2>
<p>✨ Now supports commit signing with bot-generated tokens! See
&quot;What's new&quot; below. ✍️🤖</p>
<h3>Behaviour changes</h3>
<ul>
<li>Action input <code>git-token</code> has been renamed
<code>branch-token</code>, to be more clear about its purpose. The
<code>branch-token</code> is the token that the action will use to
create and update the branch.</li>
<li>The action now handles requests that have been rate-limited by
GitHub. Requests hitting a primary rate limit will retry twice, for a
total of three attempts. Requests hitting a secondary rate limit will
not be retried.</li>
<li>The <code>pull-request-operation</code> output now returns
<code>none</code> when no operation was executed.</li>
<li>Removed deprecated output environment variable
<code>PULL_REQUEST_NUMBER</code>. Please use the
<code>pull-request-number</code> action output instead.</li>
</ul>
<h3>What's new</h3>
<ul>
<li>The action can now sign commits as <code>github-actions[bot]</code>
when using <code>GITHUB_TOKEN</code>, or your own bot when using <a
href="https://github.com/peter-evans/create-pull-request/blob/HEAD/docs/concepts-guidelines.md#authenticating-with-github-app-generated-tokens">GitHub
App tokens</a>. See <a
href="https://github.com/peter-evans/create-pull-request/blob/HEAD/docs/concepts-guidelines.md#commit-signature-verification-for-bots">commit
signing</a> for details.</li>
<li>Action input <code>draft</code> now accepts a new value
<code>always-true</code>. This will set the pull request to draft status
when the pull request is updated, as well as on creation.</li>
<li>A new action input <code>maintainer-can-modify</code> indicates
whether <a
href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork">maintainers
can modify</a> the pull request. The default is <code>true</code>, which
retains the existing behaviour of the action.</li>
<li>A new output <code>pull-request-commits-verified</code> returns
<code>true</code> or <code>false</code>, indicating whether GitHub
considers the signature of the branch's commits to be verified.</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>build(deps-dev): bump <code>@​types/node</code> from 18.19.36 to
18.19.39 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3000">peter-evans/create-pull-request#3000</a></li>
<li>build(deps-dev): bump ts-jest from 29.1.5 to 29.2.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3008">peter-evans/create-pull-request#3008</a></li>
<li>build(deps-dev): bump prettier from 3.3.2 to 3.3.3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3018">peter-evans/create-pull-request#3018</a></li>
<li>build(deps-dev): bump ts-jest from 29.2.0 to 29.2.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3019">peter-evans/create-pull-request#3019</a></li>
<li>build(deps-dev): bump eslint-plugin-prettier from 5.1.3 to 5.2.1 by
<a href="https://github.com/dependabot"><code>@​dependabot</code></a> in
<a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3035">peter-evans/create-pull-request#3035</a></li>
<li>build(deps-dev): bump <code>@​types/node</code> from 18.19.39 to
18.19.41 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3037">peter-evans/create-pull-request#3037</a></li>
<li>build(deps): bump undici from 6.19.2 to 6.19.4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3036">peter-evans/create-pull-request#3036</a></li>
<li>build(deps-dev): bump ts-jest from 29.2.2 to 29.2.3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3038">peter-evans/create-pull-request#3038</a></li>
<li>build(deps-dev): bump <code>@​types/node</code> from 18.19.41 to
18.19.42 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3070">peter-evans/create-pull-request#3070</a></li>
<li>build(deps): bump undici from 6.19.4 to 6.19.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3086">peter-evans/create-pull-request#3086</a></li>
<li>build(deps-dev): bump <code>@​types/node</code> from 18.19.42 to
18.19.43 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3087">peter-evans/create-pull-request#3087</a></li>
<li>build(deps-dev): bump ts-jest from 29.2.3 to 29.2.4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3088">peter-evans/create-pull-request#3088</a></li>
<li>build(deps): bump undici from 6.19.5 to 6.19.7 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3145">peter-evans/create-pull-request#3145</a></li>
<li>build(deps-dev): bump <code>@​types/node</code> from 18.19.43 to
18.19.44 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3144">peter-evans/create-pull-request#3144</a></li>
<li>Update distribution by <a
href="https://github.com/actions-bot"><code>@​actions-bot</code></a> in
<a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3154">peter-evans/create-pull-request#3154</a></li>
<li>build(deps): bump undici from 6.19.7 to 6.19.8 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3213">peter-evans/create-pull-request#3213</a></li>
<li>build(deps-dev): bump <code>@​types/node</code> from 18.19.44 to
18.19.45 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3214">peter-evans/create-pull-request#3214</a></li>
<li>Update distribution by <a
href="https://github.com/actions-bot"><code>@​actions-bot</code></a> in
<a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3221">peter-evans/create-pull-request#3221</a></li>
<li>build(deps-dev): bump eslint-import-resolver-typescript from 3.6.1
to 3.6.3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3255">peter-evans/create-pull-request#3255</a></li>
<li>build(deps-dev): bump <code>@​types/node</code> from 18.19.45 to
18.19.46 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3254">peter-evans/create-pull-request#3254</a></li>
<li>build(deps-dev): bump ts-jest from 29.2.4 to 29.2.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3256">peter-evans/create-pull-request#3256</a></li>
<li>v7 - signed commits by <a
href="https://github.com/peter-evans"><code>@​peter-evans</code></a> in
<a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3057">peter-evans/create-pull-request#3057</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/rustycl0ck"><code>@​rustycl0ck</code></a> made
their first contribution in <a
href="https://redirect.github.com/peter-evans/create-pull-request/pull/3057">peter-evans/create-pull-request#3057</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/peter-evans/create-pull-request/compare/v6.1.0...v7.0.0">https://github.com/peter-evans/create-pull-request/compare/v6.1.0...v7.0.0</a></p>
<h2>Create Pull Request v6.1.0</h2>
<p>✨ Adds <code>pull-request-branch</code> as an action output.</p>
<h2>What's Changed</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/peter-evans/create-pull-request/commit/5e914681df9dc83aa4e4905692ca88beb2f9e91f"><code>5e91468</code></a>
fix: support symlinks when commit signing (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/3359">#3359</a>)</li>
<li><a
href="https://github.com/peter-evans/create-pull-request/commit/2f38cd26bfebe301a5ee90bdd6550a69dc3ef23f"><code>2f38cd2</code></a>
fix: support submodules when commit signing (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/3354">#3354</a>)</li>
<li><a
href="https://github.com/peter-evans/create-pull-request/commit/7a8aeac749996aed943101d8e7dfb0cecc06197e"><code>7a8aeac</code></a>
build(deps-dev): bump eslint from 8.57.0 to 8.57.1 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/3344">#3344</a>)</li>
<li><a
href="https://github.com/peter-evans/create-pull-request/commit/d39d596a7720fc2c61c9aa5503097fb553431b5e"><code>d39d596</code></a>
build(deps-dev): bump <code>@​types/jest</code> from 29.5.12 to 29.5.13
(<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/3343">#3343</a>)</li>
<li><a
href="https://github.com/peter-evans/create-pull-request/commit/f6f978fd3dc86c443f758f603d22dc554762c832"><code>f6f978f</code></a>
docs: correct suggestion for bot setup (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/3342">#3342</a>)</li>
<li><a
href="https://github.com/peter-evans/create-pull-request/commit/6cd32fd93684475c31847837f87bb135d40a2b79"><code>6cd32fd</code></a>
fix: disable abbreviated commit shas in diff (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/3337">#3337</a>)</li>
<li><a
href="https://github.com/peter-evans/create-pull-request/commit/d121e62763d8cc35b5fb1710e887d6e69a52d3a4"><code>d121e62</code></a>
fix: disable diff detection for renames and copies (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/3330">#3330</a>)</li>
<li><a
href="https://github.com/peter-evans/create-pull-request/commit/f4d66f4d5a5a7e65a185463192800c32d296ac6d"><code>f4d66f4</code></a>
build(deps-dev): bump typescript from 5.5.4 to 5.6.2 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/3319">#3319</a>)</li>
<li><a
href="https://github.com/peter-evans/create-pull-request/commit/488c869d17c8a5cb8a2f0a09471ed82c1d2a084f"><code>488c869</code></a>
build(deps-dev): bump <code>@​types/node</code> from 18.19.48 to
18.19.50 (<a
href="https://redirect.github.com/peter-evans/create-pull-request/issues/3320">#3320</a>)</li>
<li><a
href="https://github.com/peter-evans/create-pull-request/commit/5354f85616108575685a73a0ddd2f67c26a441c3"><code>5354f85</code></a>
docs: update readme</li>
<li>Additional commits viewable in <a
href="https://github.com/peter-evans/create-pull-request/compare/v6...v7">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=peter-evans/create-pull-request&package-manager=github_actions&previous-version=6&new-version=7)](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-10-01 22:17:24 -04:00
Tyler Wilding 07c224b966 New Crowdin updates (#3693) 2024-09-30 21:19:25 -04:00
Tyler Wilding 66c455225d g/j2: Fix subtitle setting persisting and add a toggle for the hint subtitles (#3689)
Fixes #3663
2024-09-30 20:19:23 -04:00
Tyler Wilding 5b8bb8fe23 game: dont filter resolutions in windowed mode (#3688)
I'll test this more thoroughly tomorrow, quick change to allow picking
resolutions that would normally be filtered out, while in windowed mode.
2024-09-30 20:18:01 -04:00
Hat Kid 614c5a663c custom levels: support vanilla skies and texture remapping tables (#3691)
This adds some new JSON entries to custom levels so they can support
vanilla sky textures and the texture remapping tables, allowing for
proper textures on objects that use `generic`, like dark eco pools or
dying enemies.

The comments explain it in more detail, but the gist is:

For skies:
- `sky` needs to be a vanilla level that has sky textures.
- The alpha tpage (fourth entry in `tpages`) needs to be that vanilla
level's alpha tpage (if `tex_remap` is the same level as `sky`, this
will be handled automatically).
- The tpage needs to be added to the custom level `.gd` and to
`textures` in the JSON.
- In `level-info.gc`, `sky` needs to be `#t`, your level's mood needs to
call `update-mood-sky-texture` (the default mood, `update-mood-default`,
handles this as an example) and `sun-fade` needs to be nonzero for the
sun to show up.

For `generic` textures:
- `tex_remap` needs to be the name of a vanilla level.
- When using a vanilla level's remap table, you need to adhere to the
order of the files in that level's `.gd` in your own level.
  - Code files are first.
- Then the tpages (in the order `tfrag`, `pris`, `shrub`, `alpha`,
`water`).
  - Then the art groups.
  - Lastly, the level file.
- The tpages need to be added to the `textures` in the JSON.
2024-09-30 17:18:28 +02:00
OpenGOAL BotandOpenGOALBot fedfb6fd09 CI: Periodic Controller Database Update (#3687)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-09-26 21:43:12 -04:00
Hat Kid 7de5eb9fc0 jak3: misc fixes (#3686)
- Fix global heap display in cheat mode
- Fix `tpl-watcher` NaNs after they fire their laser (`vf0` was being
clobbered) (Fixes #3684)
- Fix `artifact-race` talkers (Fixes #3685)
2024-09-23 18:41:34 +02:00
water111andwater111 f60a155c0f [jak3] Fix crash with volcano platforms (#3676)
Ended up being a simple fix to a stack type in rigid-body.

Co-authored-by: water111 <[email protected]>
2024-09-22 13:09:41 -04:00
water111andwater111 4e33746634 [jak3] Fix bomb bot bombs disappearing (#3674)
This is basically applying the same fix as `vector<-cspace!`, which
we've been doing since jak 1.

They often make bugs where they use bones before they are properly
initialized. On PS2, it's relatively harmless - it results in stuff
going to the origin for 1 frame (where it collides with nothing, since
the collide cache was filled somewhere else), then going back to normal.

On PC, using these uninitialized bones results in NaNs. This is because
`0 * (1 / w)` where `w = 0` done in the `update-transforms` is `NaN` on
PC, but 0 on PS2. These NaNs propagate to the velocity, and you get
stuck with everything being NaN.


![image](https://github.com/user-attachments/assets/f575fed5-4543-4f72-b7d1-c5c8be8036f8)

Co-authored-by: water111 <[email protected]>
2024-09-22 12:41:38 -04:00
Ima_Door 58467c50fc ubuntu Dockerfile fix a missing dependency (#3667)
adds libssl-dev to apt-get

i atleast had to add this for the docker image to work
2024-09-21 21:47:50 -04:00
Aloqas b6f25bf6d6 [jak2] english subtitle fixes (#3665) 2024-09-21 21:11:27 -04:00
OpenGOAL BotandOpenGOALBot 8d9966fd2c CI: Periodic Controller Database Update (#3666)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-09-21 14:54:08 -04:00
water111andwater111 fe29eae395 Background improvements for custom levels (#3672)
This only applies to the background for now:

- support for alpha for vertex colors in custom levels
- switch time of day palette generation from octree to k-d tree
- support for alpha masking in custom levels
- support for transparent textures
- support for envmap in custom levels

---------

Co-authored-by: water111 <[email protected]>
2024-09-21 11:39:50 -04:00
Tyler Wilding 431508aab1 cmake: handle the scenario of a commit having more than 1 tag (#3662) 2024-09-09 23:49:03 -04:00
OpenGOAL BotandOpenGOALBot 69d879f901 CI: Periodic Controller Database Update (#3661)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-09-09 23:26:54 -04:00
Matt Dallmeyer d82bb3fde8 Fix github release-pipeline so version tag is available for cmake (#3651)
Followup to
https://discord.com/channels/756287461377703987/1280601431975661599
where the v0.2.16 release is showing git SHA in the speedrun
verification text, instead of the version tag
2024-09-09 23:26:46 -04:00
water111andwater111 a39af394fb [jak2] Workaround for sound effects getting dropped (#3660)
Similar to the workaround added in jak 3, if too many sounds are
playing, a sound will be removed. If there are multiple instances of the
same sound being played, those will be removed first. Within that, older
sounds are removed first.

It's not exactly the same as the instance limits of 989snd, but it seems
to work well. It's at least better than what we had before.

Co-authored-by: water111 <[email protected]>
2024-09-08 14:47:12 -04:00
Hat Kid 7053090541 jak3: decomp bigmap, blit-displays, fix progress crash (#3657)
`bigmap` and `blit-displays` mostly work. `blit-displays` is still
missing all of the special effects that were added in Jak 3 (brightness
and contrast settings, screen blur effect, etc.).

`bigmap` is missing the player marker texture (`hud-target-marker`) for
some reason, it's part of `tpage-17` which is coming from
`progress-minimap` and should already be included. The icons also
currently stretch when using aspect ratios other than 4:3.

The progress menu now also works for the most part. The draw order is a
bit messed up because some code was initially drawing things with the
ocean bucket, which was changed to use `hud-draw-hud-alpha` instead for
now. The texture for the volume and brightness/contrast sliders still
looks wrong.

Fixes #3653
Fixes #3656
2024-09-07 14:18:30 +02:00
Hat Kid bc66d416b4 decompiler: call-parent-state-handler and suspend-for macros (#3625)
Also fix `hud-draw-pris2` bucket in Jak 3 to make subtitles work and
foreground HUD envmap.
2024-09-04 19:35:54 +02:00
Will d46e9fb8bb Use custom normals in model replacement (#3649)
A small change that makes the models look a lot better. 
Will likely cause a crash if imported model has no normal data, but
that's on the user to fix on their model.
2024-09-02 19:27:28 -04:00
Dillon Pentz ebd02b28a4 jak3: fix vagdir bit-field for msvc + clang on windows (#3643) 2024-09-01 09:30:03 -04:00
Matt Dallmeyer 4fd0a57046 Create abutton-idx enum, replace magic numbers across codebase (#3646)
Found out the hard way that the `abutton` array for pressure sensitivity
uses a different order than the `pad-buttons` enum, so I created a new
enum for abutton indexing.

I replaced any magic numbers across the codebase where it made sense,
e.g.
`(-> *cpad-list* cpads (-> self control unknown-cpad-info00 number)
abutton 6)`
becomes
`(-> *cpad-list* cpads (-> self control unknown-cpad-info00 number)
abutton (abutton-idx x))`
2024-09-01 09:29:23 -04:00
dependabot[bot] 7b7885e7a8 build(deps): bump hendrikmuhs/ccache-action from 1.2.13 to 1.2.14 (#3650)
Bumps
[hendrikmuhs/ccache-action](https://github.com/hendrikmuhs/ccache-action)
from 1.2.13 to 1.2.14.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/hendrikmuhs/ccache-action/releases">hendrikmuhs/ccache-action's
releases</a>.</em></p>
<blockquote>
<h2>v1.2.14</h2>
<h2>What's Changed</h2>
<ul>
<li>Add sccache to PATH after installation by <a
href="https://github.com/kendalharland"><code>@​kendalharland</code></a>
in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/204">hendrikmuhs/ccache-action#204</a></li>
<li>Make ccache-action respect environment variables by <a
href="https://github.com/TrentHouliston"><code>@​TrentHouliston</code></a>
in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/217">hendrikmuhs/ccache-action#217</a></li>
<li>updates</li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/kendalharland"><code>@​kendalharland</code></a>
made their first contribution in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/204">hendrikmuhs/ccache-action#204</a></li>
<li><a href="https://github.com/cclauss"><code>@​cclauss</code></a> made
their first contribution in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/213">hendrikmuhs/ccache-action#213</a></li>
<li><a
href="https://github.com/TrentHouliston"><code>@​TrentHouliston</code></a>
made their first contribution in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/217">hendrikmuhs/ccache-action#217</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/hendrikmuhs/ccache-action/compare/v1...v1.2.14">https://github.com/hendrikmuhs/ccache-action/compare/v1...v1.2.14</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/ed74d11c0b343532753ecead8a951bb09bb34bc9"><code>ed74d11</code></a>
Bump <code>@​types/node</code> from 22.0.0 to 22.1.0 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/222">#222</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/a92dd99d2cf20a1db8898b00bb383b234fb1cf15"><code>a92dd99</code></a>
Bump <code>@​types/node</code> from 20.14.11 to 22.0.0 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/220">#220</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/aa7d29411285c29f578109e54b7a8d8155c2fbb3"><code>aa7d294</code></a>
Bump typescript from 5.5.3 to 5.5.4 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/218">#218</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/6f0874030891bf49d844fff92b862568f093dabe"><code>6f08740</code></a>
Make ccache-action respect environment variables (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/217">#217</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/ed979992cda44142d976add1d5a7d6f39f7e8b67"><code>ed97999</code></a>
Bump <code>@​types/node</code> from 20.14.10 to 20.14.11 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/216">#216</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/ca1e5062f3378412bbfeb780d1ebe3c2a4913081"><code>ca1e506</code></a>
Bump actions/checkout from 2 to 4 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/214">#214</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/069136ab7ab2267ea6624fde73f80d7d472d323e"><code>069136a</code></a>
Bump <code>@​types/node</code> from 20.14.9 to 20.14.10 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/212">#212</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/3cf745af56c860cc76c89ffd830efec6aef03b56"><code>3cf745a</code></a>
Bump typescript from 5.5.2 to 5.5.3 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/211">#211</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/9a0cc152966f2c3f3df86a6e0364da1608924006"><code>9a0cc15</code></a>
Keep GitHub Actions up to date with GitHub's Dependabot (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/213">#213</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/b7c0e162a73e852cdd80bd368aa77e7801fce009"><code>b7c0e16</code></a>
Bump <code>@​types/node</code> from 20.14.8 to 20.14.9 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/210">#210</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/hendrikmuhs/ccache-action/compare/v1.2.13...v1.2.14">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=hendrikmuhs/ccache-action&package-manager=github_actions&previous-version=1.2.13&new-version=1.2.14)](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-09-01 09:26:37 -04:00
OpenGOAL BotandOpenGOALBot 8c71827974 CI: Periodic Controller Database Update (#3647)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-08-30 15:28:52 -04:00
Tyler Wilding 6c63a396c0 ci: simplify release workflow (#3642) 2024-08-21 22:57:40 -04:00
Matt Dallmeyer 8a6348594a Add more autosplit points for Jak 2 Any% (#3639)
Goes with https://github.com/open-goal/speedrunning/pull/21

Based on some of the autosplit points from the [comgold
sheet](https://docs.google.com/spreadsheets/d/1ZtceX0ZxCLkufVFQuCgVxptvmVgp6deHwPYWxUPi258/edit?gid=0#gid=0),
plus one after talking to samos to give a clean split for timing the
deload.

```
   (tomb-poles-poles uint8) ;; left tomb/daxter boulder start
   (fortress-save-friends-introduction uint8) ;; talk to torn (before rescue friends)
   (sewer-escort-get-gun uint8) ;; get peacemaker
   (forest-protect-introduction uint8) ;; talk to onin (protect samos)
   (forest-protect-meeting uint8) ;; talk to samos (protect samos)
```
2024-08-21 22:57:11 -04:00
Tyler Wilding 4c10b42841 game: add per-game app icons (#3634) 2024-08-16 16:01:03 -04:00
Matt Dallmeyer 9426683ae5 Extract merc models into individual glb files (#3632)
e.g. instead of just `beach-foreground.glb` and `beach-background.glb`,
you'd now get:
- `beach/babak-lod0.glb`
- `beach/babak-lod1.glb`
- `beach/babak-lod2.glb`
- `beach/barrel-lod0.glb`
- `beach/beach-background.glb`
- `beach/beachcam-lod0.glb`
- ... (42 other files)
- `beach/windmill-one-lod2.glb`

`common` models are also grouped into their own folder
2024-08-16 16:00:12 -04:00
water111andwater111 f2e7606f1b [build_actor] Add skeleton and animation support (#3638)
This adds a feature to `build_actor` to support importing skeletons and
animations from .glb files.

Multiple animations are handled and will use the name in the GLB. The
default `viewer` process will end up playing back the first animation.

There are a few limitations:
- You can only have around 100 bones. It is technically possibly to have
slightly more, but certain animations may fail to compress when there
are more than ~100 bones.
- Currently, all animations have 60 keyframes per second. This is a
higher quality than what is normally used. If animation size becomes
problematic, we could make this customizable somehow.
- There is no support for the `align` bone.

---------

Co-authored-by: water111 <[email protected]>
2024-08-16 11:25:53 -04:00
OpenGOAL BotandOpenGOALBot b0cd59e6ba CI: Periodic Controller Database Update (#3635)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-08-16 01:26:45 -04:00
AloqasandTyler Wilding 9d2a23effe Jak 2: Finnish translations (#3533)
Finnish translations for Jak 2. These include cutscenes and all game
text.

All subtitle timings for cutscenes as well as non-cutscenes have been
edited for a better flow and to fit the 4x3 ratio.
I've been working on these solo for the most part so any input from
other finns would be appreciated.

A few issues in the progress menu I mentioned in #3504 still persist

I couldn't figure out how to add Finnish to the options menu, so I'm
gonna need someone else to do that part. 💀
But I was able to add them to the debug menu.

I also increased subtitle heap so hopefully that doesn't break anything.

Fixes #3620

---------

Co-authored-by: Tyler Wilding <[email protected]>
2024-08-11 13:01:06 -04:00
Tyler Wilding 1ba3fa7cda g/j2: fix hud positioning when in mirror mode (#3630)
Fixes #3627


![image](https://github.com/user-attachments/assets/32bf500f-0679-47b4-b64f-f3de7a4f3fdf)
2024-08-09 23:24:13 -04:00
Tyler Wilding a7d1336899 ci: compile with master's goalc, but with the PR's changes (#3631)
Mistake lead to CI failures for PRs that modified goal_src (of course
the files are different than master!)
2024-08-09 00:18:14 -04:00
OpenGOAL BotandOpenGOALBot 879f8cb5a2 CI: Periodic Controller Database Update (#3629)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-08-05 14:01:05 -04:00
Tyler Wilding 8b7e0bde53 game: ensure the default game-size is also valid when initializing the pc-settings.gc file (#3624)
Also saves out the default `pc-settings.gc` file so it's less confusing
_and_ so we can request it from users to actually see what it's doing.

The fix in the last release was only to fix bad `game-size` values when
_loading_ the file. But if you don't have a file, it picks a default.

Right now it picks that default by:
1. Your largest reported resolution
2. If that fails, the one that is currently set

In reality this scenario can never really happen (if you have a set
resolution, it will be one of the reported ones). However what can
happen is for SDL to be misinformed by bad display/monitor drivers/the
OS and be given "supported" resolutions that aren't actually supported.
For example some users have a 4K resolution as their highest, despite
them using a 1080p monitor.

The solution is to not blindly assume the largest resolution is valid,
instead use the one the user already has set.

I'm also now filtering out resolutions by refresh rate, as perhaps this
also caused a problem. ie. the monitor supports a resolution if the
refresh rate is lowered, but it's currently set high (at 144hz for
example).
2024-08-03 14:57:07 -04:00
Tyler Wilding a13b0dce45 ci: Add workflow that compares the compiled output between the PR and master (#3626)
Fixes #3063
2024-08-03 02:42:34 -04:00
3774 changed files with 579938 additions and 95305 deletions

No files matched your search

+2 -1
View File
@@ -1,6 +1,7 @@
name: "\U0001F41B Jak 1 Bug Report"
description: Create a bug report for Jak 1.
labels: ["bug", "jak1"]
labels: ["jak1"]
type: 'bug'
body:
- type: checkboxes
attributes:
+2 -1
View File
@@ -1,6 +1,7 @@
name: "\U0001F41B Jak 2 Bug Report"
description: Create a bug report for Jak 2.
labels: ["bug", "jak2"]
labels: ["jak2"]
type: 'bug'
body:
- type: checkboxes
attributes:
@@ -1,4 +1,10 @@
{
"3990": {
"msg": "Provided invalid or missing arguments"
},
"3991": {
"msg": "Input path(s) do not exist"
},
"4000": {
"msg": "Validation Failed: Cannot locate ELF"
},
+7 -9
View File
@@ -49,14 +49,12 @@ jobs:
name: "🍎 MacOS"
uses: ./.github/workflows/macos-build.yaml
with:
cmakePreset: "Release-macos-clang"
cmakePreset: "Release-macos-x86_64-clang"
cachePrefix: ""
# Q4 2023 there will hopefully be native arm64 runners
# https://github.com/github/roadmap/issues/528
# build_macos_arm:
# name: "🍎 MacOS"
# uses: ./.github/workflows/macos-build-arm.yaml
# with:
# cmakePreset: "Release-macos-clang"
# cachePrefix: ""
build_macos_arm:
name: "🍎 MacOS"
uses: ./.github/workflows/macos-build-arm.yaml
with:
cmakePreset: "Release-macos-x86_64-clang"
cachePrefix: ""
@@ -0,0 +1,98 @@
name: Compilation Check
on:
pull_request:
branches:
- master
jobs:
build:
name: Compare
runs-on: ubuntu-20.04
timeout-minutes: 60
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
ref: master
- name: Install Package Dependencies
run: |
sudo apt update
sudo apt install build-essential cmake \
clang gcc g++ lcov make nasm libxrandr-dev \
libxinerama-dev libxcursor-dev libpulse-dev \
libxi-dev zip ninja-build libgl1-mesa-dev libssl-dev
- name: Setup sccache
uses: hendrikmuhs/[email protected]
with:
variant: sccache
key: linux-ubuntu-20.04--Release-linux-clang-static-${{ github.sha }}
restore-keys: linux-ubuntu-20.04--Release-linux-clang-static
max-size: 1000M
- name: CMake Generation (master)
env:
CC: clang
CXX: clang++
run: |
cmake -B build --preset=Release-linux-clang-static \
-DCMAKE_C_COMPILER_LAUNCHER=sccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache
- name: Build goalc (master)
run: |
cmake --build build --parallel $((`nproc`)) --target goalc
mv ./build ./build.master
- name: Checkout PR
uses: actions/checkout@v4
with:
clean: "false"
- name: CMake Generation (PR)
env:
CC: clang
CXX: clang++
run: |
cmake -B build --preset=Release-linux-clang-static \
-DCMAKE_C_COMPILER_LAUNCHER=sccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache
- name: Build goalc (PR)
run: cmake --build build --parallel $((`nproc`)) --target goalc
- name: Compile and preserve (master)
run: |
./build.master/goalc/goalc --game jak1 --cmd "(make-group \"all-code\")"
./build.master/goalc/goalc --game jak2 --cmd "(make-group \"all-code\")"
./build.master/goalc/goalc --game jak3 --cmd "(make-group \"all-code\")"
mv ./out/jak1/obj ./out/jak1/obj.master
mv ./out/jak2/obj ./out/jak2/obj.master
mv ./out/jak3/obj ./out/jak3/obj.master
- name: Compile and preserve (PR)
run: |
./build/goalc/goalc --game jak1 --cmd "(make-group \"all-code\")"
./build/goalc/goalc --game jak2 --cmd "(make-group \"all-code\")"
./build/goalc/goalc --game jak3 --cmd "(make-group \"all-code\")"
mv ./out/jak1/obj ./out/jak1/obj.pr
mv ./out/jak2/obj ./out/jak2/obj.pr
mv ./out/jak3/obj ./out/jak3/obj.pr
- name: Compare Results and Produce Report
run: |
ls -l ./out/jak1
ls -l ./out/jak2
ls -l ./out/jak3
set +e
python ./scripts/gsrc/compare-compilation-outputs.py --base "./out/jak1/obj.master,./out/jak2/obj.master,./out/jak3/obj.master" --compare "./out/jak1/obj.pr,./out/jak2/obj.pr,./out/jak3/obj.pr" --markdown
SCRIPT_EXIT_CODE=$?
cat ./comp-diff-report.md >> $GITHUB_STEP_SUMMARY
if [ "$SCRIPT_EXIT_CODE" -ne 0 ]; then
exit 1
fi
-35
View File
@@ -1,35 +0,0 @@
name: 🏭 Draft Release
on:
workflow_dispatch:
inputs:
bump:
description: 'Semver Bump Type'
required: true
default: 'patch'
type: choice
options:
- patch
- minor
- major
jobs:
cut-release:
runs-on: ubuntu-latest
steps:
# Docs - https://github.com/mathieudutour/github-tag-action
# Workflows cannot trigger other workflows implicitly
# - https://github.community/t/github-actions-workflow-not-triggering-with-tag-push/17053/7
- name: Bump Version and Push Tag
if: github.repository == 'open-goal/jak-project'
id: tag_version
uses: mathieudutour/[email protected]
with:
github_token: ${{ secrets.BOT_PAT }}
tag_prefix: v
default_bump: ${{ github.event.inputs.bump }}
- name: Create Release
env:
GITHUB_TOKEN: ${{ secrets.BOT_PAT }}
run: gh release create ${{ steps.tag_version.outputs.new_tag }} --generate-notes --draft --repo open-goal/jak-project
+11 -1
View File
@@ -21,9 +21,19 @@ jobs:
timeout-minutes: 60
steps:
# minimal checkout if we're NOT uploading artifacts
- name: Checkout Repository
if: ${{ ! inputs.uploadArtifacts }}
uses: actions/checkout@v4
# full checkout with tags if we ARE uploading artifacts
- name: Checkout Repository with Tags
if: ${{ inputs.uploadArtifacts }}
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Install Package Dependencies
run: |
sudo apt update
@@ -33,7 +43,7 @@ jobs:
libxi-dev zip ninja-build libgl1-mesa-dev libssl-dev
- name: Setup sccache
uses: hendrikmuhs/[email protected]3
uses: hendrikmuhs/[email protected]6
with:
variant: sccache
key: linux-ubuntu-20.04-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
sudo update-alternatives --set g++ /usr/bin/g++-10
- name: Setup sccache
uses: hendrikmuhs/[email protected]3
uses: hendrikmuhs/[email protected]6
with:
variant: sccache
key: linux-ubuntu-20.04-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
+6 -9
View File
@@ -13,25 +13,22 @@ on:
jobs:
build:
name: ARM
runs-on: macos-12
runs-on: macos-15
timeout-minutes: 120
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Set up ARM64 environment
run: sudo softwareupdate --install-rosetta --agree-to-license
- name: Install Package Dependencies
run: arch -arm64 brew install cmake ninja
run: brew install cmake ninja nasm
- name: Setup sccache
uses: hendrikmuhs/[email protected]3
uses: hendrikmuhs/[email protected]6
with:
variant: sccache
key: macos-12-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
restore-keys: macos-12-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}
key: macos-15-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
restore-keys: macos-15-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}
max-size: 1000M
- name: CMake Generation
@@ -52,7 +49,7 @@ jobs:
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: opengoal-macos-${{ inputs.cachePrefix }}
name: opengoal-macos-arm-${{ inputs.cachePrefix }}
if-no-files-found: error
path: |
./build/goalc/goalc
+14 -4
View File
@@ -17,22 +17,32 @@ on:
jobs:
build:
name: Intel
runs-on: macos-12
runs-on: macos-13
timeout-minutes: 120
steps:
# minimal checkout if we're NOT uploading artifacts
- name: Checkout Repository
if: ${{ ! inputs.uploadArtifacts }}
uses: actions/checkout@v4
# full checkout with tags if we ARE uploading artifacts
- name: Checkout Repository with Tags
if: ${{ inputs.uploadArtifacts }}
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Install Package Dependencies
run: brew install cmake nasm ninja
- name: Setup sccache
uses: hendrikmuhs/[email protected]3
uses: hendrikmuhs/[email protected]6
with:
variant: sccache
key: macos-12-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
restore-keys: macos-12-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}
key: macos-13-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
restore-keys: macos-13-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}
max-size: 1000M
- name: CMake Generation
+81 -12
View File
@@ -1,13 +1,52 @@
name: 🏭 Release Pipeline
name: 🏭 Draft Release
on:
push:
tags:
- v*
workflow_dispatch:
inputs:
bump:
description: 'Semver Bump Type'
required: true
default: 'patch'
type: choice
options:
- patch
- minor
- major
permissions:
contents: write
jobs:
cut_release:
name: Cut Release
runs-on: ubuntu-latest
outputs:
new_tag: ${{ steps.set_tag.outputs.new_tag }}
steps:
# Docs - https://github.com/mathieudutour/github-tag-action
- name: Bump Version and Push Tag
if: github.repository == 'open-goal/jak-project'
id: tag_version
uses: mathieudutour/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
tag_prefix: v
default_bump: ${{ github.event.inputs.bump }}
- name: Create Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release create ${{ steps.tag_version.outputs.new_tag }} --generate-notes --draft --repo ${{ github.repository }}
- name: Output new tag
id: set_tag
run: |
echo "new_tag=${{ steps.tag_version.outputs.new_tag }}" >> $GITHUB_OUTPUT
# Windows
build_windows_clang:
needs:
- cut_release
name: "🖥️ Windows"
uses: ./.github/workflows/windows-build-clang.yaml
with:
@@ -18,6 +57,8 @@ jobs:
# Linux
build_linux_clang:
needs:
- cut_release
name: "🐧 Linux"
uses: ./.github/workflows/linux-build-clang.yaml
with:
@@ -28,25 +69,42 @@ jobs:
# macOS
build_macos_intel:
needs:
- cut_release
name: "🍎 MacOS"
uses: ./.github/workflows/macos-build.yaml
with:
cmakePreset: "Release-macos-clang-static"
cmakePreset: "Release-macos-x86_64-clang-static"
cachePrefix: "static"
uploadArtifacts: true
secrets: inherit
build_macos_arm:
needs:
- cut_release
name: "🍎 MacOS"
uses: ./.github/workflows/macos-build.yaml
with:
cmakePreset: "Release-macos-x86_64-clang-static"
cachePrefix: "static-arm"
uploadArtifacts: true
secrets: inherit
# Upload the Artifacts
upload_artifacts:
if: github.repository == 'open-goal/jak-project'
needs:
- cut_release
- build_windows_clang
- build_linux_clang
- build_macos_intel
- build_macos_arm
name: "Upload Artifacts"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.cut_release.outputs.new_tag }}
- name: Prepare Artifact Folder
run: mkdir -p ./ci-artifacts/final
@@ -64,7 +122,7 @@ jobs:
mkdir -p ./ci-artifacts/linux
./.github/scripts/releases/extract_build_unix.sh ./ci-artifacts/linux ./ci-artifacts/opengoal-linux-static ./
pushd ci-artifacts/linux
TAG_VAL=$(echo ${{ github.REF }} | awk -F'refs/tags/' '{print $2}')
TAG_VAL=${{ needs.cut_release.outputs.new_tag }}
tar czf ../final/opengoal-linux-${TAG_VAL}.tar.gz .
popd
chmod +x ./ci-artifacts/opengoal-linux-static/lsp/lsp
@@ -74,31 +132,42 @@ jobs:
run: |
mkdir -p ./ci-artifacts/windows
./.github/scripts/releases/extract_build_windows.sh ./ci-artifacts/windows ./ci-artifacts/opengoal-windows-static ./
TAG_VAL=$(echo ${{ github.REF }} | awk -F'refs/tags/' '{print $2}')
TAG_VAL=${{ needs.cut_release.outputs.new_tag }}
7z a -tzip ./ci-artifacts/final/opengoal-windows-${TAG_VAL}.zip ./ci-artifacts/windows/*
cp ./ci-artifacts/opengoal-windows-static/lsp.exe ./ci-artifacts/final/opengoal-lsp-windows-${TAG_VAL}.exe
- name: Prepare macOS Build Assets
- name: Prepare Intel macOS Build Assets
run: |
mkdir -p ./ci-artifacts/macos
./.github/scripts/releases/extract_build_unix.sh ./ci-artifacts/macos ./ci-artifacts/opengoal-macos-static ./
pushd ci-artifacts/macos
TAG_VAL=$(echo ${{ github.REF }} | awk -F'refs/tags/' '{print $2}')
TAG_VAL=${{ needs.cut_release.outputs.new_tag }}
tar czf ../final/opengoal-macos-intel-${TAG_VAL}.tar.gz .
popd
chmod +x ./ci-artifacts/opengoal-macos-static/lsp/lsp
cp ./ci-artifacts/opengoal-macos-static/lsp/lsp ./ci-artifacts/final/opengoal-lsp-macos-intel-${TAG_VAL}.bin
- name: Prepare ARM macOS Build Assets
run: |
mkdir -p ./ci-artifacts/macos-arm
./.github/scripts/releases/extract_build_unix.sh ./ci-artifacts/macos-arm ./ci-artifacts/opengoal-macos-static-arm ./
pushd ci-artifacts/macos-arm
TAG_VAL=${{ needs.cut_release.outputs.new_tag }}
tar czf ../final/opengoal-macos-arm-${TAG_VAL}.tar.gz .
popd
chmod +x ./ci-artifacts/opengoal-macos-static-arm/lsp/lsp
cp ./ci-artifacts/opengoal-macos-static-arm/lsp/lsp ./ci-artifacts/final/opengoal-lsp-macos-arm-${TAG_VAL}.bin
- name: Upload Assets
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_VAL=$(echo ${{ github.REF }} | awk -F'refs/tags/' '{print $2}')
TAG_VAL=${{ needs.cut_release.outputs.new_tag }}
gh release upload "${TAG_VAL}" ${{ github.WORKSPACE }}/ci-artifacts/final/* --repo open-goal/jak-project --clobber
- name: Publish Release
env:
GITHUB_TOKEN: ${{ secrets.BOT_PAT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TAG_VAL=$(echo ${{ github.REF }} | awk -F'refs/tags/' '{print $2}')
TAG_VAL=${{ needs.cut_release.outputs.new_tag }}
gh release edit ${TAG_VAL} --draft=false --repo open-goal/jak-project
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
wget -O ./game/assets/sdl_controller_db.txt https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.BOT_PAT }}
author: 'OpenGOALBot <[email protected]>'
+11 -1
View File
@@ -22,9 +22,19 @@ jobs:
timeout-minutes: 60
steps:
# minimal checkout if we're NOT uploading artifacts
- name: Checkout Repository
if: ${{ ! inputs.uploadArtifacts }}
uses: actions/checkout@v4
# full checkout with tags if we ARE uploading artifacts
- name: Checkout Repository with Tags
if: ${{ inputs.uploadArtifacts }}
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- name: Install NASM
# TODO - Simplify this with just the first command once choco 2.0 rolls out everywhere
run: |
@@ -36,7 +46,7 @@ jobs:
}
- name: Setup sccache
uses: hendrikmuhs/[email protected]3
uses: hendrikmuhs/[email protected]6
with:
variant: sccache
key: windows-2022-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
}
- name: Setup sccache
uses: hendrikmuhs/[email protected]3
uses: hendrikmuhs/[email protected]6
with:
variant: sccache
key: windows-2022-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
+5 -2
View File
@@ -1,6 +1,7 @@
# logs
/log
prof.json
/gpu-test.json
# for CMake
/Testing
@@ -9,7 +10,8 @@ prof.json
cmake-build-debug/*
cmake-build-debug--o0/*
.idea/*
build/*
build/
build.master/
/decompiler_out*
logs/*
profile_data/*
@@ -32,6 +34,7 @@ linux-default/
*.bin
*.log
*.p2s
out/
savestate-out/
savestate_out/
failures/
@@ -39,6 +42,7 @@ ee-results*.json
search-results.json
.env
/search-results.json
comp-diff-report.md
# graphics debug
debug_out/
@@ -67,7 +71,6 @@ custom_assets/jak3/merc_replacements/*
svnrev.h
common/versions/revision.h
ci-artifacts/
out/build/
__pycache__/
# sqlite stuff
+13
View File
@@ -138,6 +138,19 @@
"-debug"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - GPU Test",
"args": [
"-v",
"--gpu-test",
"opengl",
"--gpu-test-out-path",
"./gpu-test.json"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
+10 -1
View File
@@ -2,6 +2,7 @@
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(jak)
include(CTest)
@@ -43,6 +44,10 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
-Wall \
-Wno-c++11-narrowing \
-Wno-c++98-compat \
-Wno-deprecated-this-capture \
-Wno-missing-field-initializers \
-Wno-sign-compare \
-Wno-ignored-qualifiers \
-O3 \
-D_CRT_SECURE_NO_WARNINGS")
@@ -52,7 +57,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# Note: this is only _reserved_ memory, not necessarily _committed_ memory
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LDFLAGS} -Xlinker /STACK:16000000")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -g -Wextra")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb -g")
endif()
# additional c++ and linker flags for release mode for our projects
@@ -283,6 +288,10 @@ include(test/CMakeLists.txt)
build_third_party_lib(lzokay lzokay)
build_third_party_lib(stb_image stb_image)
# build draco library for tinygltf compression support
include_directories(third-party/draco/src)
add_subdirectory(third-party/draco)
add_compile_definitions(TINYGLTF_ENABLE_DRACO)
build_third_party_lib(tiny_gltf tiny_gltf)
build_third_party_lib(xdelta3 xdelta3)
+40 -8
View File
@@ -78,6 +78,22 @@
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install/${presetName}"
}
},
{
"name": "base-macos-arm64",
"hidden": true,
"cacheVariables": {
"CMAKE_APPLE_SILICON_PROCESSOR": "arm64",
"CMAKE_OSX_ARCHITECTURES": "arm64"
}
},
{
"name": "base-macos-x86_64",
"hidden": true,
"cacheVariables": {
"CMAKE_APPLE_SILICON_PROCESSOR": "x86_64",
"CMAKE_OSX_ARCHITECTURES": "x86_64"
}
},
{
"name": "base-clang",
"hidden": true,
@@ -159,16 +175,32 @@
"inherits": ["base-linux-release", "base-clang"]
},
{
"name": "Release-macos-clang",
"displayName": "MacOS Release (clang)",
"description": "Build with Clang as Release without Debug Symbols",
"inherits": ["base-macos-release", "base-clang"]
"name": "Release-macos-arm64-clang",
"displayName": "MacOS ARM64 Release (clang)",
"description": "Build for ARM64 with Clang as Release without Debug Symbols",
"inherits": ["base-macos-release", "base-macos-arm64", "base-clang"]
},
{
"name": "Release-macos-clang-static",
"displayName": "MacOS Static Release (clang)",
"description": "Build with Clang as Release without Debug Symbols but statically linked",
"inherits": ["base-macos-release", "base-clang"],
"name": "Release-macos-x86_64-clang",
"displayName": "MacOS x86_64 Release (clang)",
"description": "Build for x86_64 with Clang as Release without Debug Symbols",
"inherits": ["base-macos-release", "base-macos-x86_64", "base-clang"]
},
{
"name": "Release-macos-arm64-clang-static",
"displayName": "MacOS ARM64 Static Release (clang)",
"description": "Build for ARM64 with Clang as Release without Debug Symbols but statically linked",
"inherits": ["base-macos-release", "base-macos-arm64", "base-clang"],
"cacheVariables": {
"STATICALLY_LINK": "true",
"ZYDIS_BUILD_SHARED_LIB": "OFF"
}
},
{
"name": "Release-macos-x86_64-clang-static",
"displayName": "MacOS x86_64 Static Release (clang)",
"description": "Build for x86_64 with Clang as Release without Debug Symbols but statically linked, requires MacOS Sequoia",
"inherits": ["base-macos-release", "base-macos-x86_64", "base-clang"],
"cacheVariables": {
"STATICALLY_LINK": "true",
"ZYDIS_BUILD_SHARED_LIB": "OFF"
+1 -1
View File
@@ -1,6 +1,6 @@
ISC License
Copyright (c) 2020-2022 OpenGOAL Team
Copyright (c) 2020-2025 OpenGOAL Team
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
+13 -11
View File
@@ -72,7 +72,7 @@ Our objectives are:
We support both Linux and Windows on x86-64.
> We do not support, or plan to support the ARM architecture. This means that this will not run on devices such as an M1 Mac or a mobile device.
> We do not support, or plan to support the ARM architecture. This means that this will not run on devices such as a mobile device.
### Current Status
@@ -127,7 +127,7 @@ Unfortunately you'll still need task runner on your local machine to run the gam
Install packages and init repository:
```sh
sudo apt install gcc make cmake build-essential g++ nasm clang-format libxrandr-dev libxinerama-dev libxcursor-dev libpulse-dev libxi-dev python libgl1-mesa-dev libssl-dev
sudo apt install gcc make cmake ninja-build build-essential g++ nasm clang-format libxrandr-dev libxinerama-dev libxcursor-dev libpulse-dev libxi-dev python libgl1-mesa-dev libssl-dev
sudo sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
```
@@ -235,7 +235,7 @@ Then build the entire project as `Windows Release (clang)`. You can also press C
### MacOS
> NOTE: At this time you can only run the game on macOS if you have an Intel processor.
> NOTE: Running the game requires an Apple Silicon Mac running macOS Sequoia, or an Intel Mac.
Ensure that you have Xcode command line tools installed (this installs things like Apple Clang). If you don't, you can run the following command:
@@ -243,23 +243,25 @@ Ensure that you have Xcode command line tools installed (this installs things li
xcode-select --install
```
#### Intel Based
On Apple Silicon, Rosetta 2 also must be installed:
```bash
softwareupdate --install-rosetta
```
#### Building for x86_64
```bash
brew install go-task/tap/go-task
brew install cmake nasm ninja go-task clang-format
cmake -B build --preset=Release-macos-clang
cmake -B build --preset=Release-macos-x86_64-clang
cmake --build build --parallel $((`sysctl -n hw.logicalcpu`))
```
#### Apple Silicon
**Not Supported at This Time**
#### Building for ARM64 (experimental, unsupported)
```bash
brew install go-task/tap/go-task
brew install cmake ninja go-task clang-format
cmake -B build --preset=Release-macos-clang
cmake -B build --preset=Release-macos-arm64-clang
cmake --build build --parallel $((`sysctl -n hw.logicalcpu`))
```
+44 -29
View File
@@ -10,33 +10,33 @@ dotenv:
tasks:
# SETTINGS / CONFIGURATION
settings:
- 'python ./scripts/tasks/update-env.py --info'
- '{{.PYTHON}} ./scripts/tasks/update-env.py --info'
set-game-jak1:
- 'python ./scripts/tasks/update-env.py --game jak1'
- '{{.PYTHON}} ./scripts/tasks/update-env.py --game jak1'
set-game-jak2:
- 'python ./scripts/tasks/update-env.py --game jak2'
- '{{.PYTHON}} ./scripts/tasks/update-env.py --game jak2'
set-game-jak3:
- 'python ./scripts/tasks/update-env.py --game jak3'
- '{{.PYTHON}} ./scripts/tasks/update-env.py --game jak3'
set-decomp-ntscv1:
desc: "aka black label"
cmds:
- 'python ./scripts/tasks/update-env.py --decomp_config ntscv1'
- '{{.PYTHON}} ./scripts/tasks/update-env.py --decomp_config ntscv1'
set-decomp-ntscv2:
desc: "aka red label"
cmds:
- 'python ./scripts/tasks/update-env.py --decomp_config ntscv2'
- '{{.PYTHON}} ./scripts/tasks/update-env.py --decomp_config ntscv2'
set-decomp-pal:
desc: "PAL region version"
cmds:
- 'python ./scripts/tasks/update-env.py --decomp_config pal'
- '{{.PYTHON}} ./scripts/tasks/update-env.py --decomp_config pal'
set-decomp-ntscjp:
desc: "NTSC-J region version"
cmds:
- 'python ./scripts/tasks/update-env.py --decomp_config ntscjp'
- '{{.PYTHON}} ./scripts/tasks/update-env.py --decomp_config ntscjp'
set-decomp-ntscko:
desc: "NTSC-K region version"
cmds:
- 'python ./scripts/tasks/update-env.py --decomp_config ntscko'
- '{{.PYTHON}} ./scripts/tasks/update-env.py --decomp_config ntscko'
# GENERAL
extract:
desc: "Extracts the game's assets from './iso_data' with the set decompiler config"
@@ -67,6 +67,14 @@ tasks:
cmds:
- "{{.GK_BIN_RELEASE_DIR}}/gk -v --game {{.GAME}} -- -fakeiso -debug"
# DEVELOPMENT
gen-cmake:
desc: "Generate the CMake"
cmds:
- "cmake -B build --preset={{.CMAKE_PRESET}}"
build:
desc: "Build the project using the generated CMake"
cmds:
- "cmake --build build --parallel {{.CMAKE_NUM_THREADS}}"
repl:
desc: "Start the REPL"
preconditions:
@@ -83,9 +91,9 @@ tasks:
format:
desc: "Format code"
cmds:
- cmd: python ./scripts/cpp/format-includes.py
- cmd: python ./scripts/ci/lint-trailing-whitespace.py --fix
- cmd: python ./third-party/run-clang-format/run-clang-format.py -r common decompiler game goalc test tools lsp -i
- cmd: '{{.PYTHON}} ./scripts/cpp/format-includes.py'
- cmd: '{{.PYTHON}} ./scripts/ci/lint-trailing-whitespace.py --fix'
- cmd: '{{.PYTHON}} ./third-party/run-clang-format/run-clang-format.py -r common decompiler game goalc test tools lsp -i'
- task: format-json
format-gsrc:
desc: "Run formatter on gsrc file"
@@ -103,28 +111,28 @@ tasks:
- "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler \"./decompiler/config/{{.DECOMP_CONFIG}}\" \"./iso_data\" \"./decompiler_out\" --version \"{{.DECOMP_CONFIG_VERSION}}\" --config-override '{\"decompile_code\": true, \"levels_extract\": false, \"allowed_objects\": [\"{{.FILE}}\"]}'"
decomp-clean:
cmds:
- python ./scripts/tasks/clean-decomp.py --game "{{.GAME}}"
- '{{.PYTHON}} ./scripts/tasks/clean-decomp.py --game "{{.GAME}}"'
lint-gsrc-file:
cmds:
- python ./scripts/gsrc/lint-gsrc-file.py --game {{.GAME}} --file "{{.FILE}}"
- '{{.PYTHON}} ./scripts/gsrc/lint-gsrc-file.py --game {{.GAME}} --file "{{.FILE}}"'
update-gsrc:
cmds:
- python ./scripts/gsrc/update-gsrc-via-refs.py --game "{{.GAME}}" --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler" --decompiler_config {{.DECOMP_CONFIG}} --version {{.DECOMP_CONFIG_VERSION}}
- '{{.PYTHON}} ./scripts/gsrc/update-gsrc-via-refs.py --game "{{.GAME}}" --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler" --decompiler_config {{.DECOMP_CONFIG}} --version {{.DECOMP_CONFIG_VERSION}}'
update-gsrc-glob:
cmds:
- python ./scripts/gsrc/update-gsrc-via-refs.py --game "{{.GAME}}" --file_pattern "{{.GLOB}}" --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler" --decompiler_config {{.DECOMP_CONFIG}} --version {{.DECOMP_CONFIG_VERSION}}
- '{{.PYTHON}} ./scripts/gsrc/update-gsrc-via-refs.py --game "{{.GAME}}" --file_pattern "{{.GLOB}}" --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler" --decompiler_config {{.DECOMP_CONFIG}} --version {{.DECOMP_CONFIG_VERSION}}'
update-gsrc-file:
cmds:
- task: decomp-file
- python ./scripts/gsrc/update-from-decomp.py --game "{{.GAME}}" --file "{{.FILE}}"
- '{{.PYTHON}} ./scripts/gsrc/update-from-decomp.py --game "{{.GAME}}" --file "{{.FILE}}"'
- task: lint-gsrc-file
copy-common-naming:
cmds:
- python ./scripts/gsrc/copy-common-naming.py --file "{{.FILE}}" --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler"
- '{{.PYTHON}} ./scripts/gsrc/copy-common-naming.py --file "{{.FILE}}" --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler"'
- task: format-json
copy-common-naming-from-refs:
cmds:
- python ./scripts/gsrc/copy-common-naming.py --update-names-from-refs --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler"
- '{{.PYTHON}} ./scripts/gsrc/copy-common-naming.py --update-names-from-refs --decompiler "{{.DECOMP_BIN_RELEASE_DIR}}/decompiler"'
- task: format-json
# ASSET RIPPING
rip-textures:
@@ -139,10 +147,10 @@ tasks:
# TOOLS
analyze-ee-memory:
cmds:
- python ./scripts/tasks/extract-zip.py --file "{{.FILE}}" --out ./savestate_out/
- '{{.PYTHON}} ./scripts/tasks/extract-zip.py --file "{{.FILE}}" --out ./savestate_out/'
- '{{.MEMDUMP_BIN_RELEASE_DIR}}/memory_dump_tool ./savestate_out/eeMemory.bin --output-path ./ --game {{.GAME}} > ee-analysis.log'
watch-pcsx2:
# python -m pip install -U "watchdog[watchmedo]"
# {{.PYTHON}} -m pip install -U "watchdog[watchmedo]"
cmds:
- watchmedo shell-command --drop --patterns="*.p2s" --recursive --command='task analyze-ee-memory FILE="${watch_src_path}"' "{{.SAVESTATE_DIR}}"
vars:
@@ -155,15 +163,22 @@ tasks:
desc: Updates locally built tree-sitter rules
cmds:
- cd ../tree-sitter-opengoal && yarn gen
- python ./scripts/tasks/cp.py --src "../tree-sitter-opengoal/src/*" --dest "./third-party/tree-sitter/tree-sitter-opengoal"
- python ./scripts/tasks/cp.py --src "../tree-sitter-opengoal/grammar.js" --dest "./third-party/tree-sitter/tree-sitter-opengoal"
- '{{.PYTHON}} ./scripts/tasks/cp.py --src "../tree-sitter-opengoal/src/*" --dest "./third-party/tree-sitter/tree-sitter-opengoal"'
- '{{.PYTHON}} ./scripts/tasks/cp.py --src "../tree-sitter-opengoal/grammar.js" --dest "./third-party/tree-sitter/tree-sitter-opengoal"'
fix-translations:
desc: Finds and tries to fix invalid translation Characters
cmds:
- python ./scripts/ci/lint-characters.py --fix
- '{{.PYTHON}} ./scripts/ci/lint-characters.py --fix'
lint:
cmds:
- python ./scripts/ci/lint-trailing-whitespace.py
- '{{.PYTHON}} ./scripts/ci/lint-trailing-whitespace.py'
run-gpu-test:
desc: "Runs the game's built in GPU test"
preconditions:
- sh: test -f {{.GK_BIN_RELEASE_DIR}}/gk{{.EXE_FILE_EXTENSION}}
msg: "Couldn't locate runtime executable in '{{.GK_BIN_RELEASE_DIR}}/gk'"
cmds:
- "{{.GK_BIN_RELEASE_DIR}}/gk -v --gpu-test opengl --gpu-test-out-path ./gpu-test.json"
# TESTS
offline-tests: # ran by jenkins
cmds:
@@ -177,17 +192,17 @@ tasks:
# TODO - amalgamate offline-tests and this task, run twice if the previous step fails
update-ref-tests:
cmds:
- cmd: python ./scripts/tasks/delete-file-or-folder.py --path failures
- cmd: '{{.PYTHON}} ./scripts/tasks/delete-file-or-folder.py --path failures'
- cmd: '{{.OFFLINETEST_BIN_RELEASE_DIR}}/offline-test --iso_data_path "./iso_data/{{.GAME}}" --game {{.GAME}} --pretty-print --num_threads 32 --dump_current_output --fail-on-cmp'
ignore_error: true
- python ./scripts/update_decomp_reference.py ./failures ./test/decompiler/reference/ --game {{.GAME}}
- '{{.PYTHON}} ./scripts/update_decomp_reference.py ./failures ./test/decompiler/reference/ --game {{.GAME}}'
- task: offline-tests-fast
update-ref-file:
cmds:
- cmd: python ./scripts/tasks/delete-file-or-folder.py --path failures
- cmd: '{{.PYTHON}} ./scripts/tasks/delete-file-or-folder.py --path failures'
- cmd: '{{.OFFLINETEST_BIN_RELEASE_DIR}}/offline-test --iso_data_path "./iso_data/{{.GAME}}" --file {{.FILE}} --game {{.GAME}} --dump_current_output --fail-on-cmp'
ignore_error: true
- python ./scripts/update_decomp_reference.py ./failures ./test/decompiler/reference/ --game {{.GAME}}
- '{{.PYTHON}} ./scripts/update_decomp_reference.py ./failures ./test/decompiler/reference/ --game {{.GAME}}'
- task: offline-test-file
type-test:
cmds:
+8
View File
@@ -15,6 +15,13 @@ function(write_revision_h)
OUTPUT_VARIABLE GIT_TAG
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
# To support being on a commit with mutiple tags
if(${GIT_TAG} MATCHES "\n")
string(REPLACE "\n" ";" GIT_TAG_LIST "${GIT_TAG}")
list(LENGTH GIT_TAG_LIST GIT_TAG_LIST_LENGTH)
math(EXPR GIT_TAG_LAST_INDEX "${GIT_TAG_LIST_LENGTH} - 1")
list(GET GIT_TAG_LIST ${GIT_TAG_LAST_INDEX} GIT_TAG)
endif()
endif()
file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/versions/revision.h "#define BUILT_TAG \"${GIT_TAG}\"\n#define BUILT_SHA \"${GIT_SHORT_SHA}\"\n")
endfunction()
@@ -88,6 +95,7 @@ add_library(common
util/Timer.cpp
util/unicode_util.cpp
util/gltf_util.cpp
util/image_resize.cpp
versions/versions.cpp
)
+12 -1
View File
@@ -304,13 +304,15 @@ void TieTree::unpack() {
for (auto& draw : static_draws) {
draw.unpacked.idx_of_first_idx_in_full_buffer = unpacked.indices.size();
ASSERT(draw.plain_indices.empty());
// indices can come from either runs or already in plain indices.
for (auto& run : draw.runs) {
for (u32 ri = 0; ri < run.length; ri++) {
unpacked.indices.push_back(run.vertex0 + ri);
}
unpacked.indices.push_back(UINT32_MAX);
}
unpacked.indices.insert(unpacked.indices.end(), draw.plain_indices.begin(),
draw.plain_indices.end());
}
}
@@ -406,6 +408,8 @@ void TieTree::serialize(Serializer& ser) {
colors.serialize(ser);
bvh.serialize(ser);
ser.from_ptr(&use_strips);
ser.from_ptr(&has_per_proto_visibility_toggle);
ser.from_string_vector(&proto_names);
}
@@ -850,4 +854,11 @@ std::size_t PreloadedVertex::hash::operator()(const PreloadedVertex& v) const {
std::hash<float>()(v.s) ^ std::hash<float>()(v.t) ^ std::hash<u16>()(v.color_index);
}
std::size_t PackedTieVertices::Vertex::hash::operator()(const Vertex& v) const {
return std::hash<float>()(v.x) ^ std::hash<float>()(v.y) ^ std::hash<float>()(v.z) ^
std::hash<float>()(v.r) ^ std::hash<float>()(v.g) ^ std::hash<float>()(v.b) ^
std::hash<float>()(v.a) ^ std::hash<float>()(v.s) ^ std::hash<float>()(v.t) ^
std::hash<float>()(v.nx) ^ std::hash<float>()(v.ny) ^ std::hash<float>()(v.nz);
}
} // namespace tfrag3
+14 -2
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 = 41;
constexpr int TFRAG3_VERSION = 43;
enum MemoryUsageCategory {
TEXTURE,
@@ -116,6 +116,16 @@ struct PackedTieVertices {
float s, t;
s8 nx, ny, nz;
u8 r, g, b, a;
struct hash {
std::size_t operator()(const Vertex& x) const;
};
bool operator==(const Vertex& other) const {
return x == other.x && y == other.y && z == other.z && s == other.s && t == other.t &&
nx == other.nx && ny == other.ny && nz == other.nz && r == other.r && g == other.g &&
b == other.b && a == other.a;
}
};
struct MatrixGroup {
@@ -231,7 +241,7 @@ struct ShrubDraw {
struct InstancedStripDraw {
DrawMode mode; // the OpenGL draw settings.
u32 tree_tex_id = 0; // the texture that should be bound for the draw
s32 tree_tex_id = 0; // the texture that should be bound for the draw
// the list of vertices in the draw. This includes the restart code of UINT32_MAX that OpenGL
// will use to start a new strip.
@@ -420,6 +430,8 @@ struct TieTree {
bool has_per_proto_visibility_toggle = false;
std::vector<std::string> proto_names;
bool use_strips = true;
struct {
std::vector<PreloadedVertex> vertices; // mesh vertices
std::vector<u32> indices;
+1 -1
View File
@@ -37,7 +37,7 @@ struct DmaTag {
DmaTag(u64 value) {
spr = (value >> 63);
addr = (value >> 32) & 0x7fffffff;
qwc = value & 0xfff;
qwc = value & 0xffff;
kind = Kind((value >> 28) & 0b111);
}
+1 -1
View File
@@ -143,7 +143,7 @@ void FormatterTree::construct_formatter_tree_recursive(const std::string& source
}
for (size_t i = 0; i < ts_node_child_count(curr_node); i++) {
const auto child_node = ts_node_child(curr_node, i);
auto debug_child = ts_node_string(child_node);
[[maybe_unused]] auto debug_child = ts_node_string(child_node);
const auto contents = get_source_code(source, child_node);
bool skip_node = false;
for (const auto& skippable_content : skippable_nodes) {
+44
View File
@@ -168,6 +168,39 @@ static FormFormattingConfig new_deftype_rule(
return cfg;
}
static FormFormattingConfig new_defproc_rule(
int start_index,
int num_columns_to_compute_widths,
const std::vector<int>& inlining_preventation_indices) {
FormFormattingConfig cfg;
cfg.has_constant_pairs = true;
cfg.config_set = true;
cfg.hang_forms = false;
cfg.inline_until_index = [start_index](std::vector<std::string> curr_lines) {
// if (curr_lines.size() >= 4 && curr_lines.at(3) == "()") {
// return 4;
// }
return start_index;
};
for (const auto& index : inlining_preventation_indices) {
auto temp_config = std::make_shared<FormFormattingConfig>();
temp_config->config_set = true;
temp_config->prevent_inlining = true;
temp_config->hang_forms = false;
temp_config->indentation_width = 1;
auto temp_list_config = std::make_shared<FormFormattingConfig>();
temp_list_config->force_inline = false;
temp_list_config->hang_forms = false;
temp_config->default_index_config = temp_list_config;
if (index == 3) {
temp_config->determine_column_widths_for_list_elements = true;
temp_config->num_columns_to_compute_widths = num_columns_to_compute_widths;
}
cfg.index_configs.emplace(index, temp_config);
}
return cfg;
}
static FormFormattingConfig new_binding_rule(int form_head_width) {
FormFormattingConfig cfg;
cfg.config_set = true;
@@ -253,12 +286,16 @@ const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config
{"defmethod", new_defmethod_rule(3)},
{"lambda", new_lambda_rule(2)},
{"deftype", new_deftype_rule(3, 1, {3, 4, 5, 6})},
{"defproc", new_defproc_rule(3, 1, {3, 4, 5, 6})},
{"suspend-for", new_flow_rule(2)},
{"spawn-proc", new_flow_rule(2)},
{"defun", new_flow_rule(3)},
{"defun-recursive", new_flow_rule(4)},
{"defun-debug-recursive", new_flow_rule(4)},
{"defun-debug", new_flow_rule(3)},
{"defbehavior", new_flow_rule(4)},
{"if", new_inlineable_flow_rule(2)},
{"aif", new_inlineable_flow_rule(2)},
{"#if", new_inlineable_flow_rule(2)},
{"define", new_permissive_flow_rule()},
{"def-mips2c", new_permissive_flow_rule()},
@@ -269,10 +306,14 @@ const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config
{"declare-type", new_permissive_flow_rule()},
{"defmacro", new_function_rule(3)},
{"desfun", new_function_rule(3)},
{"def-actor", new_flow_rule(2, true)},
{"defskelgroup", new_flow_rule(2, true)},
{"defpartgroup", new_flow_rule(2, true)},
{"defpart", new_flow_rule(2, true)},
{"defstate", new_defstate_rule(3, true)},
{"defevent", new_flow_rule(2)},
{"event", new_flow_rule(1)},
{"defpost", new_flow_rule(2)},
{"behavior", new_flow_rule(2)},
{"dotimes", new_flow_rule(2)},
{"dolist", new_flow_rule(2)},
@@ -281,12 +322,15 @@ const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config
{"protect", new_binding_rule(4)},
{"let*", new_binding_rule(5)},
{"rlet", new_binding_rule(5)},
{"mlet", new_binding_rule(5)},
{"when", new_flow_rule(2)},
{"awhen", new_flow_rule(2)},
{"unless", new_flow_rule(2)},
{"with-profiler", new_flow_rule(2)},
{"with-pc", new_flow_rule(0)},
{"#unless", new_flow_rule(2)},
{"#when", new_flow_rule(2)},
{"#when-game", new_flow_rule(2)},
{"countdown", new_flow_rule(2)},
{"until", new_flow_rule(2)},
{"loop", new_flow_rule(0)},
+15 -1
View File
@@ -57,6 +57,8 @@
#include "common/util/Assert.h"
#include "common/util/crc32.h"
#include "fmt/core.h"
namespace goos {
/*!
@@ -234,10 +236,14 @@ class Object {
ObjectType type = ObjectType::INVALID;
private:
bool disallow_hex_for_int = false;
public:
std::string print() const {
switch (type) {
case ObjectType::INTEGER:
return integer_obj.print();
return disallow_hex_for_int ? fmt::format("{}", integer_obj.value) : integer_obj.print();
case ObjectType::FLOAT:
return float_obj.print();
case ObjectType::CHAR:
@@ -278,6 +284,14 @@ class Object {
return o;
}
static Object make_integer_no_hex(IntType value) {
Object o;
o.type = ObjectType::INTEGER;
o.integer_obj.value = value;
o.disallow_hex_for_int = true;
return o;
}
static Object make_float(FloatType value) {
Object o;
o.type = ObjectType::FLOAT;
+4 -4
View File
@@ -295,7 +295,7 @@ void break_list(Node* node) {
}
} else if (name == "until" || name == "while" || name == "dotimes" || name == "countdown" ||
name == "when" || name == "behavior" || name == "lambda" || name == "defpart" ||
name == "define") {
name == "define" || name == "suspend-for") {
node->top_line_count = 2;
} else if (name == "let" || name == "let*" || name == "rlet" ||
name == "with-dma-buffer-add-bucket") {
@@ -341,9 +341,9 @@ void break_list(Node* node) {
void insert_required_breaks(const std::vector<Node*>& bfs_order) {
const std::unordered_set<std::string> always_break = {
"when", "defun-debug", "countdown", "case", "defun", "defmethod", "let",
"until", "while", "if", "dotimes", "cond", "else", "defbehavior",
"with-pp", "rlet", "defstate", "behavior", "defpart", "loop", "let*"};
"when", "defun-debug", "countdown", "case", "defun", "defmethod", "let", "until",
"while", "if", "dotimes", "cond", "else", "defbehavior", "with-pp", "rlet",
"defstate", "behavior", "defpart", "loop", "let*", "suspend-for"};
for (auto node : bfs_order) {
if (!node->break_list && node->kind == Node::Kind::LIST &&
node->child_nodes.at(0).kind == Node::Kind::ATOM) {
+11
View File
@@ -369,6 +369,17 @@ struct Matrix {
return result;
}
Matrix<T, Rows, Cols> transposed() const {
static_assert(Rows == Cols);
Matrix<T, Rows, Cols> ret;
for (int i = 0; i < Rows; i++) {
for (int j = 0; j < Cols; j++) {
ret(i, j) = operator()(j, i);
}
}
return ret;
}
template <int OtherCols>
Matrix<T, Rows, OtherCols> operator*(const Matrix<T, Cols, OtherCols>& y) const {
Matrix<T, Rows, OtherCols> result;
+1
View File
@@ -49,6 +49,7 @@ struct Config {
{KeyBind::Modifier::CTRL, "N", "Full build of the game", "(mi)"}};
bool per_game_history = true;
bool permissive_redefinitions = false;
std::string iso_path;
int get_nrepl_port() {
if (temp_nrepl_port != -1) {
+16 -8
View File
@@ -43,6 +43,15 @@ void Wrapper::print_welcome_message(const std::vector<std::string>& loaded_proje
fmt::format(" Project Path: {}\n",
fmt::format(fg(fmt::color::gray), file_util::get_jak_project_dir().string()));
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " - :===: -");
std::string effective_iso_path;
if (repl_config.iso_path.empty()) {
effective_iso_path = file_util::get_file_path({"iso_data"});
} else {
effective_iso_path = repl_config.iso_path;
}
message +=
fmt::format(" ISO Data Path: {}\n", fmt::format(fg(fmt::color::gray), effective_iso_path));
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " --. .--: :--. .--");
message += " nREPL:";
if (!nrepl_alive) {
message += fmt::format(fg(fmt::color::red), "DISABLED\n");
@@ -50,22 +59,21 @@ void Wrapper::print_welcome_message(const std::vector<std::string>& loaded_proje
message += fmt::format(fg(fmt::color::light_green), " Listening on {}\n",
repl_config.get_nrepl_port());
}
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " --. .--: :--. .--");
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .=======. =======.");
message += " Source File Search Dirs: ";
const auto search_dir_string =
fmt::format("{}", fmt::join(repl_config.asm_file_search_dirs, ","));
message += fmt::format("[{}]\n", fmt::format(fg(fmt::color::gray), search_dir_string));
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .=======. =======.");
message += fmt::format(" {} or {} for basic help and usage\n",
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-=====-. .-=====-");
message += fmt::format(" {} or {} for basic help and usage\n",
fmt::format(fg(fmt::color::cyan), "(repl-help)"),
fmt::format(fg(fmt::color::cyan), "(repl-keybinds)"));
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-=====-. .-=====-");
message +=
fmt::format(" {} to connect to the game\n", fmt::format(fg(fmt::color::cyan), "(lt)"));
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-===========-.");
message += fmt::format(" {} to recompile the active project.\n",
message +=
fmt::format(" {} to connect to the game\n", fmt::format(fg(fmt::color::cyan), "(lt)"));
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-===-.");
message += fmt::format(" {} to recompile the active project.\n",
fmt::format(fg(fmt::color::cyan), "(mi)"));
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-===-.\n");
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .\n");
fmt::print("{}", message);
}
+6 -2
View File
@@ -61,7 +61,10 @@ const std::unordered_map<GameVersion, std::vector<std::string>> locale_lookup =
{GameVersion::Jak1,
{"en-US", "fr-FR", "de-DE", "es-ES", "it-IT", "jp-JP", "en-GB", "pt-PT", "fi-FI", "sv-SE",
"da-DK", "no-NO", "nl-NL", "pt-BR", "hu-HU", "ca-ES", "is-IS"}},
{GameVersion::Jak2, {"en-US", "fr-FR", "de-DE", "es-ES", "it-IT", "jp-JP", "ko-KR", "en-GB"}}};
{GameVersion::Jak2, {"en-US", "fr-FR", "de-DE", "es-ES", "it-IT", "jp-JP", "ko-KR", "en-GB"}},
{GameVersion::Jak3,
{"en-US", "fr-FR", "de-DE", "es-ES", "it-IT", "cm-CM", "jp-JP", "ko-KR", "ru-RU", "pt-PT",
"nl-NL", "en-GB"}}};
std::string lookup_locale_code(const GameVersion game_version, const int language_id) {
if (locale_lookup.find(game_version) == locale_lookup.end() ||
@@ -73,7 +76,8 @@ std::string lookup_locale_code(const GameVersion game_version, const int languag
const std::unordered_map<GameVersion, std::vector<int>> language_ids_with_audio = {
{GameVersion::Jak1, {0, 1, 2, 3, 4, 5, 6}},
{GameVersion::Jak2, {0, 1, 2, 3, 4, 5, 6, 7}}};
{GameVersion::Jak2, {0, 1, 2, 3, 4, 5, 6, 7}},
{GameVersion::Jak3, {0, 1, 2, 3, 4, 5, 11}}};
bool dump_language_with_duplicates_from_base(const GameVersion game_version,
const int language_id) {
@@ -93,6 +93,57 @@ const std::unordered_map<std::string, u16> jak2_speaker_name_to_enum_val = {
{"metalkor-before-consite", 35},
{"metalkor-intro", 36}};
// matches enum in `subtitle3-h.gc` with "none" (first) and "max" (last and removed)
const std::unordered_map<std::string, u16> jak3_speaker_name_to_enum_val = {
{"none", 0},
{"jak", 1},
{"darkjak", 2},
{"daxter", 3},
{"pecker", 4},
{"ashelin", 5},
{"veger", 6},
{"samos", 7},
{"damas", 8},
{"kleiver", 9},
{"seem", 10},
{"errol", 11},
{"errol-hologram", 12},
{"sig", 13},
{"torn", 14},
{"tess", 15},
{"guard", 16},
{"guard-a", 17},
{"guard-b", 18},
{"keira", 19},
{"vin", 20},
{"onin", 21},
{"jinx", 22},
{"wastelander-male", 23},
{"wastelander-female", 24},
{"citizen-male", 25},
{"citizen-female", 26},
{"marauder", 27},
{"oracle", 28},
{"precursor", 29},
{"ottsel-leader", 30},
{"ottsel-surfer", 31},
{"ottsel-dummy", 32},
{"ottsel-veger", 33},
{"ottsel-tess", 34},
{"computer", 35},
{"ottsel-voice-before-outro", 36},
{"ottsel-voice", 37},
{"krew", 38},
{"baron", 39},
{"scherr", 40},
{"arey", 41},
{"baldwin", 42},
{"schimpf", 43},
{"martinsen", 44},
{"phillips", 45},
{"yates", 46},
};
GameSubtitlePackage read_json_files_v2(const GameSubtitleDefinitionFile& file_info) {
GameSubtitlePackage package;
SubtitleFile lang_lines;
@@ -256,11 +307,21 @@ void GameSubtitleBank::add_scenes_from_files(const GameSubtitlePackage& package)
}
}
// TODO - for jak 3+, this needs some game version context info (could infer from text version)
std::vector<std::string> GameSubtitleBank::speaker_names_ordered_by_enum_value() {
// Create a temporary vector of pairs (key, value)
std::vector<std::pair<std::string, u16>> temp_vec(jak2_speaker_name_to_enum_val.begin(),
jak2_speaker_name_to_enum_val.end());
std::vector<std::pair<std::string, u16>> temp_vec;
switch (m_text_version) {
case GameTextVersion::JAK2:
temp_vec = {jak2_speaker_name_to_enum_val.begin(), jak2_speaker_name_to_enum_val.end()};
break;
case GameTextVersion::JAK3:
temp_vec = {jak3_speaker_name_to_enum_val.begin(), jak3_speaker_name_to_enum_val.end()};
break;
default:
throw std::runtime_error(fmt::format("GameSubtitleBank: invalid game text version {} ({})",
(int)m_text_version,
get_text_version_name(m_text_version)));
}
// Sort the temporary vector based on the enum value in ascending order
std::sort(temp_vec.begin(), temp_vec.end(),
[](const auto& a, const auto& b) { return a.second < b.second; });
@@ -279,13 +340,25 @@ std::vector<std::string> GameSubtitleBank::speaker_names_ordered_by_enum_value()
}
u16 GameSubtitleBank::speaker_enum_value_from_name(const std::string& speaker_id) {
if (jak2_speaker_name_to_enum_val.find(speaker_id) == jak2_speaker_name_to_enum_val.end()) {
std::unordered_map<std::string, u16> enum_map;
switch (m_text_version) {
case GameTextVersion::JAK2:
enum_map = jak2_speaker_name_to_enum_val;
break;
case GameTextVersion::JAK3:
enum_map = jak3_speaker_name_to_enum_val;
break;
default:
throw std::runtime_error(fmt::format("GameSubtitleBank: invalid game text version {}",
get_text_version_name(m_text_version)));
}
if (enum_map.find(speaker_id) == enum_map.end()) {
throw std::runtime_error(
fmt::format("'{}' speaker could not be found in the enum value mapping, update it or fix "
"the invalid speaker!",
speaker_id));
}
return u16(jak2_speaker_name_to_enum_val.at(speaker_id));
return u16(enum_map.at(speaker_id));
}
SubtitleMetadataFile dump_bank_meta_v2(const GameVersion game_version,
+15 -4
View File
@@ -8,6 +8,8 @@
#include "BinaryWriter.h"
#include "FileUtil.h"
#include "common/log/log.h"
void build_dgo(const DgoDescription& description, const std::string& output_prefix) {
BinaryWriter writer;
// dgo header
@@ -15,8 +17,14 @@ void build_dgo(const DgoDescription& description, const std::string& output_pref
writer.add_cstr_len(description.dgo_name.c_str(), 60);
for (auto& obj : description.entries) {
auto obj_data = file_util::read_binary_file(file_util::get_jak_project_dir() / "out" /
output_prefix / "obj" / obj.file_name);
// Ensure the directory exists
const auto file_path =
file_util::get_jak_project_dir() / "out" / output_prefix / "obj" / obj.file_name;
if (!file_util::file_exists(file_path.string())) {
lg::warn("tried to build a DGO with a file that doesn't exist: {}", file_path.string());
continue;
}
auto obj_data = file_util::read_binary_file(file_path);
// size
writer.add<uint32_t>(obj_data.size());
// name
@@ -29,6 +37,9 @@ void build_dgo(const DgoDescription& description, const std::string& output_pref
}
}
writer.write_to_file(file_util::get_jak_project_dir() / "out" / output_prefix / "iso" /
description.dgo_name);
// Ensure the output directory exists
const auto dgo_path =
file_util::get_jak_project_dir() / "out" / output_prefix / "iso" / description.dgo_name;
file_util::create_dir_if_needed_for_file(dgo_path);
writer.write_to_file(dgo_path);
}
+74
View File
@@ -559,6 +559,8 @@ static std::vector<ReplaceInfo> s_replace_info_jak1 = {
{"U~Y~-13H~+2V,~Z", "Ų"},
{"U~Y~-18H~-10V-~Z", "Ū"},
{"I~Y~-8H~+1V,~Z", "Į"},
// czech specific
{"U~Y~-23H~-5Vº~Z", "Ů"},
// tildes
{"N~Y~-22H~-4V<TIL>~Z", "Ñ"},
@@ -575,6 +577,8 @@ static std::vector<ReplaceInfo> s_replace_info_jak1 = {
{"N~Y~-21H~-5V'~Z", "Ń"},
{"S~Y~-21H~-5V'~Z", "Ś"},
{"Z~Y~-21H~-5V'~Z", "Ź"},
// czech specific
{"Y~Y~-25H~-4V'~Z", "Ý"},
// double acute accents
{"O~Y~-28H~-4V'~-9H'~Z", "Ő"}, // custom
@@ -602,6 +606,22 @@ static std::vector<ReplaceInfo> s_replace_info_jak1 = {
{"O~Y~-22H~-3V¨~Z", "ö"}, // dumb
{"U~Y~-22H~-3V¨~Z", "Ü"},
// caron - Ǎ ǎ Ě ě Ǧ ǧ Ǐ ǐ Ǒ ǒ Ǔ ǔ Y̌ y̌
{"A~Y~-20H~-4Vˇ~Z", "Ǎ"},
{"E~Y~-20H~-5Vˇ~Z", "Ě"},
{"G~Y~-20H~-5Vˇ~Z", "Ǧ"},
{"I~Y~-19H~-5Vˇ~Z", "Ǐ"},
{"O~Y~-20H~-4Vˇ~Z", "Ǒ"},
{"U~Y~-24H~-3Vˇ~Z", "Ǔ"},
{"Y~Y~-24H~-3Vˇ~Z", "Y̌"},
// czech specific - Č Ň Ř Š Ž Ť
{"C~Y~-25H~-9Vˇ~Z", "Č"},
{"N~Y~-23H~-5Vˇ~Z", "Ň"},
{"R~Y~-24H~-5Vˇ~Z", "Ř"},
{"S~Y~-24H~-5Vˇ~Z", "Š"},
{"T~Y~-23H~-5Vˇ~Z", "Ť"},
{"Z~Y~-23H~-5Vˇ~Z", "Ž"},
// dakuten katakana
{"~Yウ~Z゛", "ヴ"},
{"~Yカ~Z゛", "ガ"},
@@ -966,6 +986,10 @@ static std::vector<ReplaceInfo> s_replace_info_jak2 = {
{"u~Y~-18H~-15V-~Z", "ū"},
{"I~Y~-8H~+4V,~Z", "Į"},
{"i~Y~-8H~+4V,~Z", "į"},
// czech specific
{"U~Y~-24H~-7Vº~Z", "Ů"},
{"u~Y~-23H~-5Vº~Z", "ů"},
{"t~Y~-7H~-21V,~Z", "ť"},
// tildes
{"N~Y~-22H~-4V<TIL>~Z", "Ñ"},
@@ -987,6 +1011,9 @@ static std::vector<ReplaceInfo> s_replace_info_jak2 = {
{"u~Y~-24H~-3V'~Z", "ú"},
{"Z~Y~-24H~-3V'~Z", "Ź"},
{"z~Y~-24H~-3V'~Z", "ź"},
// czech specific
{"Y~Y~-26H~-5V'~Z", "Ý"},
{"~+7Vy~-7V~Y~-24H~-3V'~Z", "ý"},
// circumflex
{"A~Y~-20H~-4V^~Z", "Â"},
@@ -1023,6 +1050,34 @@ static std::vector<ReplaceInfo> s_replace_info_jak2 = {
{"U~Y~-25H~-8V¨~Z", "Ü"},
{"u~Y~-24H~-3V¨~Z", "ü"},
// caron - Ǎ ǎ Ě ě Ǧ ǧ Ǐ ǐ Ǒ ǒ Ǔ ǔ Y̌ y̌
{"A~Y~-25H~-9Vˇ~Z", "Ǎ"},
{"a~Y~-24H~-5Vˇ~Z", "ǎ"},
{"E~Y~-22H~-8Vˇ~Z", "Ě"},
{"e~Y~-25H~-4Vˇ~Z", "ě"},
{"G~Y~-24H~-8Vˇ~Z", "Ǧ"},
{"~+7Vg~-7V~Y~-25H~-4Vˇ~Z", "ǧ"},
{"I~Y~-19H~-8Vˇ~Z", "Ǐ"},
{"i~Y~-19H~-8Vˇ~Z", "ǐ"},
{"O~Y~-25H~-7Vˇ~Z", "Ǒ"},
{"o~Y~-25H~-4Vˇ~Z", "ǒ"},
{"U~Y~-25H~-6Vˇ~Z", "Ǔ"},
{"u~Y~-24H~-3Vˇ~Z", "ǔ"},
{"Y~Y~-25H~-5Vˇ~Z", "Y̌"},
{"~+7Vy~-7V~Y~-25H~-3Vˇ~Z", "y̌"},
// czech specific - Č č Ň ň Ř ř Š š Ž ž Ť
{"C~Y~-25H~-9Vˇ~Z", "Č"},
{"c~Y~-24H~-5Vˇ~Z", "č"},
{"N~Y~-25H~-9Vˇ~Z", "Ň"},
{"n~Y~-24H~-5Vˇ~Z", "ň"},
{"R~Y~-25H~-9Vˇ~Z", "Ř"},
{"r~Y~-22H~-5Vˇ~Z", "ř"},
{"S~Y~-25H~-9Vˇ~Z", "Š"},
{"s~Y~-22H~-5Vˇ~Z", "š"},
{"T~Y~-24H~-7Vˇ~Z", "Ť"},
{"Z~Y~-25H~-9Vˇ~Z", "Ž"},
{"z~Y~-24H~-5Vˇ~Z", "ž"},
// dakuten katakana
{"~Yウ~Z゛", "ヴ"},
{"~Yカ~Z゛", "ガ"},
@@ -1156,6 +1211,25 @@ static std::vector<ReplaceInfo> s_replace_info_jak2 = {
"<FLAG_KOREA>"},
{"~Y~1L<FLAG_PART_FILL>~]~-1H~Y~1L<FLAG_PART_FILL>~Z~-11H~3L<FLAG_PART_JAPAN_SUN>~Z~+26H",
"<FLAG_JAPAN>"},
{"~Y~1L<FLAG_PART_FILL>~Z~7L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~7L<FLAG_PART_VERT_STRIPE_RIGHT>~]"
"~-1H~Y~1L<FLAG_PART_FILL>~Z~7L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~+26H",
"<FLAG_FINLAND>"},
{"~Y~7L<FLAG_PART_FILL>~Z~5L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~5L<FLAG_PART_VERT_STRIPE_RIGHT>~]"
"~-1H~Y~7L<FLAG_PART_FILL>~Z~5L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~+26H",
"<FLAG_SWEDEN>"},
{"~Y~3L<FLAG_PART_FILL>~Z~1L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~1L<FLAG_PART_VERT_STRIPE_RIGHT>~]"
"~-1H~Y~3L<FLAG_PART_FILL>~Z~1L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~+26H",
"<FLAG_DENMARK>"},
{"~Y~1L<FLAG_PART_FILL>~Z~3L<FLAG_PART_TOP_BOTTOM_STRIPE>~]~-1H~Y~1L<FLAG_PART_FILL>~Z~3L<FLAG_"
"PART_TOP_BOTTOM_STRIPE>~Z~-19H~1L<FLAG_PART_VERT_STRIPE_MIDDLE>~Z~-23H~7L<FLAG_PART_VERT_"
"STRIPE_RIGHT>~Z~-23H~7L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~7L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~"
"+26H",
"<FLAG_NORWAY>"},
{"~Y~1L<FLAG_PART_FILL>~Z~7L<FLAG_PART_TOP_BOTTOM_STRIPE>~]~-1H~Y~1L<FLAG_PART_FILL>~Z~7L<FLAG_"
"PART_TOP_BOTTOM_STRIPE>~Z~-19H~1L<FLAG_PART_VERT_STRIPE_MIDDLE>~Z~-23H~3L<FLAG_PART_VERT_"
"STRIPE_RIGHT>~Z~-23H~3L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~3L<FLAG_PART_HORZ_STRIPE_MIDDLE>~Z~"
"+26H",
"<FLAG_ICELAND>"},
// weird stuff
// - descenders
+399 -21
View File
@@ -1,5 +1,7 @@
#include "gltf_util.h"
#include "image_resize.h"
#include "common/log/log.h"
namespace gltf_util {
@@ -44,6 +46,20 @@ std::vector<math::Vector<u8, 4>> extract_color_from_vec4_float(const u8* data,
return result;
}
std::vector<math::Vector<u8, 4>> extract_color_from_vec3_float(const u8* data,
u32 count,
u32 stride) {
std::vector<math::Vector<u8, 4>> result;
result.reserve(count);
for (u32 i = 0; i < count; i++) {
math::Vector<float, 3> temp;
memcpy(&temp, data, sizeof(math::Vector<float, 3>));
data += stride;
result.emplace_back(temp.x() * 255, temp.y() * 255, temp.z() * 255, 255);
}
return result;
}
/*!
* Convert a GLTF color buffer (u16 format) to u8 colors.
*/
@@ -61,6 +77,16 @@ std::vector<math::Vector<u8, 4>> extract_color_from_vec4_u16(const u8* data,
return result;
}
std::vector<math::Vector<u8, 4>> extract_color_from_vec4_u8(const u8* data, u32 count, u32 stride) {
std::vector<math::Vector<u8, 4>> result;
result.reserve(count);
for (u32 i = 0; i < count; i++) {
result.push_back(math::Vector<u8, 4>(data[0], data[1], data[2], data[3]));
data += stride;
}
return result;
}
/*!
* Convert a GLTF index buffer
*/
@@ -92,6 +118,74 @@ std::vector<u32> gltf_index_buffer(const tinygltf::Model& model,
}
}
std::vector<math::Matrix4f> extract_mat4(const tinygltf::Model& model, int accessor_idx) {
const auto& accessor = model.accessors[accessor_idx];
const auto& buffer_view = model.bufferViews[accessor.bufferView];
const auto& buffer = model.buffers[buffer_view.buffer];
const u8* data_ptr = buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset;
const auto stride = accessor.ByteStride(buffer_view);
const auto count = accessor.count;
// ASSERT(buffer_view.target == TINYGLTF_TARGET_ARRAY_BUFFER); // ??
ASSERT(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT);
ASSERT(accessor.type == TINYGLTF_TYPE_MAT4);
std::vector<math::Matrix4f> result(accessor.count);
for (size_t x = 0; x < count; x++) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
memcpy(&result[x](j, i), data_ptr + sizeof(float) * (i * 4 + j), sizeof(float));
}
}
data_ptr += stride;
}
return result;
}
JointsAndWeights convert_per_vertex_data(const math::Vector4f& weights,
const math::Vector<u8, 4>& joints) {
int discard_idx = -1;
float discard_weight = 100;
for (int i = 0; i < 4; i++) {
if (weights[i] < discard_weight) {
discard_idx = i;
discard_weight = weights[i];
}
}
JointsAndWeights ret;
int dst = 0;
float sum = 0;
for (int src = 0; src < 4; src++) {
if (src == discard_idx) {
continue;
}
// this +1 is to account for align not existing in the gltf.
ret.joints[dst] = joints[src] + 2;
ret.weights[dst] = weights[src];
sum += ret.weights[dst];
dst++;
}
ret.weights /= sum;
return ret;
}
std::vector<JointsAndWeights> extract_and_flatten_joints_and_weights(
const tinygltf::Model& model,
const tinygltf::Primitive& prim) {
auto weights =
extract_vec<float, 4>(model, prim.attributes.at("WEIGHTS_0"), TINYGLTF_COMPONENT_TYPE_FLOAT);
auto joints = extract_vec<u8, 4>(model, prim.attributes.at("JOINTS_0"),
TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE);
std::vector<JointsAndWeights> ret;
ASSERT(weights.size() == joints.size());
for (size_t i = 0; i < weights.size(); i++) {
ret.push_back(convert_per_vertex_data(weights[i], joints[i]));
}
return ret;
}
/*!
* Extract positions, colors, and normals from a mesh.
*/
@@ -148,19 +242,37 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model,
buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset;
const auto byte_stride = attrib_accessor.ByteStride(buffer_view);
const auto count = attrib_accessor.count;
ASSERT_MSG(attrib_accessor.type == TINYGLTF_TYPE_VEC4, "COLOR_0 wasn't vec4");
std::vector<math::Vector<u8, 4>> colors;
switch (attrib_accessor.componentType) {
case TINYGLTF_COMPONENT_TYPE_FLOAT:
colors = extract_color_from_vec4_float(data_ptr, count, byte_stride);
switch (attrib_accessor.type) {
case TINYGLTF_TYPE_VEC4:
switch (attrib_accessor.componentType) {
case TINYGLTF_COMPONENT_TYPE_FLOAT:
colors = extract_color_from_vec4_float(data_ptr, count, byte_stride);
break;
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
colors = extract_color_from_vec4_u16(data_ptr, count, byte_stride);
break;
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
colors = extract_color_from_vec4_u8(data_ptr, count, byte_stride);
break;
default:
lg::die("Unknown type for COLOR_0: {}", attrib_accessor.componentType);
}
break;
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
colors = extract_color_from_vec4_u16(data_ptr, count, byte_stride);
case TINYGLTF_TYPE_VEC3:
switch (attrib_accessor.componentType) {
case TINYGLTF_COMPONENT_TYPE_FLOAT:
colors = extract_color_from_vec3_float(data_ptr, count, byte_stride);
break;
default:
lg::die("unkonwn component type for vec3 color {}", attrib_accessor.componentType);
}
break;
default:
lg::die("Unknown component type for COLOR_0: {}", attrib_accessor.componentType);
lg::die("unknown attribute type for color {}", attrib_accessor.type);
}
vtx_colors.insert(vtx_colors.end(), colors.begin(), colors.end());
}
}
@@ -213,7 +325,8 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model,
normals = extract_vec3f(data_ptr, count, byte_stride);
for (auto& nrm : normals) {
math::Vector4f nrm4(nrm.x(), nrm.y(), nrm.z(), 0.f);
nrm = (w_T_local * nrm4).xyz();
// we found that normals aren't normalized if an object is scaled in blender.
nrm = (w_T_local * nrm4).xyz().normalized();
}
ASSERT(normals.size() == result.size());
} else {
@@ -277,7 +390,7 @@ int texture_pool_debug_checker(TexturePool* pool) {
}
}
int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex) {
int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex, int alpha_shift) {
const auto& existing = pool->textures_by_name.find(tex.name);
if (existing != pool->textures_by_name.end()) {
lg::info("Reusing image: {}", tex.name);
@@ -302,6 +415,72 @@ int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex) {
tt.data.resize(tt.w * tt.h);
ASSERT(tex.image.size() >= tt.data.size());
memcpy(tt.data.data(), tex.image.data(), tt.data.size() * 4);
// adjust alpha colors for PS2/PC difference
for (auto& color : tt.data) {
u32 alpha = color >> 24;
alpha >>= alpha_shift;
color &= 0xff'ff'ff;
color |= (alpha << 24);
}
return idx;
}
int texture_pool_add_envmap_control_texture(TexturePool* pool,
const tinygltf::Model& model,
int rgb_image_id,
int mr_image_id,
bool wrap_w,
bool wrap_h) {
const auto& existing = pool->envmap_textures_by_gltf_id.find({rgb_image_id, mr_image_id});
if (existing != pool->envmap_textures_by_gltf_id.end()) {
lg::info("Reusing envmap textures");
return existing->second;
}
const auto& rgb_tex = model.images.at(rgb_image_id);
const auto& mr_tex = model.images.at(mr_image_id);
lg::info("new envmap texture {} {}", rgb_tex.name, mr_tex.name);
ASSERT(rgb_tex.bits == 8);
ASSERT(rgb_tex.component == 4);
ASSERT(rgb_tex.pixel_type == TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE);
ASSERT(mr_tex.bits == 8);
ASSERT(mr_tex.pixel_type == TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE);
ASSERT(mr_tex.component == 4);
std::vector<u8> resized_mr_tex;
const u8* mr_src;
if (rgb_tex.width == mr_tex.width && rgb_tex.height == mr_tex.height) {
mr_src = mr_tex.image.data();
} else {
resized_mr_tex.resize(rgb_tex.width * rgb_tex.height * 4);
resize_rgba_image(resized_mr_tex.data(), rgb_tex.width, rgb_tex.height, mr_tex.image.data(),
mr_tex.width, mr_tex.height, wrap_w, wrap_h);
mr_src = resized_mr_tex.data();
}
size_t idx = pool->textures_by_idx.size();
pool->envmap_textures_by_gltf_id[{rgb_image_id, mr_image_id}] = idx;
auto& tt = pool->textures_by_idx.emplace_back();
tt.w = rgb_tex.width;
tt.h = rgb_tex.height;
tt.debug_name = rgb_tex.name;
tt.debug_tpage_name = "custom-level";
tt.load_to_pool = false;
tt.combo_id = 0; // doesn't matter, not a pool tex
tt.data.resize(tt.w * tt.h);
ASSERT(rgb_tex.image.size() >= tt.data.size());
memcpy(tt.data.data(), rgb_tex.image.data(), tt.data.size() * 4);
// adjust alpha from metallic channel
for (size_t i = 0; i < tt.data.size(); i++) {
u32 rgb = tt.data[i];
u32 metal = mr_src[4 * i + 2] / 4;
rgb &= 0xff'ff'ff;
rgb |= (metal << 24);
tt.data[i] = rgb;
}
return idx;
}
@@ -348,6 +527,15 @@ math::Vector4f vector4f_from_gltf(const std::vector<double>& in) {
return math::Vector4f{in[0], in[1], in[2], in[3]};
}
math::Matrix4f matrix_from_trs(const math::Vector3f& trans,
const math::Vector4f& quat,
const math::Vector3f& scale) {
math::Matrix4f t = affine_translation(trans);
math::Matrix4f r = affine_rot_qxyzw(quat);
math::Matrix4f s = affine_scale(scale);
return t * r * s;
}
math::Matrix4f matrix_from_node(const tinygltf::Node& node) {
if (!node.matrix.empty()) {
math::Matrix4f result;
@@ -430,22 +618,38 @@ void dedup_vertices(const std::vector<tfrag3::PreloadedVertex>& vertices_in,
}
}
DrawMode draw_mode_from_sampler(const tinygltf::Sampler& sampler) {
DrawMode mode = make_default_draw_mode();
void setup_alpha_from_material(const tinygltf::Material& material, DrawMode* mode) {
if (material.alphaMode == "OPAQUE") {
mode->disable_ab();
} else if (material.alphaMode == "MASK") {
mode->enable_at();
mode->set_alpha_test(DrawMode::AlphaTest::GEQUAL);
mode->set_alpha_fail(GsTest::AlphaFail::KEEP);
mode->set_aref(material.alphaCutoff * 127);
} else if (material.alphaMode == "BLEND") {
mode->enable_ab();
mode->set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST);
mode->set_depth_write_enable(false);
} else {
lg::die("Unknown GLTF alphaMode {}", material.alphaMode);
}
}
void setup_draw_mode_from_sampler(const tinygltf::Sampler& sampler, DrawMode* mode) {
if (sampler.magFilter == TINYGLTF_TEXTURE_FILTER_NEAREST) {
ASSERT(sampler.minFilter == TINYGLTF_TEXTURE_FILTER_NEAREST);
mode.set_filt_enable(false);
ASSERT(sampler.minFilter == TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST);
mode->set_filt_enable(false);
} else {
ASSERT(sampler.minFilter != TINYGLTF_TEXTURE_FILTER_NEAREST);
mode.set_filt_enable(true);
mode->set_filt_enable(true);
}
switch (sampler.wrapS) {
case TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE:
mode.set_clamp_s_enable(true);
mode->set_clamp_s_enable(true);
break;
case TINYGLTF_TEXTURE_WRAP_REPEAT:
mode.set_clamp_s_enable(false);
mode->set_clamp_s_enable(false);
break;
default:
ASSERT(false);
@@ -453,15 +657,189 @@ DrawMode draw_mode_from_sampler(const tinygltf::Sampler& sampler) {
switch (sampler.wrapT) {
case TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE:
mode.set_clamp_t_enable(true);
mode->set_clamp_t_enable(true);
break;
case TINYGLTF_TEXTURE_WRAP_REPEAT:
mode.set_clamp_t_enable(false);
mode->set_clamp_t_enable(false);
break;
default:
ASSERT(false);
}
return mode;
}
EnvmapSettings envmap_settings_from_gltf(const tinygltf::Material& mat) {
EnvmapSettings settings;
ASSERT(mat.extensions.contains("KHR_materials_specular"));
const auto& specular_extension = mat.extensions.at("KHR_materials_specular");
ASSERT(specular_extension.Has("specularColorTexture"));
auto& texture = specular_extension.Get("specularColorTexture");
ASSERT(texture.Has("index"));
settings.texture_idx = texture.Get("index").Get<int>();
return settings;
}
bool material_has_envmap(const tinygltf::Material& mat) {
return mat.extensions.contains("KHR_materials_specular");
}
bool envmap_is_valid(const tinygltf::Material& mat) {
auto envmap = material_has_envmap(mat);
if (envmap && mat.pbrMetallicRoughness.metallicRoughnessTexture.index < 0) {
lg::warn(fmt::format(
"Material \"{}\" has specular property set, but is missing a metallic roughness texture, "
"ignoring envmap!",
mat.name));
return false;
}
return envmap;
}
std::optional<int> find_single_skin(const tinygltf::Model& model,
const std::vector<NodeWithTransform>& all_nodes) {
std::optional<int> skin_index;
for (const auto& n : all_nodes) {
const auto& node = model.nodes.at(n.node_idx);
if (node.skin >= 0) {
if (skin_index && *skin_index != node.skin) {
lg::die("GLTF contains multiple skins, but only one skin per actor is supported.");
}
skin_index = node.skin;
}
}
return skin_index;
}
int get_joint_count(const tinygltf::Model& model, int skin_idx) {
const auto& skin = model.skins.at(skin_idx);
return skin.joints.size();
}
std::vector<float> extract_floats(const tinygltf::Model& model, int accessor_idx) {
const auto& accessor = model.accessors[accessor_idx];
const auto& buffer_view = model.bufferViews[accessor.bufferView];
const auto& buffer = model.buffers[buffer_view.buffer];
const u8* data_ptr = buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset;
const auto stride = accessor.ByteStride(buffer_view);
const auto count = accessor.count;
// ASSERT(buffer_view.target == TINYGLTF_TARGET_ARRAY_BUFFER); // ??
if (accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
lg::die("mismatched format, wanted {} but got {}", TINYGLTF_COMPONENT_TYPE_FLOAT,
accessor.componentType);
}
ASSERT(accessor.type == TINYGLTF_TYPE_SCALAR);
std::vector<float> result(accessor.count);
for (size_t x = 0; x < count; x++) {
memcpy(&result[x], data_ptr, sizeof(float));
data_ptr += stride;
}
return result;
}
std::size_t TieFullVertex::hash::operator()(const TieFullVertex& x) const {
return tfrag3::PackedTieVertices::Vertex::hash()(x.vertex) ^ std::hash<u16>()(x.color_index);
}
tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector<math::Vector<u8, 4>>& color_palette) {
tfrag3::PackedTimeOfDay colors;
colors.color_count = (color_palette.size() + 3) & (~3);
colors.data.resize(colors.color_count * 8 * 4);
for (u32 color_index = 0; color_index < color_palette.size(); color_index++) {
for (u32 palette = 0; palette < 8; palette++) {
for (u32 channel = 0; channel < 4; channel++) {
colors.read(color_index, palette, channel) = color_palette[color_index][channel];
}
}
}
return colors;
}
void process_normal_merc_draw(const tinygltf::Model& model,
MercExtractData& out,
u32 tex_offset,
tfrag3::MercEffect& eff,
int mat_idx,
const tfrag3::MercDraw& d_) {
const auto& mat = model.materials[mat_idx];
eff.all_draws.push_back(d_);
auto& draw = eff.all_draws.back();
draw.mode = gltf_util::make_default_draw_mode();
if (mat_idx == -1) {
lg::warn("Draw had a material index of -1, using default texture.");
draw.tree_tex_id = 0;
return;
}
int tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
if (tex_idx == -1) {
lg::warn("Material {} has no texture, using default texture.", mat.name);
draw.tree_tex_id = 0;
return;
}
const auto& tex = model.textures[tex_idx];
ASSERT(tex.sampler >= 0);
ASSERT(tex.source >= 0);
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(tex.sampler), &draw.mode);
gltf_util::setup_alpha_from_material(mat, &draw.mode);
const auto& img = model.images[tex.source];
draw.tree_tex_id = tex_offset + texture_pool_add_texture(&out.tex_pool, img);
};
void process_envmap_merc_draw(const tinygltf::Model& model,
MercExtractData& out,
u32 tex_offset,
tfrag3::MercEffect& eff,
int mat_idx,
const tfrag3::MercDraw& d_) {
const auto& mat = model.materials[mat_idx];
eff.all_draws.push_back(d_);
auto& draw = eff.all_draws.back();
draw.mode = gltf_util::make_default_draw_mode();
if (mat_idx == -1) {
lg::warn("Envmap draw had a material index of -1, using default texture.");
draw.tree_tex_id = texture_pool_debug_checker(&out.tex_pool);
return;
}
int base_tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
if (base_tex_idx == -1) {
lg::warn("Envmap material {} has no texture, using default texture.", mat.name);
draw.tree_tex_id = texture_pool_debug_checker(&out.tex_pool);
return;
}
const auto& base_tex = model.textures[base_tex_idx];
ASSERT(base_tex.sampler >= 0);
ASSERT(base_tex.source >= 0);
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(base_tex.sampler), &draw.mode);
gltf_util::setup_alpha_from_material(mat, &draw.mode);
const auto& roughness_tex =
model.textures.at(mat.pbrMetallicRoughness.metallicRoughnessTexture.index);
ASSERT(roughness_tex.sampler >= 0);
ASSERT(roughness_tex.source >= 0);
draw.tree_tex_id =
tex_offset + gltf_util::texture_pool_add_envmap_control_texture(
&out.tex_pool, model, base_tex.source, roughness_tex.source,
!draw.mode.get_clamp_s_enable(), !draw.mode.get_clamp_t_enable());
// now, setup envmap draw:
auto envmap_settings = gltf_util::envmap_settings_from_gltf(mat);
const auto& envmap_tex = model.textures[envmap_settings.texture_idx];
ASSERT(envmap_tex.sampler >= 0);
ASSERT(envmap_tex.source >= 0);
auto env_mode = gltf_util::make_default_draw_mode();
gltf_util::setup_draw_mode_from_sampler(model.samplers.at(envmap_tex.sampler), &env_mode);
eff.envmap_texture = tex_offset + gltf_util::texture_pool_add_texture(
&out.tex_pool, model.images[envmap_tex.source]);
env_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_DST_DST);
env_mode.enable_ab();
eff.envmap_mode = env_mode;
};
} // namespace gltf_util
+148 -5
View File
@@ -1,11 +1,13 @@
#pragma once
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
#include "common/common_types.h"
#include "common/custom_data/Tfrag3Data.h"
#include "common/log/log.h"
#include "common/math/Vector.h"
#include "third-party/tiny_gltf/tiny_gltf.h"
@@ -28,10 +30,19 @@ std::vector<u32> index_list_to_u32(const u8* data, u32 num_verts, u32 offset, u3
return result;
}
struct JointsAndWeights {
math::Vector<u8, 3> joints = math::Vector<u8, 3>::zero();
math::Vector<float, 3> weights = math::Vector<float, 3>::zero();
};
std::vector<math::Vector3f> extract_vec3f(const u8* data, u32 count, u32 stride);
std::vector<math::Vector2f> extract_vec2f(const u8* data, u32 count, u32 stride);
std::vector<math::Vector<u8, 4>> extract_color_from_vec4_u16(const u8* data, u32 count, u32 stride);
std::vector<u32> gltf_index_buffer(const tinygltf::Model& model, int indices_idx, u32 index_offset);
std::vector<math::Matrix4f> extract_mat4(const tinygltf::Model& model, int accessor_idx);
std::vector<JointsAndWeights> extract_and_flatten_joints_and_weights(
const tinygltf::Model& model,
const tinygltf::Primitive& prim);
struct ExtractedVertices {
std::vector<tfrag3::PreloadedVertex> vtx;
@@ -50,9 +61,16 @@ DrawMode make_default_draw_mode();
struct TexturePool {
std::unordered_map<std::string, int> textures_by_name;
std::vector<tfrag3::Texture> textures_by_idx;
std::map<std::pair<int, int>, int> envmap_textures_by_gltf_id;
};
int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex);
int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex, int alpha_shift = 1);
int texture_pool_add_envmap_control_texture(TexturePool* pool,
const tinygltf::Model& model,
int rgb_image_id,
int mr_image_id,
bool wrap_w,
bool wrap_h);
int texture_pool_debug_checker(TexturePool* pool);
struct NodeWithTransform {
@@ -60,12 +78,137 @@ struct NodeWithTransform {
math::Matrix4f w_T_node;
};
void dedup_vertices(const std::vector<tfrag3::PreloadedVertex>& vertices_in,
std::vector<tfrag3::PreloadedVertex>& vertices_out,
std::vector<u32>& old_to_new_out);
struct TieFullVertex {
tfrag3::PackedTieVertices::Vertex vertex;
u16 color_index = 0;
struct hash {
std::size_t operator()(const TieFullVertex& x) const;
};
bool operator==(const TieFullVertex& other) const {
return vertex == other.vertex && color_index == other.color_index;
}
};
template <typename T>
void dedup_vertices(const std::vector<T>& vertices_in,
std::vector<T>& vertices_out,
std::vector<u32>& old_to_new_out) {
ASSERT(vertices_out.empty());
ASSERT(old_to_new_out.empty());
old_to_new_out.resize(vertices_in.size(), -1);
std::unordered_map<T, u32, typename T::hash> vtx_to_new;
for (size_t in_idx = 0; in_idx < vertices_in.size(); in_idx++) {
auto& vtx = vertices_in[in_idx];
const auto& lookup = vtx_to_new.find(vtx);
if (lookup == vtx_to_new.end()) {
// first time seeing this one
size_t new_idx = vertices_out.size();
vertices_out.push_back(vtx);
old_to_new_out[in_idx] = new_idx;
vtx_to_new[vtx] = new_idx;
} else {
old_to_new_out[in_idx] = lookup->second;
}
}
}
std::vector<NodeWithTransform> flatten_nodes_from_all_scenes(const tinygltf::Model& model);
DrawMode draw_mode_from_sampler(const tinygltf::Sampler& sampler);
void setup_alpha_from_material(const tinygltf::Material& material, DrawMode* mode);
void setup_draw_mode_from_sampler(const tinygltf::Sampler& sampler, DrawMode* mode);
struct EnvmapSettings {
int texture_idx = -1;
};
EnvmapSettings envmap_settings_from_gltf(const tinygltf::Material& mat);
bool material_has_envmap(const tinygltf::Material& mat);
bool envmap_is_valid(const tinygltf::Material& mat);
/*!
* Find the index of the skin for this model. Returns nullopt if there is no skin, the index of the
* skin if there is a single skin used, or fatal error if there are multiple skins.
*/
std::optional<int> find_single_skin(const tinygltf::Model& model,
const std::vector<NodeWithTransform>& all_nodes);
int get_joint_count(const tinygltf::Model& model, int skin_idx);
template <typename T, int n>
std::vector<math::Vector<T, n>> extract_vec(const tinygltf::Model& model,
int accessor_idx,
int format) {
const auto& accessor = model.accessors[accessor_idx];
const auto& buffer_view = model.bufferViews[accessor.bufferView];
const auto& buffer = model.buffers[buffer_view.buffer];
const u8* data_ptr = buffer.data.data() + buffer_view.byteOffset + accessor.byteOffset;
const auto stride = accessor.ByteStride(buffer_view);
const auto count = accessor.count;
// ASSERT(buffer_view.target == TINYGLTF_TARGET_ARRAY_BUFFER); // ??
if (accessor.componentType != format) {
lg::die("mismatched format, wanted {} but got {}", format, accessor.componentType);
}
ASSERT(accessor.componentType == format);
switch (n) {
case 3:
ASSERT(accessor.type == TINYGLTF_TYPE_VEC3);
break;
case 4:
ASSERT(accessor.type == TINYGLTF_TYPE_VEC4);
break;
default:
ASSERT_NOT_REACHED();
}
std::vector<math::Vector<T, n>> result(accessor.count);
for (size_t x = 0; x < count; x++) {
for (int i = 0; i < n; i++) {
memcpy(&result[x][i], data_ptr + sizeof(T) * i, sizeof(T));
}
data_ptr += stride;
}
return result;
}
std::vector<float> extract_floats(const tinygltf::Model& model, int accessor_idx);
math::Matrix4f matrix_from_trs(const math::Vector3f& trans,
const math::Vector4f& quat,
const math::Vector3f& scale);
tfrag3::PackedTimeOfDay pack_time_of_day(const std::vector<math::Vector<u8, 4>>& color_palette);
struct MercExtractData {
TexturePool tex_pool;
std::vector<u32> new_indices;
std::vector<tfrag3::PreloadedVertex> new_vertices;
std::vector<math::Vector<u8, 4>> new_colors;
std::vector<math::Vector3f> normals;
std::vector<JointsAndWeights> joints_and_weights;
tfrag3::MercModel new_model;
};
// Data produced by loading a replacement model
struct MercSwapData {
std::vector<u32> new_indices;
std::vector<tfrag3::MercVertex> new_vertices;
std::vector<tfrag3::Texture> new_textures;
tfrag3::MercModel new_model;
};
void process_normal_merc_draw(const tinygltf::Model& model,
MercExtractData& out,
u32 tex_offset,
tfrag3::MercEffect& eff,
int mat_idx,
const tfrag3::MercDraw& d_);
void process_envmap_merc_draw(const tinygltf::Model& model,
MercExtractData& out,
u32 tex_offset,
tfrag3::MercEffect& eff,
int mat_idx,
const tfrag3::MercDraw& d_);
} // namespace gltf_util
+101
View File
@@ -0,0 +1,101 @@
#include "image_resize.h"
#include <cmath>
#include "common/math/Vector.h"
namespace {
struct BilinearSample {
int i0, i1;
double w0, w1;
};
BilinearSample bilinear(int src_i, double sample, bool wrap) {
BilinearSample result;
const double px_size = 1. / double(src_i);
const double px_center_f = (sample - 0.5 * px_size) / px_size;
const int px_floor = std::floor(px_center_f);
const double frac = px_center_f - double(px_floor);
if (px_center_f < 0) { // off the bottom
if (wrap) {
// wrap around!
result.i0 = 0;
result.i1 = src_i - 1;
result.w1 = -px_center_f;
result.w0 = 1. - result.w1;
} else {
// clamp to edge
result.i0 = 0;
result.i1 = 0;
result.w0 = 1;
result.w1 = 0;
}
} else if (px_floor >= (src_i - 1)) { // off the top
if (wrap) {
result.i0 = src_i - 1;
result.i1 = 0;
result.w0 = 1. - frac;
result.w1 = frac;
} else {
// clamp
result.i0 = src_i - 1;
result.i1 = src_i - 1;
result.w0 = 1;
result.w1 = 0;
}
} else {
result.i0 = px_floor;
result.i1 = px_floor + 1;
result.w0 = 1. - frac;
result.w1 = frac;
}
return result;
}
math::Vector4<u8> sample1(const u8* src, int w, int h, int x, int y) {
(void)h;
int offset = 4 * (y * w + x);
return math::Vector4<u8>(src[offset], src[offset + 1], src[offset + 2], src[offset + 3]);
}
math::Vector4<u8> sample_bilinear(const u8* src,
int w,
int h,
const BilinearSample& x,
const BilinearSample& y) {
auto p00 = sample1(src, w, h, x.i0, y.i0).cast<double>();
auto p01 = sample1(src, w, h, x.i0, y.i1).cast<double>();
auto p10 = sample1(src, w, h, x.i1, y.i0).cast<double>();
auto p11 = sample1(src, w, h, x.i1, y.i1).cast<double>();
auto p_interp = (p00 * x.w0 * y.w0 + p01 * x.w0 * y.w1 + p10 * x.w1 * y.w0 + p11 * x.w1 * y.w1);
return p_interp.cast<u8>();
}
} // namespace
void resize_rgba_image(u8* dst,
int dst_w,
int dst_h,
const u8* src,
int src_w,
int src_h,
bool wrap_w,
bool wrap_h) {
const double dst_px_h = 1. / dst_h;
const double dst_px_w = 1. / dst_w;
for (int h = 0; h < dst_h; h++) {
const float h_pos = (double(h) + 0.5) * dst_px_h;
const auto h_sample = bilinear(src_h, h_pos, wrap_h);
for (int w = 0; w < dst_w; w++) {
const float w_pos = (double(w) + 0.5) * dst_px_w;
const auto w_sample = bilinear(src_w, w_pos, wrap_w);
auto result = sample_bilinear(src, src_w, src_h, w_sample, h_sample);
for (int i = 0; i < 4; i++) {
*dst = result[i];
dst++;
}
}
}
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include "common/common_types.h"
void resize_rgba_image(u8* dst,
int dst_w,
int dst_h,
const u8* src,
int src_w,
int src_h,
bool wrap_w,
bool wrap_h);
+32
View File
@@ -2,6 +2,14 @@
#include "common/common_types.h"
#include "common/log/log.h"
#include "common/util/string_util.h"
#ifdef __APPLE__
#include <stdio.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#endif
#ifdef _WIN32
// clang-format off
@@ -104,3 +112,27 @@ void setup_cpu_info() {
CpuInfo& get_cpu_info() {
return gCpuInfo;
}
std::optional<double> get_macos_major_version() {
#ifndef __APPLE__
return {};
#else
char buffer[128];
size_t bufferlen = 128;
auto ok = sysctlbyname("kern.osproductversion", &buffer, &bufferlen, NULL, 0);
if (ok != 0) {
lg::warn("Unable to check for `kern.osproductversion` to determine macOS version");
return {};
}
try {
std::string macos_major_version = buffer;
if (str_util::contains(buffer, ".")) {
macos_major_version = str_util::split_string(macos_major_version, ".")[0];
}
return std::stod(macos_major_version);
} catch (std::exception& e) {
lg::error("Error occured when attempting to convert sysctl value {} to number", buffer);
return {};
}
#endif
}
+3
View File
@@ -1,6 +1,7 @@
#pragma once
#include <cstddef>
#include <optional>
#include <string>
size_t get_peak_rss();
@@ -16,3 +17,5 @@ struct CpuInfo {
};
CpuInfo& get_cpu_info();
std::optional<double> get_macos_major_version();
@@ -90,6 +90,9 @@ def draw_func_ob(self, context):
layout = self.layout
ob = context.object
layout.prop(ob, "set_invisible")
layout.prop(ob, "enable_custom_weights")
layout.prop(ob, "copy_eye_draws")
layout.prop(ob, "copy_mod_draws")
layout.prop(ob, "set_collision")
if (ob.set_collision):
layout.prop(ob, "ignore")
@@ -116,6 +119,9 @@ def register():
bpy.types.Object.set_invisible = bpy.props.BoolProperty(name="Invisible")
bpy.types.Object.set_collision = bpy.props.BoolProperty(name="Apply Collision Properties")
bpy.types.Object.enable_custom_weights = bpy.props.BoolProperty(name="Use Custom Bone Weights")
bpy.types.Object.copy_eye_draws = bpy.props.BoolProperty(name="Copy Eye Draws")
bpy.types.Object.copy_mod_draws = bpy.props.BoolProperty(name="Copy Mod Draws")
bpy.types.Object.ignore = bpy.props.BoolProperty(name="ignore")
bpy.types.Object.noedge = bpy.props.BoolProperty(name="No-Edge")
bpy.types.Object.noentity = bpy.props.BoolProperty(name="No-Entity")
@@ -67,21 +67,60 @@
"custom_models": ["test-actor"],
// Any textures you want to include in your custom level. This is mainly useful for things such as the zoomer HUD,
// which is not in the common level files and has no art group associated with it.
// sky textures and cases where you want to use objects drawn with the generic renderer,
// which also requires you to set a texture remap table and a list of tpages.
// To get a list of all the textures, you can extract all of the game's textures
// by setting "save_texture_pngs" to true in the decompiler config.
// The format is ["tpage-name", "texture-name1", "texture-name2", ...].
// If you want all textures from a tpage, you can just do ["tpage-name"].
"textures": [
// all textures required for the zoomer HUD
// "zoomerhud",
// "zoomerhud-dial",
// "zoomerhud-main-02",
// "zoomerhud-main-03",
// "zoomerhud-pieslice",
// "zoomerhud-heatbg-01",
// "zoomerhud-main-03arrow",
// "zoomerhud-main-03knob"
// Zoomer HUD textures
// ["zoomerhud"],
// Sandover sky textures
["village1-vis-alpha"]
],
// Which vanilla level's texture remap table to use.
// This is needed if you want to have proper textures for objects that are drawn using generic, such as
// dark eco pools or dying enemies. If you choose to use this,
// the order of art groups and tpages in your level's .gd MUST match the vanilla level's for the textures to work.
"tex_remap": "village1",
// Which sky to use for your custom level. This needs to be the name of a vanilla level with sky textures.
// Your level's mood update needs to be set up to copy the sky texture (update-mood-default already handles this as an example).
// You also need to add a specific tpage to your level .gd depending on the level you chose:
// training: tpage-1308.go
// village1: tpage-401.go
// beach: tpage-215.go
// jungle: tpage-388.go
// misty: tpage-520.go
// firecanyon: tpage-1123.go
// village2: tpage-921.go
// rolling: tpage-925.go
// sunkenb: tpage-162.go
// swamp: tpage-630.go
// ogre: tpage-1117.go
// village3: tpage-1194.go
// snow: tpage-712.go
// finalboss: tpage-1418.go
// The tpage you choose also has to be in the alpha (4th) slot in the "tpages" list below.
"sky": "village1",
// Any texture pages that are added to the level's "texture-ids" array.
// These will be logged in and linked as part of level loading.
// There are five tpage categories, in this order:
// - tfrag
// - pris
// - shrub
// - alpha
// - water
// This is also (with the exception of levels that use the zoomer) the order that the tpages are listed in in the vanilla .gd files.
// You need to also add these to your level .gd as well.
// Sky textures use the alpha slot.
// If this is empty and "tex_remap" and "sky" are the same level, this will be auto-filled with the tpages from the
// corresponding level (check its .gd file for the art group/tpage order to copy over).
"tpages": [],
// Ambients you want to use in your custom level. Ambients can be used for various things like changing the music variation (flava),
// adding ambient sounds, level name hints, etc.
"ambients": [
@@ -97,10 +136,10 @@
}
],
"actors" : [
"actors": [
{
"trans": [-21.6238, 20.0496, 17.1191], // translation
"etype": "fuel-cell", // actor type
"etype": "fuel-cell", // actor type
"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
@@ -111,11 +150,11 @@
},
{
"trans": [-15.2818, 15.2461, 17.1360], // translation
"etype": "crate", // actor type
"trans": [-15.2818, 15.2461, 17.136], // translation
"etype": "crate", // actor type
"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
"bsphere": [-15.2818, 15.2461, 17.136, 10], // bounding sphere
"lump": {
"name": "test-crate",
"crate-type": "'steel",
@@ -124,18 +163,18 @@
},
{
"trans": [-5.4630, 17.4553, 1.6169], // translation
"etype": "eco-yellow", // actor type
"trans": [-5.463, 17.4553, 1.6169], // translation
"etype": "eco-yellow", // actor type
"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
"bsphere": [-5.463, 17.4553, 1.6169, 10], // bounding sphere
"lump": {
"name": "test-eco"
}
},
{
"trans": [-5.41, 3.5, 28.42], // translation
"etype": "test-actor", // actor type
"etype": "test-actor", // actor type
"game_task": 0, // associated game task (for powercells, etc)
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-7.41, 3.5, 28.42, 10], // bounding sphere
@@ -154,4 +193,4 @@
// }
// }
]
}
}
@@ -3,9 +3,14 @@
;; the actual file name still needs to be 8.3
("TSZ.DGO"
("static-screen.o"
"test-zone-obs.o"
("test-zone-obs.o"
"tpage-398.go"
"tpage-400.go"
"tpage-399.go"
"tpage-401.go"
"tpage-1470.go"
"plat-ag.go"
"test-actor-ag.go"
"test-zone.go"
))
)
)
@@ -49,27 +49,33 @@
// 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,
// 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"],
// Any textures you want to include in your custom level.
// This is mainly useful for textures which are not in the common level files and have no art group associated with them.
// To get a list of all the textures, you can extract all of the game's textures
// by setting "save_texture_pngs" to true in the decompiler config.
"textures": [],
// If you have any custom models in the "custom_assets/jak2/models/custom_levels" folder that you want to use in your level, add them to this list.
// Note: Like with art groups, these should also be added to your level's .gd file.
"custom_models": ["test-actor"],
"actors" : [
// Any textures you want to include in your custom level.
// This is mainly useful for textures which are not in the common level files and have no art group associated with them.
// To get a list of all the textures, you can extract all of the game's textures
// by setting "save_texture_pngs" to true in the decompiler config.
// The format is ["tpage-name", "texture-name1", "texture-name2", ...].
// If you want all textures from a tpage, you can just do ["tpage-name"].
"textures": [],
"actors": [
{
"trans": [-15.2818, 15.2461, 17.1360], // translation
"etype": "crate", // actor type
"trans": [-15.2818, 15.2461, 17.136], // translation
"etype": "crate", // actor type
"game_task": 0, // associated game task (for powercells, etc)
"kill_mask": 0,
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
"bsphere": [-15.2818, 15.2461, 17.136, 10], // bounding sphere
"lump": {
"name": "test-crate",
"eco-info": ["eco-info", "(pickup-type health)", 2]
@@ -77,12 +83,12 @@
},
{
"trans": [-5.4630, 17.4553, 1.6169], // translation
"etype": "eco-yellow", // actor type
"trans": [-5.463, 17.4553, 1.6169], // translation
"etype": "eco-yellow", // actor type
"game_task": "(game-task none)", // associated game task (for powercells, etc)
"kill_mask": 0,
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere
"bsphere": [-5.463, 17.4553, 1.6169, 10], // bounding sphere
"lump": {
"name": "test-eco"
}
@@ -90,13 +96,24 @@
{
"trans": [-7.41, 13.5, 28.42], // translation
"etype": "prsn-torture", // actor type
"etype": "prsn-torture", // actor type
"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": {
"name": "test-torture"
}
},
{
"trans": [5.41, 3.5, 28.42], // translation
"etype": "test-actor", // actor type
"game_task": 0, // associated game task (for powercells, etc)
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [5.41, 3.5, 28.42, 10], // bounding sphere
"lump": {
"name": "test-actor"
}
}
]
}
}
@@ -5,5 +5,7 @@
("TSZ.DGO"
(
"prison-obs.o"
"test-zone-obs.o"
"test-actor-ag.go"
"test-zone.go"
))
@@ -49,26 +49,32 @@
// 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,
// The base actor id for your custom level. If you have multiple levels, this should be unique!
"base_id": 100,
// All art groups you want to use in your custom level. Will add their models and corresponding textures to the FR3 file.
// "art_groups": [],
// Any textures you want to include in your custom level.
// This is mainly useful for textures which are not in the common level files and have no art group associated with them.
// To get a list of all the textures, you can extract all of the game's textures
// by setting "save_texture_pngs" to true in the decompiler config.
// "textures": [],
// If you have any custom models in the "custom_assets/jak3/models/custom_levels" folder that you want to use in your level, add them to this list.
// Note: Like with art groups, these should also be added to your level's .gd file.
"custom_models": ["test-actor"],
"actors" : [
// Any textures you want to include in your custom level.
// This is mainly useful for textures which are not in the common level files and have no art group associated with them.
// To get a list of all the textures, you can extract all of the game's textures
// by setting "save_texture_pngs" to true in the decompiler config.
// The format is ["tpage-name", "texture-name1", "texture-name2", ...].
// If you want all textures from a tpage, you can just do ["tpage-name"].
"textures": [],
"actors": [
{
"trans": [-15.2818, 15.2461, 17.1360], // translation
"etype": "crate", // actor type
"trans": [-15.2818, 15.2461, 17.136], // translation
"etype": "crate", // actor type
"game_task": "(game-task none)", // associated game task (for powercells, etc)
"kill_mask": 0,
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
"bsphere": [-15.2818, 15.2461, 17.136, 10], // bounding sphere
"lump": {
"name": "test-crate",
"eco-info": ["eco-info", "(pickup-type gem)", 1]
@@ -76,15 +82,26 @@
},
{
"trans": [-5.4630, 17.4553, 1.6169], // translation
"etype": "eco-yellow", // actor type
"trans": [-5.463, 17.4553, 1.6169], // translation
"etype": "eco-yellow", // actor type
"game_task": "(game-task none)", // associated game task (for powercells, etc)
"kill_mask": 0,
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere
"bsphere": [-5.463, 17.4553, 1.6169, 10], // bounding sphere
"lump": {
"name": "test-eco"
}
},
{
"trans": [5.41, 3.5, 28.42], // translation
"etype": "test-actor", // actor type
"game_task": 0, // associated game task (for powercells, etc)
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [5.41, 3.5, 28.42, 10], // bounding sphere
"lump": {
"name": "test-actor"
}
}
]
}
}
@@ -3,6 +3,8 @@
;; the actual file name still needs to be 8.3
("TSZ.DGO"
("test-zone.go"
)
)
(
"test-zone-obs.o"
"test-actor-ag.go"
"test-zone.go"
))
+10
View File
@@ -149,6 +149,11 @@ SimpleAtom SimpleAtom::make_static_address(int static_label_id) {
return result;
}
void SimpleAtom::mark_as_no_hex() {
ASSERT(is_int() && !is_integer_promoted_to_float());
m_no_display_int_as_hex = true;
}
/*!
* Mark this atom as a float. It will be printed as a float.
* This can only be applied to an "integer" atom.
@@ -194,6 +199,8 @@ goos::Object SimpleAtom::to_form(const std::vector<DecompilerLabel>& labels, con
if (std::abs(m_int) > INT32_MAX) {
u64 v = m_int;
return pretty_print::to_symbol(fmt::format("#x{:x}", v));
} else if (m_no_display_int_as_hex) {
return goos::Object::make_integer_no_hex(m_int);
} else {
return goos::Object::make_integer(m_int);
}
@@ -346,6 +353,8 @@ std::string get_simple_expression_op_name(SimpleExpression::Kind kind) {
return "pcypld";
case SimpleExpression::Kind::VECTOR_PLUS:
return "vector+!2";
case SimpleExpression::Kind::VECTOR_XYZ_PRODUCT:
return "vector-xyz-product!";
case SimpleExpression::Kind::VECTOR_MINUS:
return "vector-!2";
case SimpleExpression::Kind::VECTOR_FLOAT_PRODUCT:
@@ -420,6 +429,7 @@ int get_simple_expression_arg_count(SimpleExpression::Kind kind) {
case SimpleExpression::Kind::VECTOR_MINUS:
case SimpleExpression::Kind::VECTOR_FLOAT_PRODUCT:
case SimpleExpression::Kind::VECTOR_CROSS:
case SimpleExpression::Kind::VECTOR_XYZ_PRODUCT:
return 3;
case SimpleExpression::Kind::SUBU_L32_S7:
return 1;
+3
View File
@@ -190,6 +190,7 @@ class SimpleAtom {
ASSERT(is_sym_ptr() || is_sym_val() || is_sym_val_ptr());
return m_string;
}
void mark_as_no_hex();
void mark_as_float();
bool is_integer_promoted_to_float() const;
float get_integer_promoted_to_float() const;
@@ -200,6 +201,7 @@ class SimpleAtom {
s64 m_int = -1; // for integer constant and static address label id
RegisterAccess m_variable;
bool m_display_int_as_float = false;
bool m_no_display_int_as_hex = false;
};
/*!
@@ -254,6 +256,7 @@ class SimpleExpression {
VECTOR_PLUS,
VECTOR_MINUS,
VECTOR_FLOAT_PRODUCT,
VECTOR_XYZ_PRODUCT, // vector*!, elementwise xyz, jak3 only
VECTOR_CROSS,
SUBU_L32_S7, // use SUBU X, src0, s7 to check if lower 32-bits are s7.
VECTOR_3_DOT,
+1
View File
@@ -238,6 +238,7 @@ TP_Type SimpleExpression::get_type(const TypeState& input,
case Kind::VECTOR_PLUS:
case Kind::VECTOR_MINUS:
case Kind::VECTOR_CROSS:
case Kind::VECTOR_XYZ_PRODUCT:
return TP_Type::make_from_ts("vector");
case Kind::VECTOR_FLOAT_PRODUCT:
return TP_Type::make_from_ts("vector");
+20 -2
View File
@@ -281,12 +281,19 @@ void LoadSourceElement::get_modified_regs(RegSet& regs) const {
/////////////////////////////
SimpleAtomElement::SimpleAtomElement(const SimpleAtom& atom, bool omit_var_cast)
: m_atom(atom), m_omit_var_cast(omit_var_cast) {
: m_atom(atom), m_omit_var_cast(omit_var_cast), m_no_hex(false) {
if (m_omit_var_cast) {
ASSERT(atom.is_var());
}
}
SimpleAtomElement::SimpleAtomElement(int int_val, bool no_hex)
: m_atom(SimpleAtom::make_int_constant(int_val)), m_omit_var_cast(false), m_no_hex(no_hex) {
if (m_no_hex) {
m_atom.mark_as_no_hex();
}
}
goos::Object SimpleAtomElement::to_form_internal(const Env& env) const {
if (m_omit_var_cast) {
return m_atom.var().to_form(env, RegisterAccess::Print::AS_VARIABLE_NO_CAST);
@@ -1851,6 +1858,8 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
return "vector-!";
case FixedOperatorKind::VECTOR_PLUS:
return "vector+!";
case FixedOperatorKind::VECTOR_XYZ_PRODUCT:
return "vector*!";
case FixedOperatorKind::VECTOR_CROSS:
return "vector-cross!";
case FixedOperatorKind::VECTOR_FLOAT_PRODUCT:
@@ -2139,6 +2148,15 @@ DerefToken to_token(const FieldReverseLookupOutput::Token& in) {
}
}
std::vector<DerefToken> to_tokens(const std::vector<FieldReverseLookupOutput::Token>& in) {
std::vector<DerefToken> ret;
ret.reserve(in.size());
for (auto& x : in) {
ret.push_back(to_token(x));
}
return ret;
}
DerefElement::DerefElement(Form* base, bool is_addr_of, DerefToken token)
: m_base(base), m_is_addr_of(is_addr_of), m_tokens({std::move(token)}) {
m_base->parent_element = this;
@@ -3175,7 +3193,7 @@ goos::Object DefskelgroupElement::ClothParams::to_list(const std::string& ag_nam
pretty_print::to_symbol(std::to_string(timestep_freq))}));
}
if (secret != 0) {
auto bits = decompile_bitfield_enum_from_int(TypeSpec("game-secrets"), env.dts->ts, flags);
auto bits = decompile_bitfield_enum_from_int(TypeSpec("game-secrets"), env.dts->ts, secret);
result.push_back(pretty_print::build_list(
{pretty_print::to_symbol("secret-disable"),
pretty_print::to_symbol(fmt::format("(game-secrets {})", fmt::join(bits, " ")))}));
+3
View File
@@ -309,6 +309,7 @@ class LoadSourceElement : public FormElement {
class SimpleAtomElement : public FormElement {
public:
explicit SimpleAtomElement(const SimpleAtom& var, bool omit_var_cast = false);
SimpleAtomElement(int int_val, bool no_hex = false);
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
@@ -324,6 +325,7 @@ class SimpleAtomElement : public FormElement {
private:
SimpleAtom m_atom;
bool m_omit_var_cast;
bool m_no_hex;
};
/*!
@@ -1272,6 +1274,7 @@ class DerefToken {
};
DerefToken to_token(const FieldReverseLookupOutput::Token& in);
std::vector<DerefToken> to_tokens(const std::vector<FieldReverseLookupOutput::Token>& in);
class DerefElement : public FormElement {
public:
+460 -68
View File
@@ -489,6 +489,38 @@ Form* cast_form(Form* in,
return pool.form<CastElement>(new_type, in);
}
Form* cast_form_from(Form* in,
const TypeSpec& old_type,
const TypeSpec& new_type,
FormPool& pool,
const Env& env,
bool tc_pass = false) {
auto& ts = env.dts->ts;
// sometimes, accessing a field is a no-op but changes the type. For example, accessing an inlined
// structure at the start of a structure. To detect this, look up all the possible derefs with no
// deref or offset, then find the highest scoring one that is the right type.
FieldReverseLookupInput lookup_input;
lookup_input.deref = std::nullopt;
lookup_input.offset = 0;
lookup_input.stride = 0;
lookup_input.base_type = old_type;
auto lookup_result = ts.reverse_field_multi_lookup(lookup_input);
if (lookup_result.success) {
for (auto& result : lookup_result.results) {
if (result.result_type == new_type) {
// it's a match!
auto form = pool.form<DerefElement>(in, result.addr_of, to_tokens(result.tokens));
form->try_as_element<DerefElement>()->inline_nested();
return form;
}
}
}
// fall back to normal casts.
return cast_form(in, new_type, pool, env, tc_pass);
}
/*!
* Pop each variable in the input list into a form. The variables should be given in the order
* they are evaluated in the source. It is safe to put the result of these in the same expression.
@@ -660,7 +692,7 @@ Form* make_cast_if_needed(Form* in,
return try_cast_simplify(in, TypeSpec("time-frame"), pool, env, true);
}
return cast_form(in, out_type, pool, env);
return cast_form_from(in, in_type, out_type, pool, env);
}
std::vector<Form*> make_casts_if_needed(const std::vector<Form*>& in,
@@ -965,7 +997,7 @@ FormElement* make_and_compact_math_op(Form* arg0,
/*!
* Update a two-argument form that uses two floats.
* This is for operations like * and + that can be nested
* (* (* a b)) -> (* a b c)
* (* (* a b) c) -> (* a b c)
* Note that we only apply this to the _first_ argument to keep the order of operations the same.
*/
void SimpleExpressionElement::update_from_stack_float_2_nestable(const Env& env,
@@ -1605,7 +1637,8 @@ void SimpleExpressionElement::update_from_stack_vector_plus_minus_cross(
for (int i = 0; i < 3; i++) {
auto arg_type = env.get_types_before_op(m_my_idx).get(m_expr.get_arg(i).var().reg());
if (arg_type.typespec() != TypeSpec("vector")) {
popped_args.at(i) = cast_form(popped_args.at(i), TypeSpec("vector"), pool, env);
popped_args.at(i) =
cast_form_from(popped_args.at(i), arg_type.typespec(), TypeSpec("vector"), pool, env);
}
}
@@ -1629,7 +1662,8 @@ void SimpleExpressionElement::update_from_stack_vector_plus_float_times(
auto arg_type = env.get_types_before_op(m_my_idx).get(m_expr.get_arg(i).var().reg());
TypeSpec desired_type(i == 3 ? "float" : "vector");
if (arg_type.typespec() != desired_type) {
popped_args.at(i) = cast_form(popped_args.at(i), desired_type, pool, env);
popped_args.at(i) =
cast_form_from(popped_args.at(i), arg_type.typespec(), desired_type, pool, env);
}
}
@@ -1654,7 +1688,8 @@ void SimpleExpressionElement::update_from_stack_vector_float_product(
auto arg_type = env.get_types_before_op(m_my_idx).get(m_expr.get_arg(i).var().reg());
TypeSpec desired_type(i == 2 ? "float" : "vector");
if (arg_type.typespec() != desired_type) {
popped_args.at(i) = cast_form(popped_args.at(i), desired_type, pool, env);
popped_args.at(i) =
cast_form_from(popped_args.at(i), arg_type.typespec(), desired_type, pool, env);
}
}
@@ -1680,7 +1715,8 @@ void SimpleExpressionElement::update_from_stack_vectors_in_common(FixedOperatorK
for (int i = 0; i < m_expr.args(); i++) {
auto arg_type = env.get_types_before_op(m_my_idx).get(m_expr.get_arg(i).var().reg());
if (arg_type.typespec() != TypeSpec("vector")) {
popped_args.at(i) = cast_form(popped_args.at(i), TypeSpec("vector"), pool, env);
popped_args.at(i) =
cast_form_from(popped_args.at(i), arg_type.typespec(), TypeSpec("vector"), pool, env);
}
}
@@ -2527,6 +2563,10 @@ void SimpleExpressionElement::update_from_stack(const Env& env,
update_from_stack_vector_plus_minus_cross(FixedOperatorKind::VECTOR_CROSS, env, pool, stack,
result, allow_side_effects);
break;
case SimpleExpression::Kind::VECTOR_XYZ_PRODUCT:
update_from_stack_vector_plus_minus_cross(FixedOperatorKind::VECTOR_XYZ_PRODUCT, env, pool,
stack, result, allow_side_effects);
break;
case SimpleExpression::Kind::VECTOR_FLOAT_PRODUCT:
update_from_stack_vector_float_product(env, pool, stack, result, allow_side_effects);
break;
@@ -2624,6 +2664,71 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
}
}
}
// (* 0.125 b) -> (/ b 8)
// adds explicit cast b to float if necessary
auto src_as_ge = dynamic_cast<GenericElement*>(m_src->back());
if (src_as_ge) {
auto mr = match(Matcher::op_fixed(FixedOperatorKind::MULTIPLICATION,
{Matcher::any_single(0), Matcher::any(1)}),
m_src);
if (mr.matched && std::abs(mr.maps.floats.at(0)) < 1 && mr.maps.floats.at(0) != 0) {
auto inverse_mult = mr.maps.floats.at(0);
float divisor_num = 1.0f / inverse_mult;
// note: float inaccuracies lead to convergent values, so we can do this safely
if ((int)divisor_num != divisor_num && 1.0f / std::roundf(divisor_num) == inverse_mult) {
lg::debug("managed to round divisor - cool !! {} -> {} ({})", divisor_num,
std::roundf(divisor_num), inverse_mult);
divisor_num = std::roundf(divisor_num);
}
int divisor_int = (int)divisor_num;
bool integer = divisor_int == divisor_num;
if (integer) {
auto elt = mr.maps.forms.at(1)->try_as_single_element();
auto b_as_simple = dynamic_cast<SimpleExpressionElement*>(elt);
// WARNING : there is an assumption here that derefs DO NOT have implicit casts!
auto b_as_deref = dynamic_cast<DerefElement*>(elt);
if (b_as_deref ||
(b_as_simple && b_as_simple->expr().kind() == SimpleExpression::Kind::IDENTITY)) {
// TODO check if op is float, cast if so
Form* divisor = nullptr;
if (divisor_num == 4096.0f) {
divisor = pool.form<ConstantTokenElement>("METER_LENGTH");
} else if (integer && divisor_int % 4096 == 0) {
divisor = pool.form<GenericElement>(
GenericOperator::make_function(pool.form<ConstantTokenElement>("meters")),
pool.form<SimpleAtomElement>(divisor_int / 4096, true));
} else if (integer && divisor_int % 2048 == 0) {
divisor = pool.form<GenericElement>(
GenericOperator::make_function(pool.form<ConstantTokenElement>("meters")),
pool.form<ConstantFloatElement>(divisor_num / (float)METER_LENGTH));
} else if (integer) {
divisor = pool.form<SimpleAtomElement>(divisor_int, true);
} else {
// this shouldn't run because of the checks before.
divisor = pool.form<ConstantFloatElement>(divisor_num);
}
if (divisor) {
if (b_as_deref || (b_as_simple->expr().is_var() &&
env.get_types_before_op(b_as_simple->expr().var().idx())
.get(b_as_simple->expr().var().reg())
.typespec() == TypeSpec("float"))) {
*m_src->back_ref() = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::DIVISION), mr.maps.forms.at(1),
divisor);
} else {
*m_src->back_ref() = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::DIVISION),
pool.form<CastElement>(TypeSpec("float"), mr.maps.forms.at(1), true), divisor);
}
m_src->back()->parent_form = m_src;
}
}
}
}
}
}
stack.push_value_to_reg(m_dst, m_src, true, m_src_type, m_var_info);
@@ -2899,6 +3004,121 @@ bool try_to_rewrite_vector_inline_ctor(const Env& env,
return false;
}
bool try_to_rewrite_matrix_inline_copy(const Env& env, FormPool& pool, FormStack& stack) {
if (env.func->name() == "(method 63 collide-shape-moving)") {
return false;
}
auto matrix_entries =
stack.try_getting_active_stack_entries({true, true, true, true, false, false, false, false});
if (matrix_entries) {
// first, check the loads. they should be something like source = (-> MAT vec quad)
// MAT should always be a variable
const char* names[] = {"rvec", "uvec", "fvec", "trans"};
std::vector<RegisterAccess> load_src_ras, store_dest_ras, store_src_ras;
for (int i = 0; i < 4; i++) {
auto deref_matcher =
Matcher::deref(Matcher::any_reg(0), false,
{DerefTokenMatcher::string(names[i]), DerefTokenMatcher::string("quad")});
auto mr = match(deref_matcher, matrix_entries->at(i).source, &env);
if (!mr.matched) {
return false;
}
load_src_ras.push_back(mr.maps.regs.at(0).value());
}
// check the stores
for (int i = 4; i < 8; i++) {
Matcher matcher = Matcher::set(Matcher::deref(Matcher::any_reg(0), false,
{DerefTokenMatcher::string(names[i - 4]),
DerefTokenMatcher::string("quad")}),
Matcher::any_reg(1));
auto mr = match(matcher, matrix_entries->at(i).elt, &env);
if (!mr.matched) {
return false;
}
store_dest_ras.push_back(mr.maps.regs.at(0).value());
store_src_ras.push_back(mr.maps.regs.at(1).value());
}
// check loads are all loading from the same matrix
for (int i = 1; i < 4; i++) {
if (load_src_ras.at(i).reg() != load_src_ras.at(0).reg()) {
return false;
}
}
// check stores are all storing to the same matrix
for (int i = 1; i < 4; i++) {
if (store_dest_ras.at(i).reg() != store_dest_ras.at(0).reg()) {
return false;
}
}
// check temps are consistent
for (int i = 0; i < 4; i++) {
if (store_src_ras.at(i).reg() != matrix_entries->at(i).destination.value().reg()) {
return false;
}
}
// check types
if (env.get_variable_type(load_src_ras.at(0), true) != TypeSpec("matrix")) {
return false;
}
if (env.get_variable_type(store_dest_ras.at(0), true) != TypeSpec("matrix")) {
return false;
}
stack.pop(8);
auto* menv = const_cast<Env*>(&env);
for (int i = 0; i < 4; i++) {
menv->disable_use(store_dest_ras.at(i));
}
auto src_repopped = stack.pop_reg(load_src_ras.at(0), {}, env, true);
if (!src_repopped) {
// lg::info("repop src failed!!");
src_repopped = var_to_form(load_src_ras.at(0), pool);
} else {
// lg::info(" popped src: {}", src_repopped->to_string(env));
}
// src_repopped = matrix_entries->at(0).source;
bool found = false;
RegisterAccess ra;
auto dst_repopped = stack.pop_reg(store_dest_ras.at(0).reg(), {}, env, true, -1, &ra, &found);
if (!dst_repopped) {
// lg::info("repop dst failed!!");
dst_repopped = var_to_form(store_dest_ras.at(0), pool);
} else {
ASSERT(found);
// lg::info(" popped dst: {} {} {}", dst_repopped->to_string(env), ra.reg().to_string(),
// ra.mode() == AccessMode::WRITE);
}
if (found) {
stack.push_value_to_reg(
ra,
pool.form<GenericElement>(
GenericOperator::make_function(pool.form<ConstantTokenElement>("matrix-copy!")),
std::vector<Form*>{dst_repopped, src_repopped}),
true, TypeSpec("matrix"));
} else {
stack.push_form_element(
pool.alloc_element<GenericElement>(
GenericOperator::make_function(pool.form<ConstantTokenElement>("matrix-copy!")),
std::vector<Form*>{dst_repopped, src_repopped}),
true);
}
return true;
}
return false;
}
bool try_to_rewrite_matrix_inline_ctor(const Env& env, FormPool& pool, FormStack& stack) {
// now, let's check for a matrix initialization.
auto matrix_entries = stack.try_getting_active_stack_entries({true, false, false, false, false});
@@ -2918,54 +3138,79 @@ bool try_to_rewrite_matrix_inline_ctor(const Env& env, FormPool& pool, FormStack
// zeroing the rows:
std::vector<RegisterAccess> write_vars;
if (env.version == GameVersion::Jak1) {
for (int i = 0; i < 4; i++) {
auto elt = matrix_entries->at(i + 1).elt;
switch (env.version) {
case GameVersion::Jak1: {
for (int i = 0; i < 4; i++) {
auto elt = matrix_entries->at(i + 1).elt;
auto matcher = Matcher::set(
Matcher::deref(Matcher::any_reg(0), false,
{DerefTokenMatcher::string("vector"), DerefTokenMatcher::integer(i),
DerefTokenMatcher::string("quad")}),
Matcher::cast("uint128", Matcher::integer(0)));
auto mr = match(matcher, elt);
if (mr.matched) {
if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) {
return false;
}
write_vars.push_back(*mr.maps.regs.at(0));
} else {
return false;
}
}
} else {
for (int i = 0; i < 4; i++) {
auto elt = matrix_entries->at(i + 1).elt;
Matcher matcher;
if (i == 3) {
matcher = Matcher::set(Matcher::deref(Matcher::any_reg(0), false,
{DerefTokenMatcher::string("trans"),
DerefTokenMatcher::string("quad")}),
Matcher::cast("uint128", Matcher::integer(0)));
} else {
matcher = Matcher::set(
auto matcher = Matcher::set(
Matcher::deref(Matcher::any_reg(0), false,
{DerefTokenMatcher::string("quad"), DerefTokenMatcher::integer(i)}),
{DerefTokenMatcher::string("vector"), DerefTokenMatcher::integer(i),
DerefTokenMatcher::string("quad")}),
Matcher::cast("uint128", Matcher::integer(0)));
}
auto mr = match(matcher, elt);
if (mr.matched) {
if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) {
auto mr = match(matcher, elt);
if (mr.matched) {
if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) {
return false;
}
write_vars.push_back(*mr.maps.regs.at(0));
} else {
return false;
}
write_vars.push_back(*mr.maps.regs.at(0));
} else {
return false;
}
}
} break;
case GameVersion::Jak2: {
for (int i = 0; i < 4; i++) {
auto elt = matrix_entries->at(i + 1).elt;
Matcher matcher;
if (i == 3) {
matcher = Matcher::set(Matcher::deref(Matcher::any_reg(0), false,
{DerefTokenMatcher::string("trans"),
DerefTokenMatcher::string("quad")}),
Matcher::cast("uint128", Matcher::integer(0)));
} else {
matcher = Matcher::set(
Matcher::deref(Matcher::any_reg(0), false,
{DerefTokenMatcher::string("quad"), DerefTokenMatcher::integer(i)}),
Matcher::cast("uint128", Matcher::integer(0)));
}
auto mr = match(matcher, elt);
if (mr.matched) {
if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) {
return false;
}
write_vars.push_back(*mr.maps.regs.at(0));
} else {
return false;
}
}
} break;
case GameVersion::Jak3: {
for (int i = 0; i < 4; i++) {
auto elt = matrix_entries->at(i + 1).elt;
const char* names[] = {"rvec", "uvec", "fvec", "trans"};
Matcher matcher = Matcher::set(Matcher::deref(Matcher::any_reg(0), false,
{DerefTokenMatcher::string(names[i]),
DerefTokenMatcher::string("quad")}),
Matcher::cast("uint128", Matcher::integer(0)));
auto mr = match(matcher, elt);
if (mr.matched) {
if (var_name != env.get_variable_name(*mr.maps.regs.at(0))) {
return false;
}
write_vars.push_back(*mr.maps.regs.at(0));
} else {
return false;
}
}
} break;
}
// success!
@@ -2985,6 +3230,70 @@ bool try_to_rewrite_matrix_inline_ctor(const Env& env, FormPool& pool, FormStack
return false;
}
bool is_deref_to_quad(DerefElement* deref) {
return deref && !deref->is_addr_of() && !deref->tokens().empty() &&
deref->tokens().back().is_field_name("quad");
}
Form* pop_last_deref_token(Form* form) {
auto deref = form->try_as_element<DerefElement>();
ASSERT(deref);
if (deref->tokens().size() == 1) {
return deref->base();
} else {
deref->tokens().pop_back();
return form;
}
}
FormElement* try_to_rewrite_vector_copy(Form* dst,
const TypeSpec& dst_type,
Form* src,
const TypeSpec& src_type,
FormPool& pool,
const Env& env) {
if (env.func->name() == "vector-copy!") {
return nullptr;
}
if (dst && src) {
// check types
if (dst_type != TypeSpec("vector")) {
return nullptr;
}
// kinda sus - we really want to check the place where this was loaded...
if (src_type != TypeSpec("uint128")) {
return nullptr;
}
auto* dst_deref = dst->try_as_element<DerefElement>();
auto* src_deref = src->try_as_element<DerefElement>();
if (!dst_deref) {
return nullptr;
}
if (!src_deref) {
return nullptr;
}
if (!is_deref_to_quad(dst_deref)) {
return nullptr;
}
if (!is_deref_to_quad(src_deref)) {
return nullptr;
}
auto ret = pool.alloc_element<GenericElement>(
GenericOperator::make_function(pool.form<ConstantTokenElement>("vector-copy!")),
std::vector<Form*>{pop_last_deref_token(dst), pop_last_deref_token(src)});
// lg::info("success: {}\n", ret->to_string(env));
return ret;
}
return nullptr;
}
} // namespace
void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
@@ -3001,14 +3310,27 @@ void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& s
if (size() == 16) {
std::swap(popped.at(0), popped.at(1));
}
m_dst->try_as_element<DerefElement>()->set_base(
make_optional_cast(m_dst_cast_type, popped.at(1), pool, env));
auto dst_deref = m_dst->try_as_element<DerefElement>();
dst_deref->set_base(make_optional_cast(m_dst_cast_type, popped.at(1), pool, env));
m_dst->mark_popped();
m_dst->try_as_element<DerefElement>()->inline_nested();
auto fr = pool.alloc_element<SetFormFormElement>(
m_dst, make_optional_cast(m_src_cast_type, popped.at(0), pool, env));
// so the bitfield set check can run
fr->mark_popped();
dst_deref->inline_nested();
FormElement* fr = nullptr;
// hack: for now only do this on Jak 3
if (size() == 16 && env.version == GameVersion::Jak3) {
fr = try_to_rewrite_vector_copy(
m_dst, env.get_variable_type(m_base_var, true), popped.at(0),
m_src_cast_type.value_or(env.get_variable_type(m_expr.var(), true)), pool, env);
}
if (!fr) {
fr = pool.alloc_element<SetFormFormElement>(
m_dst, make_optional_cast(m_src_cast_type, popped.at(0), pool, env));
// so the bitfield set check can run
fr->mark_popped();
}
fr->push_to_stack(env, pool, stack);
} else {
auto vars = std::vector<RegisterAccess>({m_base_var});
@@ -3027,7 +3349,9 @@ void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& s
if (!try_to_rewrite_matrix_inline_ctor(env, pool, stack)) {
if (!try_to_rewrite_vector_inline_ctor(env, pool, stack, "vector")) {
try_to_rewrite_vector_inline_ctor(env, pool, stack, "quaternion");
if (!try_to_rewrite_vector_inline_ctor(env, pool, stack, "quaternion")) {
try_to_rewrite_matrix_inline_copy(env, pool, stack);
}
}
}
}
@@ -3266,8 +3590,8 @@ void FunctionCallElement::update_from_stack(const Env& env,
auto desired_arg_type = function_type.get_arg(arg_id);
if (env.dts->should_attempt_cast_simplify(desired_arg_type, actual_arg_type)) {
arg_forms.push_back(cast_form(val, desired_arg_type, pool, env,
env.dts->ts.tc(desired_arg_type, actual_arg_type)));
arg_forms.push_back(cast_form_from(val, actual_arg_type, desired_arg_type, pool, env,
env.dts->ts.tc(desired_arg_type, actual_arg_type)));
} else {
arg_forms.push_back(val);
}
@@ -4161,11 +4485,11 @@ void DerefElement::update_from_stack(const Env& env,
}
void DerefElement::inline_nested() {
auto as_deref = dynamic_cast<DerefElement*>(m_base->try_as_single_element());
if (as_deref) {
if (!m_is_addr_of && !as_deref->is_addr_of()) {
m_tokens.insert(m_tokens.begin(), as_deref->tokens().begin(), as_deref->tokens().end());
m_base = as_deref->m_base;
auto inner = dynamic_cast<DerefElement*>(m_base->try_as_single_element());
if (inner) {
if (!inner->is_addr_of()) {
m_tokens.insert(m_tokens.begin(), inner->tokens().begin(), inner->tokens().end());
m_base = inner->m_base;
}
}
}
@@ -4314,6 +4638,67 @@ Form* try_rewrite_as_process_to_ppointer(CondNoElseElement* value,
GenericOperator::make_fixed(FixedOperatorKind::PROCESS_TO_PPOINTER), repopped);
}
/*!
* (if (type? foo bar)
* foo
* )
*/
Form* try_rewrite_as_as_type(CondNoElseElement* value,
FormStack& stack,
FormPool& pool,
const Env& env,
const TypeSpec& resulting_type) {
if (value->entries.size() != 1) {
return nullptr;
}
auto condition = value->entries.at(0).condition;
auto body = value->entries[0].body;
auto condition_matcher = Matcher::op(
GenericOpMatcher::condition(IR2_Condition::Kind::TRUTHY),
{Matcher::func(Matcher::symbol("type?"), {Matcher::any_reg(0), Matcher::any_symbol(1)})});
auto condition_mr = match(condition_matcher, condition);
if (!condition_mr.matched) {
return nullptr;
}
auto body_matcher = Matcher::any_reg(0);
auto body_mr = match(body_matcher, body);
if (!body_mr.matched) {
body_mr = match(Matcher::cast_to_any(1, body_matcher), body);
if (!body_mr.matched) {
return nullptr;
}
}
auto body_var = body_mr.maps.regs.at(0).value();
auto condition_var = condition_mr.maps.regs.at(0).value();
auto* menv = const_cast<Env*>(&env);
menv->disable_use(body_var);
auto repopped = stack.pop_reg(condition_var, {}, env, true);
if (!repopped) {
repopped = var_to_form(condition_var, pool);
}
auto new_type = condition_mr.maps.strings.at(1);
auto result = pool.form<GenericElement>(
GenericOperator::make_function(pool.form<ConstantTokenElement>("as-type")),
std::vector<Form*>{repopped, pool.form<ConstantTokenElement>(new_type)});
// silly cast situation:
// sometimes there is something dumb like (the specific (as-type foo general))
// we have to make sure that we keep the leading cast.
// HACK: inserting casts more aggressively in Jak 2 because I am too lazy to fix up all the
// slightly wrong casts that matter now.
if (resulting_type != TypeSpec(new_type) &&
(env.version == GameVersion::Jak2 || env.dts->ts.tc(TypeSpec(new_type), resulting_type))) {
return pool.form<CastElement>(resulting_type, result);
} else {
return result;
}
}
// (if x (-> x 0 self)) -> (ppointer->process x)
Form* try_rewrite_as_pppointer_to_process(CondNoElseElement* value,
FormStack& stack,
@@ -4486,11 +4871,18 @@ void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack&
stack.push_value_to_reg(write_as_value, as_ja_group, true,
env.get_variable_type(final_destination, false));
} else {
// lg::print("func {} final destination {} type {}\n", env.func->name(),
// final_destination.to_string(env),
// env.get_variable_type(final_destination, false).print());
stack.push_value_to_reg(write_as_value, pool.alloc_single_form(nullptr, this), true,
env.get_variable_type(final_destination, false));
auto as_as_type = try_rewrite_as_as_type(this, stack, pool, env,
env.get_variable_type(final_destination, true));
if (as_as_type) {
stack.push_value_to_reg(write_as_value, as_as_type, true,
env.get_variable_type(final_destination, false));
} else {
// lg::print("func {} final destination {} type {}\n", env.func->name(),
// final_destination.to_string(env),
// env.get_variable_type(final_destination, false).print());
stack.push_value_to_reg(write_as_value, pool.alloc_single_form(nullptr, this), true,
env.get_variable_type(final_destination, false));
}
}
}
}
@@ -5713,7 +6105,7 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
as_cast->set_type(func_type);
return_code->push_back(as_cast);
} else {
return_code = cast_form(return_code, func_type, pool, env);
return_code = cast_form_from(return_code, *return_type, func_type, pool, env);
return_code->parent_element = this;
}
}
+72
View File
@@ -91,6 +91,14 @@ Matcher Matcher::cast(const std::string& type, Matcher value) {
return m;
}
Matcher Matcher::numeric_cast(const std::string& type, Matcher value) {
Matcher m;
m.m_kind = Kind::NUMERIC_CAST;
m.m_str = type;
m.m_sub_matchers = {value};
return m;
}
Matcher Matcher::cast_to_any(int type_out, Matcher value) {
Matcher m;
m.m_kind = Kind::CAST_TO_ANY;
@@ -127,6 +135,13 @@ Matcher Matcher::single(std::optional<float> value) {
return m;
}
Matcher Matcher::any_single(int match_id) {
Matcher m;
m.m_kind = Kind::ANY_FLOAT;
m.m_float_out_id = match_id;
return m;
}
Matcher Matcher::any_quoted_symbol(int match_id) {
Matcher m;
m.m_kind = Kind::ANY_QUOTED_SYMBOL;
@@ -211,6 +226,13 @@ Matcher Matcher::while_loop(const Matcher& condition, const Matcher& body) {
return m;
}
Matcher Matcher::until_loop(const Matcher& condition, const Matcher& body) {
Matcher m;
m.m_kind = Kind::UNTIL_LOOP;
m.m_sub_matchers = {condition, body};
return m;
}
Matcher Matcher::any_constant_token(int match_id) {
Matcher m;
m.m_kind = Kind::ANY_CONSTANT_TOKEN;
@@ -398,6 +420,16 @@ bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out, const Env* cons
return false;
} break;
case Kind::NUMERIC_CAST: {
auto as_cast = dynamic_cast<CastElement*>(input->try_as_single_active_element());
if (as_cast && as_cast->numeric()) {
if (as_cast->type().print() == m_str) {
return m_sub_matchers.at(0).do_match(as_cast->source(), maps_out, env);
}
}
return false;
} break;
case Kind::CAST_TO_ANY: {
auto as_cast = dynamic_cast<CastElement*>(input->try_as_single_active_element());
if (as_cast) {
@@ -470,6 +502,30 @@ bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out, const Env* cons
return false;
} break;
case Kind::ANY_FLOAT: {
auto as_const_float =
dynamic_cast<ConstantFloatElement*>(input->try_as_single_active_element());
if (as_const_float) {
if (m_float_out_id != -1) {
maps_out->floats[m_float_out_id] = as_const_float->value();
}
return true;
}
auto as_expr = dynamic_cast<SimpleExpressionElement*>(input->try_as_single_active_element());
if (as_expr && as_expr->expr().is_identity()) {
const auto& atom = as_expr->expr().get_arg(0);
if (atom.is_integer_promoted_to_float()) {
if (m_float_out_id != -1) {
maps_out->floats[m_float_out_id] = atom.get_integer_promoted_to_float();
}
return true;
}
}
return false;
} break;
case Kind::ANY_QUOTED_SYMBOL: {
auto as_simple_atom = dynamic_cast<SimpleAtomElement*>(input->try_as_single_active_element());
if (as_simple_atom) {
@@ -671,6 +727,22 @@ bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out, const Env* cons
return true;
} break;
case Kind::UNTIL_LOOP: {
auto as_until = dynamic_cast<UntilElement*>(input->try_as_single_active_element());
if (!as_until) {
return false;
}
if (!m_sub_matchers.at(0).do_match(as_until->condition, maps_out, env)) {
return false;
}
if (!m_sub_matchers.at(1).do_match(as_until->body, maps_out, env)) {
return false;
}
return true;
} break;
case Kind::BEGIN: {
if ((int)m_sub_matchers.size() != input->size()) {
return false;
+8
View File
@@ -21,6 +21,7 @@ struct MatchResult {
std::unordered_map<int, Form*> forms;
std::unordered_map<int, s64> label;
std::unordered_map<int, s64> ints;
std::unordered_map<int, float> floats;
} maps;
Form* int_or_form_to_form(FormPool& pool, int key_idx) {
@@ -51,11 +52,13 @@ class Matcher {
static Matcher set_var(const Matcher& src, int dst_match_id); // var-form
static Matcher match_or(const std::vector<Matcher>& args);
static Matcher cast(const std::string& type, Matcher value);
static Matcher numeric_cast(const std::string& type, Matcher value);
static Matcher cast_to_any(int type_out, Matcher value);
static Matcher any(int match_id = -1);
static Matcher integer(std::optional<int> value);
static Matcher any_integer(int match_id = -1);
static Matcher single(std::optional<float> value);
static Matcher any_single(int match_id = -1);
static Matcher any_reg_cast_to_int_or_uint(int match_id = -1);
static Matcher any_quoted_symbol(int match_id = -1);
static Matcher any_symbol(int match_id = -1);
@@ -69,6 +72,7 @@ class Matcher {
const Matcher& false_case);
static Matcher if_no_else(const Matcher& condition, const Matcher& true_case);
static Matcher while_loop(const Matcher& condition, const Matcher& body);
static Matcher until_loop(const Matcher& condition, const Matcher& body);
static Matcher any_constant_token(int match_id = -1);
static Matcher constant_token(const std::string& name);
static Matcher or_expression(const std::vector<Matcher>& elts);
@@ -85,11 +89,13 @@ class Matcher {
GENERIC_OP_WITH_REST,
OR,
CAST,
NUMERIC_CAST,
CAST_TO_ANY,
ANY,
INT,
ANY_INT,
FLOAT,
ANY_FLOAT,
ANY_QUOTED_SYMBOL,
ANY_SYMBOL,
DEREF_OP,
@@ -100,6 +106,7 @@ class Matcher {
IF_WITH_ELSE,
IF_NO_ELSE,
WHILE_LOOP,
UNTIL_LOOP,
ANY_CONSTANT_TOKEN,
CONSTANT_TOKEN,
SC_OR,
@@ -130,6 +137,7 @@ class Matcher {
int m_form_match;
int m_label_out_id;
int m_int_out_id;
int m_float_out_id;
};
std::optional<int> m_int_match;
std::optional<float> m_float_match;
+1
View File
@@ -162,6 +162,7 @@ enum class FixedOperatorKind {
VECTOR_MINUS,
VECTOR_CROSS,
VECTOR_FLOAT_PRODUCT,
VECTOR_XYZ_PRODUCT,
L32_NOT_FALSE_CBOOL,
VECTOR_3_DOT,
PROCESS_TO_PPOINTER,
+7 -7
View File
@@ -207,6 +207,13 @@ std::string OpenGOALAsm::full_function_name() {
func_name = fmt::format(fmt::runtime(func_name), bc);
}
}
// Handle destination masks
if (func.allows_modifier(MOD::DEST_MASK) && m_instr.cop2_dest != 0xff &&
m_instr.cop2_dest != 15) {
func_name += m_instr.cop2_dest_to_char();
}
return func_name;
}
@@ -270,13 +277,6 @@ std::vector<goos::Object> OpenGOALAsm::get_args(const std::vector<DecompilerLabe
args.push_back(pretty_print::to_symbol("acc"));
}
// Handle destination masks
if (func.allows_modifier(MOD::DEST_MASK) && m_instr.cop2_dest != 0xff &&
m_instr.cop2_dest != 15) {
named_args.push_back(
pretty_print::to_symbol(fmt::format(":mask #b{:b}", m_instr.cop2_dest_mask_intel())));
}
// Some functions are configured, or its easiest to swap the source args
// NOTE - this currently assumes it is the first two args that must be swapped
if (func.allows_modifier(MOD::SWAP_FIRST_TWO_SOURCE_ARGS)) {
+5 -4
View File
@@ -231,10 +231,11 @@ ObjectFileDB::ObjectFileDB(const std::vector<fs::path>& _dgos,
StrFileReader reader(obj, version());
// name from the file name
std::string base_name = obj_filename_to_name(obj.string());
ASSERT(reader.chunk_count() == 1);
auto name = reader.get_texture_name();
add_obj_from_dgo(name, name, reader.get_chunk(0).data(), reader.get_chunk(0).size(),
"TEXSPOOL", config, name);
for (int i = 0; i < reader.chunk_count(); i++) {
auto name = reader.get_chunk_texture_name(i);
add_obj_from_dgo(name, name, reader.get_chunk(i).data(), reader.get_chunk(i).size(),
"TEXSPOOL", config, name);
}
}
}
+11 -1
View File
@@ -79,12 +79,15 @@ struct LetRewriteStats {
int with_dma_buf_add_bucket = 0;
int dma_buffer_add_gs_set = 0;
int launch_particles = 0;
int call_parent_state_handler = 0;
int suspend_for = 0;
int font_method = 0;
int total() const {
return dotimes + countdown + abs + abs2 + unused + ja + case_no_else + case_with_else +
set_vector + set_vector2 + send_event + font_context_meth + proc_new + attack_info +
vector_dot + rand_float_gen + set_let + with_dma_buf_add_bucket + dma_buffer_add_gs_set +
launch_particles;
launch_particles + call_parent_state_handler + suspend_for + font_method;
}
std::string print() const {
@@ -111,6 +114,9 @@ struct LetRewriteStats {
out += fmt::format(" with_dma_buf_add_bucket: {}\n", with_dma_buf_add_bucket);
out += fmt::format(" dma_buffer_add_gs_set: {}\n", dma_buffer_add_gs_set);
out += fmt::format(" launch_particles: {}\n", launch_particles);
out += fmt::format(" call_parent_state_handler: {}\n", call_parent_state_handler);
out += fmt::format(" suspend_for: {}\n", suspend_for);
out += fmt::format(" font_method: {}\n", font_method);
return out;
}
@@ -135,6 +141,8 @@ struct LetRewriteStats {
result.set_let = rand_float_gen + other.set_let;
result.with_dma_buf_add_bucket = rand_float_gen + other.with_dma_buf_add_bucket;
result.launch_particles = launch_particles + other.launch_particles;
result.call_parent_state_handler = call_parent_state_handler + other.call_parent_state_handler;
result.suspend_for = suspend_for + other.suspend_for;
return result;
}
@@ -158,6 +166,8 @@ struct LetRewriteStats {
set_let += other.set_let;
with_dma_buf_add_bucket += other.with_dma_buf_add_bucket;
launch_particles += other.launch_particles;
call_parent_state_handler += other.call_parent_state_handler;
suspend_for += other.suspend_for;
return *this;
}
};
+61
View File
@@ -1689,6 +1689,62 @@ std::unique_ptr<AtomicOp> convert_vector_plus(const Instruction& i0,
idx);
}
std::unique_ptr<AtomicOp> convert_vector_xyz_product(const Instruction& i0,
const Instruction& i1,
const Instruction& i2,
const Instruction& i3,
const Instruction& i4,
int idx) {
/*
lqc2 vf4, 0(a1)
lqc2 vf5, 0(a2)
vaddx.w vf6, vf0, vf0
vmul.xyz vf6, vf4, vf5
sqc2 vf6, 0(a0)
*/
// lqc2 vf4, 0(a1) (src1)
if (i0.kind != InstructionKind::LQC2 || i0.get_dst(0).get_reg() != make_vf(4) ||
!i0.get_src(0).is_imm(0)) {
return nullptr;
}
Register src1 = i0.get_src(1).get_reg();
// lqc2 vf5, 0(a2) (src2)
if (i1.kind != InstructionKind::LQC2 || i1.get_dst(0).get_reg() != make_vf(5) ||
!i1.get_src(0).is_imm(0)) {
return nullptr;
}
Register src2 = i1.get_src(1).get_reg();
// vaddx.w vf6, vf0, vf0
if (i2.kind != InstructionKind::VADD_BC || i2.get_dst(0).get_reg() != make_vf(6) ||
i2.get_src(0).get_reg() != make_vf(0) || i2.get_src(1).get_reg() != make_vf(0) ||
i2.cop2_dest != 1 || i2.cop2_bc != 0) {
return nullptr;
}
// vmul.xyz vf6, vf4, vf5
if (i3.kind != InstructionKind::VMUL || i3.get_dst(0).get_reg() != make_vf(6) ||
i3.get_src(0).get_reg() != make_vf(4) || i3.get_src(1).get_reg() != make_vf(5) ||
i3.cop2_dest != 14) {
return nullptr;
}
// sqc2 vf6, 0(a0) (dst)
if (i4.kind != InstructionKind::SQC2 || i4.get_src(0).get_reg() != make_vf(6) ||
!i4.get_src(1).is_imm(0)) {
return nullptr;
}
Register dst = i4.get_src(2).get_reg();
return std::make_unique<SetVarOp>(
make_dst_var(dst, idx),
SimpleExpression(SimpleExpression::Kind::VECTOR_XYZ_PRODUCT, make_src_atom(dst, idx),
make_src_atom(src1, idx), make_src_atom(src2, idx)),
idx);
}
std::unique_ptr<AtomicOp> convert_vector_minus(const Instruction& i0,
const Instruction& i1,
const Instruction& i2,
@@ -1819,6 +1875,11 @@ std::unique_ptr<AtomicOp> convert_5(const Instruction& i0,
return as_vector_plus;
}
auto as_vector_xyz = convert_vector_xyz_product(i0, i1, i2, i3, i4, idx);
if (as_vector_xyz) {
return as_vector_xyz;
}
auto as_vector_minus = convert_vector_minus(i0, i1, i2, i3, i4, idx);
if (as_vector_minus) {
return as_vector_minus;
+248 -13
View File
@@ -1673,6 +1673,99 @@ FormElement* rewrite_part_tracker_new(const std::string& type,
->try_as_single_element();
}
FormElement* rewrite_call_parent_state_handler(LetElement* in, const Env& env, FormPool& pool) {
// (let ((t9-3 (-> (find-parent-state) code)))
// (if t9-3
// ((the-as (function none) t9-3))
// )
// )
auto mr =
Matcher::let(false,
{LetEntryMatcher::any(Matcher::deref(Matcher::func("find-parent-state", {}),
false, {DerefTokenMatcher::any_string(1)}),
0)},
{Matcher::if_no_else(Matcher::any(), Matcher::any(2))});
auto let_mr = match(mr, in);
if (!let_mr.matched) {
return nullptr;
}
auto handler = let_mr.maps.strings.at(1);
auto valid_handlers = {"enter", "trans", "code", "post"};
if (std::find(valid_handlers.begin(), valid_handlers.end(), handler) != valid_handlers.end()) {
std::vector<Form*> macro_args;
macro_args.push_back(pool.form<ConstantTokenElement>(handler));
// there are no examples of this being used with args, so that is not handled for now...
// auto func = let_mr.maps.forms.at(2);
return pool
.form<GenericElement>(GenericOperator::make_function(
pool.form<ConstantTokenElement>("call-parent-state-handler")),
macro_args)
->try_as_single_element();
}
return nullptr;
}
FormElement* rewrite_suspend_for(LetElement* in, const Env& env, FormPool& pool) {
// (let ((gp-1 (current-time)))
// (until (time-elapsed? gp-1 (seconds 0.5))
// (suspend)
// )
// )
// ->
// (suspend-for (seconds 0.5))
auto until = dynamic_cast<UntilElement*>(in->body()->at(0));
if (!until) {
return nullptr;
}
auto mr = Matcher::let(
false, {LetEntryMatcher::any(Matcher::func("current-time", {}), 0)},
{Matcher::until_loop(Matcher::func("time-elapsed?", {Matcher::any_reg(1), Matcher::any(2)}),
Matcher::any(3))});
auto let_mr = match(mr, in);
if (!let_mr.matched) {
return nullptr;
}
auto var = let_mr.maps.regs.at(1);
auto time = let_mr.maps.forms.at(2);
auto body = let_mr.maps.forms.at(3);
std::vector<Form*> macro_args;
std::vector<FormElement*> macro_elts;
macro_args.push_back(time);
for (auto& elt : body->elts()) {
auto op = dynamic_cast<AtomicOpElement*>(elt);
auto suspend = op && op->op() && dynamic_cast<SpecialOp*>(op->op()) &&
dynamic_cast<SpecialOp*>(op->op())->kind() == SpecialOp::Kind::SUSPEND;
if (!suspend || elt != body->elts().back()) {
elt->apply_form([&](Form* form) {
for (auto& e : form->elts()) {
auto as_expr = dynamic_cast<SimpleExpressionElement*>(e);
if (as_expr) {
RegAccessSet regs;
as_expr->collect_vars(regs, false);
for (auto reg : regs) {
if (reg.to_string(env, RegisterAccess::Print::AS_VARIABLE) ==
var.value().to_string(env, RegisterAccess::Print::AS_VARIABLE)) {
e = pool.alloc_element<ConstantTokenElement>("time");
}
}
}
}
});
macro_elts.push_back(elt);
}
}
if (!macro_elts.empty()) {
for (auto elt : macro_elts) {
macro_args.push_back(pool.alloc_single_form(nullptr, elt));
}
}
return pool
.form<GenericElement>(
GenericOperator::make_function(pool.form<ConstantTokenElement>("suspend-for")),
macro_args)
->try_as_single_element();
}
FormElement* rewrite_proc_new(LetElement* in, const Env& env, FormPool& pool) {
// this function checks for the process-spawn macros.
// it uses recursive form scanning to wrap the macro inside a potential "shell"
@@ -2119,6 +2212,50 @@ FormElement* rewrite_attack_info(LetElement* in, const Env& env, FormPool& pool)
return elt;
}
FormElement* rewrite_set_font_single(LetElement* in,
const Env& env,
FormPool& pool,
const char* deref_name,
const char* op_name,
bool cast_to_float) {
/*
(let ((v1-10 gp-0))
(set! (-> v1-10 scale) 0.6)
)
*/
if (in->entries().size() != 1) {
return nullptr;
}
if (in->body()->elts().size() != 1) {
return nullptr;
}
Form* font_obj_expr = in->entries().at(0).src;
RegisterAccess font_obj_reg = in->entries().at(0).dest;
if (env.get_variable_type(font_obj_reg, true) != TypeSpec("font-context")) {
return nullptr;
}
auto src_matcher =
cast_to_float ? Matcher::numeric_cast("float", Matcher::any(0)) : Matcher::any(0);
Matcher set_matcher = Matcher::set(Matcher::deref(Matcher::reg(font_obj_reg.reg()), false,
{DerefTokenMatcher::string(deref_name)}),
src_matcher);
auto set_mr = match(set_matcher, in->body()->at(0));
if (!set_mr.matched) {
return nullptr;
}
auto elt = pool.alloc_element<GenericElement>(
GenericOperator::make_function(pool.form<ConstantTokenElement>(op_name)),
std::vector<Form*>{font_obj_expr, set_mr.maps.forms.at(0)});
elt->parent_form = in->parent_form;
return elt;
}
/*!
* Attempt to rewrite a let as another form. If it cannot be rewritten, this will return nullptr.
*/
@@ -2185,6 +2322,12 @@ FormElement* rewrite_let(LetElement* in, const Env& env, FormPool& pool, LetRewr
return as_set_vector3;
}
auto suspend_for = rewrite_suspend_for(in, env, pool);
if (suspend_for) {
stats.suspend_for++;
return suspend_for;
}
auto as_abs_2 = fix_up_abs_2(in, env, pool);
if (as_abs_2) {
stats.abs2++;
@@ -2215,6 +2358,30 @@ FormElement* rewrite_let(LetElement* in, const Env& env, FormPool& pool, LetRewr
return as_attack_info;
}
auto as_call_parent_state = rewrite_call_parent_state_handler(in, env, pool);
if (as_call_parent_state) {
stats.call_parent_state_handler++;
return as_call_parent_state;
}
auto as_font_scale = rewrite_set_font_single(in, env, pool, "scale", "set-scale!", false);
if (as_font_scale) {
stats.font_method++;
return as_font_scale;
}
auto as_font_width = rewrite_set_font_single(in, env, pool, "width", "set-width!", true);
if (as_font_width) {
stats.font_method++;
return as_font_width;
}
auto as_font_height = rewrite_set_font_single(in, env, pool, "height", "set-height!", true);
if (as_font_height) {
stats.font_method++;
return as_font_height;
}
// nothing matched.
return nullptr;
}
@@ -2582,6 +2749,59 @@ FormElement* rewrite_with_dma_buf_add_bucket(LetElement* in, const Env& env, For
return elt;
}
FormElement* rewrite_set_font_origin(LetElement* in, const Env& env, FormPool& pool) {
/*
(let ((v1-9 gp-0)
(a1-1 36)
(a0-4 140)
)
(set! (-> v1-9 origin x) (the float a1-1))
(set! (-> v1-9 origin y) (the float a0-4))
)
*/
if (in->entries().size() != 3) {
return nullptr;
}
if (in->body()->elts().size() != 2) {
return nullptr;
}
Form* font_obj_expr = in->entries().at(0).src;
RegisterAccess font_obj_reg = in->entries().at(0).dest;
if (env.get_variable_type(font_obj_reg, true) != TypeSpec("font-context")) {
return nullptr;
}
Form* x_val = in->entries().at(1).src;
Form* y_val = in->entries().at(2).src;
Matcher x_matcher = Matcher::set(
Matcher::deref(Matcher::reg(font_obj_reg.reg()), false,
{DerefTokenMatcher::string("origin"), DerefTokenMatcher::string("x")}),
Matcher::numeric_cast("float", Matcher::reg(in->entries().at(1).dest.reg())));
auto x_mr = match(x_matcher, in->body()->at(0));
Matcher y_matcher = Matcher::set(
Matcher::deref(Matcher::reg(font_obj_reg.reg()), false,
{DerefTokenMatcher::string("origin"), DerefTokenMatcher::string("y")}),
Matcher::numeric_cast("float", Matcher::reg(in->entries().at(2).dest.reg())));
auto y_mr = match(y_matcher, in->body()->at(1));
if (!x_mr.matched) {
return nullptr;
}
if (!y_mr.matched) {
return nullptr;
}
auto elt = pool.alloc_element<GenericElement>(
GenericOperator::make_function(pool.form<ConstantTokenElement>("set-origin!")),
std::vector<Form*>{font_obj_expr, x_val, y_val});
elt->parent_form = in->parent_form;
return elt;
}
FormElement* rewrite_launch_particles(LetElement* in, const Env& env, FormPool& pool) {
/*
* (let ((t9-0 sp-launch-particles-var)
@@ -2611,8 +2831,12 @@ FormElement* rewrite_launch_particles(LetElement* in, const Env& env, FormPool&
}
auto set_elt = dynamic_cast<SetFormFormElement*>(in->body()->at(0));
GenericElement* vector_copy_elt = nullptr;
if (!set_elt) {
return nullptr;
vector_copy_elt = dynamic_cast<GenericElement*>(in->body()->at(0));
if (!vector_copy_elt || vector_copy_elt->op().to_form(env).print() != "vector-copy!") {
return nullptr;
}
}
auto func_elt = dynamic_cast<GenericElement*>(in->body()->at(1));
@@ -2642,19 +2866,24 @@ FormElement* rewrite_launch_particles(LetElement* in, const Env& env, FormPool&
return nullptr;
}
auto origin = dynamic_cast<DerefElement*>(set_elt->src()->elts().at(0));
if (!origin) {
return nullptr;
}
auto tokens = origin->tokens().size();
Form* origin_form;
// remove only the quad if there are multiple derefs
if (tokens > 1) {
origin_form = pool.form<DerefElement>(origin->base(), false, origin->tokens());
auto orig = dynamic_cast<DerefElement*>(origin_form->elts().at(0));
orig->tokens().pop_back();
Form* origin_form = nullptr;
if (set_elt) {
auto origin = dynamic_cast<DerefElement*>(set_elt->src()->elts().at(0));
auto tokens = origin->tokens().size();
// remove only the quad if there are multiple derefs
if (tokens > 1) {
origin_form = pool.form<DerefElement>(origin->base(), false, origin->tokens());
auto orig = dynamic_cast<DerefElement*>(origin_form->elts().at(0));
orig->tokens().pop_back();
} else {
origin_form = origin->base();
}
} else {
origin_form = origin->base();
// the vector copy rewrite already did the logic above.
origin_form = vector_copy_elt->elts().at(1);
}
if (!origin_form) {
return nullptr;
}
auto launch_state = func_elt->elts().at(func_elt->elts().size() - 3);
@@ -2732,6 +2961,12 @@ FormElement* rewrite_multi_let(LetElement* in,
}
}
auto as_font_set_origin = rewrite_set_font_origin(in, env, pool);
if (as_font_set_origin) {
stats.font_method++;
return as_font_set_origin;
}
return in;
}
+86 -19
View File
@@ -287,25 +287,41 @@
)
(defenum pad-buttons
:bitfield #t
:type uint32
(select 0)
(l3 1)
(r3 2)
(start 3)
(up 4)
(right 5)
(down 6)
(left 7)
(l2 8)
(r2 9)
(l1 10)
(r1 11)
(triangle 12)
(circle 13)
(x 14)
(square 15)
)
:bitfield #t
:type uint32
(select 0)
(l3 1)
(r3 2)
(start 3)
(up 4)
(right 5)
(down 6)
(left 7)
(l2 8)
(r2 9)
(l1 10)
(r1 11)
(triangle 12)
(circle 13)
(x 14)
(square 15)
)
(defenum abutton-idx
:type uint8
(right 0)
(left 1)
(up 2)
(down 3)
(triangle 4)
(circle 5)
(x 6)
(square 7)
(l1 8)
(r1 9)
(l2 10)
(r2 11)
)
(defenum gs-psm
:bitfield #f
@@ -19612,6 +19628,57 @@
(wt31)
)
(defenum water-look
(water-anim-sunken-big-room 0)
(water-anim-sunken-first-room-from-entrance 1)
(water-anim-sunken-qbert-room 2)
(water-anim-sunken-first-right-branch 3)
(water-anim-sunken-circular-with-bullys 4)
(water-anim-sunken-hall-with-one-whirlpool 5)
(water-anim-sunken-hall-with-three-whirlpools 6)
(water-anim-sunken-start-of-helix-slide 7)
(water-anim-sunken-room-above-exit-chamber 8)
(water-anim-sunken-hall-before-big-room 9)
(water-anim-sunken-dark-eco-qbert 10)
(water-anim-sunken-short-piece 11)
(water-anim-sunken-big-room-upper-water 12)
(water-anim-sunken-dark-eco-platform-room 13)
(water-anim-maincave-water-with-crystal 14)
(water-anim-maincave-center-pool 15)
(water-anim-maincave-lower-right-pool 16)
(water-anim-maincave-mid-right-pool 17)
(water-anim-maincave-lower-left-pool 18)
(water-anim-maincave-mid-left-pool 19)
(water-anim-robocave-main-pool 20)
(water-anim-misty-mud-by-arena 21)
(water-anim-misty-mud-above-skeleton 22)
(water-anim-misty-mud-behind-skeleton 23)
(water-anim-misty-mud-above-skull-back 24)
(water-anim-misty-mud-above-skull-front 25)
(water-anim-misty-mud-other-near-skull 26)
(water-anim-misty-mud-near-skull 27)
(water-anim-misty-mud-under-spine 28)
(water-anim-misty-mud-by-dock 29)
(water-anim-misty-mud-island-near-dock 30)
(water-anim-misty-mud-lonely-island 31)
(water-anim-misty-dark-eco-pool 32)
(water-anim-ogre-lava 33)
(water-anim-jungle-river 34)
(water-anim-village3-lava 35)
(water-anim-training-lake 36)
(water-anim-darkcave-water-with-crystal 37)
(water-anim-rolling-water-back 38)
(water-anim-rolling-water-front 39)
(water-anim-sunken-dark-eco-helix-room 40)
(water-anim-finalboss-dark-eco-pool 41)
(water-anim-lavatube-energy-lava 42)
(water-anim-village1-rice-paddy 43)
(water-anim-village1-fountain 44)
(water-anim-village1-rice-paddy-mid 45)
(water-anim-village1-rice-paddy-top 46)
(water-anim-village2-bucket 47)
)
(deftype water-control (basic)
((flags water-flags :offset-assert 4)
(process process-drawable :offset-assert 8)
@@ -1 +1 @@
[]
[[2147418112,{"idx":0,"name":"placeholder-white","tpage_name":"placeholder"}],[105447426,{"idx":2,"name":"demo5cj","tpage_name":"demo5j"}],[105447425,{"idx":1,"name":"demo5bj","tpage_name":"demo5j"}],[105447424,{"idx":0,"name":"demo5aj","tpage_name":"demo5j"}],[105316354,{"idx":2,"name":"demo4cs","tpage_name":"demo4s"}],[105316353,{"idx":1,"name":"demo4bs","tpage_name":"demo4s"}],[105316352,{"idx":0,"name":"demo4as","tpage_name":"demo4s"}],[105250818,{"idx":2,"name":"demo4ci","tpage_name":"demo4i"}],[105250817,{"idx":1,"name":"demo4bi","tpage_name":"demo4i"}],[105250816,{"idx":0,"name":"demo4ai","tpage_name":"demo4i"}],[105119746,{"idx":2,"name":"demo4cf","tpage_name":"demo4f"}],[105119745,{"idx":1,"name":"demo4bf","tpage_name":"demo4f"}],[105119744,{"idx":0,"name":"demo4af","tpage_name":"demo4f"}],[104988674,{"idx":2,"name":"demo2cs","tpage_name":"demo2s"}],[104988673,{"idx":1,"name":"demo2bs","tpage_name":"demo2s"}],[104988672,{"idx":0,"name":"demo2as","tpage_name":"demo2s"}],[104923138,{"idx":2,"name":"demo2ci","tpage_name":"demo2i"}],[104923137,{"idx":1,"name":"demo2bi","tpage_name":"demo2i"}],[104923136,{"idx":0,"name":"demo2ai","tpage_name":"demo2i"}],[100401161,{"idx":9,"name":"sk-eye-lid","tpage_name":"sidekick-lod0"}],[100401160,{"idx":8,"name":"e-white-alpha","tpage_name":"sidekick-lod0"}],[100401159,{"idx":7,"name":"sk-armfur","tpage_name":"sidekick-lod0"}],[98238464,{"idx":0,"name":"logo-flare","tpage_name":"title-vis-water"}],[97386498,{"idx":2,"name":"demo3c","tpage_name":"demo3"}],[97386497,{"idx":1,"name":"demo3b","tpage_name":"demo3"}],[97320962,{"idx":2,"name":"demo2c","tpage_name":"demo2"}],[97320961,{"idx":1,"name":"demo2b","tpage_name":"demo2"}],[97320960,{"idx":0,"name":"demo2a","tpage_name":"demo2"}],[96927748,{"idx":4,"name":"vil1-sky-03","tpage_name":"demo-vis-alpha"}],[96927747,{"idx":3,"name":"vil1-sky-02","tpage_name":"demo-vis-alpha"}],[96927746,{"idx":2,"name":"vil1-sky-01","tpage_name":"demo-vis-alpha"}],[96927745,{"idx":1,"name":"vil1-sky-00","tpage_name":"demo-vis-alpha"}],[96927744,{"idx":0,"name":"vil1-clouds","tpage_name":"demo-vis-alpha"}],[96731136,{"idx":0,"name":"cv-water","tpage_name":"village2-vis-water"}],[95485988,{"idx":36,"name":"vest-01","tpage_name":"intro-vis-pris"}],[95485987,{"idx":35,"name":"hair-01","tpage_name":"intro-vis-pris"}],[95485986,{"idx":34,"name":"farmer-teeth","tpage_name":"intro-vis-pris"}],[95485985,{"idx":33,"name":"esskin","tpage_name":"intro-vis-pris"}],[95485984,{"idx":32,"name":"espants-02","tpage_name":"intro-vis-pris"}],[95485983,{"idx":31,"name":"espants-01","tpage_name":"intro-vis-pris"}],[95485981,{"idx":29,"name":"eseyebrow","tpage_name":"intro-vis-pris"}],[95485980,{"idx":28,"name":"eseye","tpage_name":"intro-vis-pris"}],[95485979,{"idx":27,"name":"evilbro-eyelid","tpage_name":"intro-vis-pris"}],[95485978,{"idx":26,"name":"esbelly-01","tpage_name":"intro-vis-pris"}],[95485977,{"idx":25,"name":"es-precursor-metal-01","tpage_name":"intro-vis-pris"}],[95485976,{"idx":24,"name":"es-green-metal","tpage_name":"intro-vis-pris"}],[95485975,{"idx":23,"name":"ogre-envmap","tpage_name":"intro-vis-pris"}],[95485974,{"idx":22,"name":"evilbro-wrap","tpage_name":"intro-vis-pris"}],[95485973,{"idx":21,"name":"evilbro-teeth","tpage_name":"intro-vis-pris"}],[95485972,{"idx":20,"name":"evilbro-strap","tpage_name":"intro-vis-pris"}],[95485971,{"idx":19,"name":"evilbro-rings","tpage_name":"intro-vis-pris"}],[95485970,{"idx":18,"name":"evilbro-redcape","tpage_name":"intro-vis-pris"}],[95485969,{"idx":17,"name":"evilbro-pipes","tpage_name":"intro-vis-pris"}],[95485968,{"idx":16,"name":"evilbro-pants","tpage_name":"intro-vis-pris"}],[95485967,{"idx":15,"name":"evilbro-mechglove-02","tpage_name":"intro-vis-pris"}],[95485966,{"idx":14,"name":"evilbro-mechglove-01","tpage_name":"intro-vis-pris"}],[95485965,{"idx":13,"name":"evilbro-mecharm-03","tpage_name":"intro-vis-pris"}],[95485964,{"idx":12,"name":"evilbro-mecharm-02","tpage_name":"intro-vis-pris"}],[95485962,{"idx":10,"name":"evilbro-hair-01","tpage_name":"intro-vis-pris"}],[95485961,{"idx":9,"name":"evilbro-flesh","tpage_name":"intro-vis-pris"}],[95485959,{"idx":7,"name":"evilbro-envmap","tpage_name":"intro-vis-pris"}],[95485958,{"idx":6,"name":"evilbro-chin","tpage_name":"intro-vis-pris"}],[95485957,{"idx":5,"name":"evilbro-brownleather","tpage_name":"intro-vis-pris"}],[95485956,{"idx":4,"name":"evilbro-blueleather-02","tpage_name":"intro-vis-pris"}],[95485955,{"idx":3,"name":"evilbro-blueleather-01","tpage_name":"intro-vis-pris"}],[95485954,{"idx":2,"name":"evilbro-belt","tpage_name":"intro-vis-pris"}],[95485953,{"idx":1,"name":"evilbro-beard","tpage_name":"intro-vis-pris"}],[95485952,{"idx":0,"name":"evilbro-balls","tpage_name":"intro-vis-pris"}],[95354886,{"idx":6,"name":"mis-rockwall-trim","tpage_name":"intro-vis-tfrag"}],[95354885,{"idx":5,"name":"mis-ground","tpage_name":"intro-vis-tfrag"}],[95354884,{"idx":4,"name":"mis-tree","tpage_name":"intro-vis-tfrag"}],[95354883,{"idx":3,"name":"mis-boLine truncated
+40 -20
View File
@@ -52,14 +52,28 @@
(defenum language-enum
:type int64
(english)
(french)
(german)
(spanish)
(italian)
(japanese)
(korean)
(uk-english)
(english 0)
(french 1)
(german 2)
(spanish 3)
(italian 4)
(japanese 5)
(korean 6)
(uk-english 7)
;; custom
(portuguese 8)
(finnish 9)
(swedish 10)
(danish 11)
(norwegian 12)
(dutch 13)
(br-portuguese 14)
(hungarian 15)
(catalan 16)
(icelandic 17)
(russian 18)
(polish 19)
(lithuanian 20)
)
(defenum runtime-exit-status
@@ -4188,6 +4202,22 @@ and the state of the VU memory buffers at the end of the bucket."
(confirm 24)
)
(defenum abutton-idx
:type uint8
(right 0)
(left 1)
(up 2)
(down 3)
(triangle 4)
(circle 5)
(x 6)
(square 7)
(l1 8)
(r1 9)
(l2 10)
(r2 11)
)
(defenum mouse-buttons
:bitfield #t
:type uint32
@@ -8787,6 +8817,8 @@ Unlike [[engine]], users can use [[engine-pers]] as a parent class."
(progress-graphics-ps2-lod-dist #x1337)
(progress-graphics-msaa-off #x1338)
(progress-graphics-display #x1339)
(language-name-finnish #x133a)
(progress-hint-subtitles #x133b)
)
;; ---text-id-h:text-id
@@ -9433,18 +9465,6 @@ Unlike [[engine]], users can use [[engine-pers]] as a parent class."
;; settings-h ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defenum language-enum
:type int64
(english)
(french)
(german)
(spanish)
(italian)
(japanese)
(korean)
(uk-english)
)
(defenum game-feature
:type uint64
:bitfield #t
+1 -1
View File
@@ -127,7 +127,7 @@
"rip_collision": false,
// save game textures as .png files to decompiler_out/<game>/textures
"save_texture_pngs": false,
// whether or not to dump out streamed audio files to decompiler_out/<game>/audio
"rip_streamed_audio": false,
@@ -1 +1 @@
[]
[[232521729,{"idx":1,"name":"dig-shrub-pebbles","tpage_name":"dig3b-vis-shrub"}],[232521728,{"idx":0,"name":"dig-rock-shrubs","tpage_name":"dig3b-vis-shrub"}],[230227972,{"idx":4,"name":"firework-mini-glow-orange","tpage_name":"outrocst-sprite"}],[230227971,{"idx":3,"name":"firework-dust-grey","tpage_name":"outrocst-sprite"}],[230227970,{"idx":2,"name":"firework-mini-glow-grey","tpage_name":"outrocst-sprite"}],[230227969,{"idx":1,"name":"firework-mini-glow","tpage_name":"outrocst-sprite"}],[230227968,{"idx":0,"name":"firework-dust","tpage_name":"outrocst-sprite"}],[229244928,{"idx":0,"name":"cpad-grass-fringe","tpage_name":"caspad-vis-alpha"}],[227999746,{"idx":2,"name":"sew-mar-ruby-env","tpage_name":"sewer-warp"}],[226623489,{"idx":1,"name":"explosion","tpage_name":"casboss-sprite"}],[226623488,{"idx":0,"name":"cboss-green-lightning-01","tpage_name":"casboss-sprite"}],[226164805,{"idx":69,"name":"stdmc-yellow-light-02","tpage_name":"stadiumb-vis-tfrag"}],[226164804,{"idx":68,"name":"stdmc-yellow-light-01","tpage_name":"stadiumb-vis-tfrag"}],[226164803,{"idx":67,"name":"stdmb-redlight-02","tpage_name":"stadiumb-vis-tfrag"}],[226164801,{"idx":65,"name":"race-hatch-side-01","tpage_name":"stadiumb-vis-tfrag"}],[226164800,{"idx":64,"name":"stdmb-pipe-04a","tpage_name":"stadiumb-vis-tfrag"}],[226164799,{"idx":63,"name":"stdmb-blastdoors-ramp","tpage_name":"stadiumb-vis-tfrag"}],[226164798,{"idx":62,"name":"stdmb-green-grill-light-02","tpage_name":"stadiumb-vis-tfrag"}],[226164797,{"idx":61,"name":"stdmb-floor-01","tpage_name":"stadiumb-vis-tfrag"}],[226164796,{"idx":60,"name":"stdmb-startline","tpage_name":"stadiumb-vis-tfrag"}],[226164795,{"idx":59,"name":"stdmb-green-grill-light-01-hitweak","tpage_name":"stadiumb-vis-tfrag"}],[226164794,{"idx":58,"name":"stdmb-pillar-01-hitweak","tpage_name":"stadiumb-vis-tfrag"}],[226164793,{"idx":57,"name":"stdmb-trim-02","tpage_name":"stadiumb-vis-tfrag"}],[226164792,{"idx":56,"name":"stdmb-arena-floor","tpage_name":"stadiumb-vis-tfrag"}],[226164791,{"idx":55,"name":"stdmb-forcefield-light-02","tpage_name":"stadiumb-vis-tfrag"}],[226164790,{"idx":54,"name":"stdmb-panel-10","tpage_name":"stadiumb-vis-tfrag"}],[226164789,{"idx":53,"name":"stdmb-honeycomb-glow-01","tpage_name":"stadiumb-vis-tfrag"}],[226164788,{"idx":52,"name":"stdmb-road-side-02","tpage_name":"stadiumb-vis-tfrag"}],[226164787,{"idx":51,"name":"stdmb-redstripe","tpage_name":"stadiumb-vis-tfrag"}],[226164786,{"idx":50,"name":"stdmb-shaft-rim-01","tpage_name":"stadiumb-vis-tfrag"}],[226164785,{"idx":49,"name":"stdmb-wall-01","tpage_name":"stadiumb-vis-tfrag"}],[226164784,{"idx":48,"name":"stdmb-track-01","tpage_name":"stadiumb-vis-tfrag"}],[226164783,{"idx":47,"name":"stdmb-track-02","tpage_name":"stadiumb-vis-tfrag"}],[226164782,{"idx":46,"name":"stdmb-roof-01","tpage_name":"stadiumb-vis-tfrag"}],[226164781,{"idx":45,"name":"stdmb-slope-metal","tpage_name":"stadiumb-vis-tfrag"}],[226164780,{"idx":44,"name":"stdmb-tech-walls","tpage_name":"stadiumb-vis-tfrag"}],[226164779,{"idx":43,"name":"stdmb-sign-glow-blue","tpage_name":"stadiumb-vis-tfrag"}],[226164778,{"idx":42,"name":"stdmb-rail-02","tpage_name":"stadiumb-vis-tfrag"}],[226164777,{"idx":41,"name":"stdmb-pipe-04","tpage_name":"stadiumb-vis-tfrag"}],[226164776,{"idx":40,"name":"stdmb-pipe-ring-02","tpage_name":"stadiumb-vis-tfrag"}],[226164775,{"idx":39,"name":"stdmb-pipe-ring-03","tpage_name":"stadiumb-vis-tfrag"}],[226164774,{"idx":38,"name":"stdmb-floor-plate-01","tpage_name":"stadiumb-vis-tfrag"}],[226164773,{"idx":37,"name":"stdmb-arrow-gradient","tpage_name":"stadiumb-vis-tfrag"}],[226164772,{"idx":36,"name":"stdmb-pipe-01","tpage_name":"stadiumb-vis-tfrag"}],[226164771,{"idx":35,"name":"stdmb-track-side-01","tpage_name":"stadiumb-vis-tfrag"}],[226164770,{"idx":34,"name":"stdmb-panel-05","tpage_name":"stadiumb-vis-tfrag"}],[226164769,{"idx":33,"name":"stdmb-panel-11","tpage_name":"stadiumb-vis-tfrag"}],[226164768,{"idx":32,"name":"stdmb-panel-09","tpage_name":"stadiumb-vis-tfrag"}],[226164767,{"idx":31,"name":"stdmb-wall-03","tpage_name":"stadiumb-vis-tfrag"}],[226164766,{"idx":30,"name":"stdmb-stone-trim-01","tpage_name":"stadiumb-vis-tfrag"}],[226164765,{"idx":29,"name":"stdmb-panel-08","tpage_name":"stadiumb-vis-tfrag"}],[226164764,{"idx":28,"name":"stdmb-yellowstripe","tpage_name":"stadiumb-vis-tfrag"}],[226164763,{"idx":27,"name":"stdmb-wall-detail-04","tpage_name":"stadiumb-vis-tfrag"}],[226164762,{"idx":26,"name":"stdmb-pipe-02","tpage_name":"stadiumb-vis-tfrag"}],[226164761,{"idx":25,"name":"stdmb-wall-detail-02","tpage_name":"stadiumb-vis-tfrag"}],[226164760,{"idx":24,"name":"stdmb-pipe-ring-01","tpage_name":"stadiumb-vis-tfrag"}],[226164759,{"idx":23,"name":"stdmb-wall-detail-05","tpage_name":"stadiumb-vis-tfrag"}],[226164758,{"idx":22,"name":"stdmb-panel-06","tpage_name":"stadiumb-vis-tfrag"}],[226164757,{"idx":21,"name":"stdmb-pillar-blue-light-01","tpage_name":"stadiumb-vis-tfrag"}],[226164756,{"idx":20,"name":"stdmb-pillar-01","tpage_naLine truncated
+336 -259
View File
@@ -219,31 +219,6 @@
:flag-assert #xe00000010
)
#|
(deftype array (UNKNOWN)
((allocated-length int32 :offset-assert 4)
(length int32 :offset-assert 0)
(content-type type :offset-assert 8) ;; guessed by decompiler
(data uint8 :dynamic :offset-assert 12) ;; guessed by decompiler
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
(UNKNOWN UNKNOWN :offset-assert -1) ;; field could not be read.
)
:method-count-assert 0
:size-assert #x0
:flag-assert #x0
)
|#
(define-extern identity
"The identity function."
(function object object))
@@ -557,9 +532,9 @@
(new "Allocate a process-tree with the kernel clock." (symbol type string) _type_) ;; 0
(activate "Move a process from dead to active, moving it to the given tree." (_type_ process-tree string pointer) process-tree) ;; 9
(deactivate "Make a process dead, clean it up, remove it from the active pool, and return to dead pool." (_type_) none) ;; 10
(init-from-entity! (_type_ entity-actor) object) ;; 11
(init-from-entity! "Set up a newly created process from the entity that created it." (_type_ entity-actor) object) ;; 11
(run-logic? "Should this process be run? Checked by execute-process-tree." (_type_) symbol) ;; 12
(process-tree-method-13 () none) ;; 13
(entity-info-slot "Not a method. This vtable slot stores entity-info for this type." () none) ;; 13
)
)
@@ -1971,6 +1946,8 @@
)
(deftype lissajous (structure)
"A curve where the x and y position are set by two different sinusoids.
This stores the parameters and state for evaluating this curve."
((x-mag float :offset-assert 0)
(y-mag float :offset-assert 4)
(theta float :offset-assert 8)
@@ -1984,11 +1961,14 @@
:size-assert #x1c
:flag-assert #xa0000001c
(:methods
(lissajous-method-9 (_type_ vector) vector) ;; 9
(evaluate! "Set the x and y component of the vector to the current point on the curve."
(_type_ vector) vector) ;; 9
)
)
(deftype lissajous-interp (structure)
"Handles interpolating between two different lissajous parameters, and also
stepping forward the dynamics."
((current lissajous :inline :offset-assert 0)
(dest lissajous :inline :offset-assert 28)
(rate lissajous :inline :offset-assert 56)
@@ -1997,8 +1977,10 @@
:size-assert #x54
:flag-assert #xb00000054
(:methods
(lissajous-interp-method-9 (_type_ vector) vector) ;; 9
(lissajous-interp-method-10 (_type_) float) ;; 10
(evaluate! "Set the x and y component of the vector to the current point on the curve."
(_type_ vector) vector) ;; 9
(update! "Update both the interpolation, and the curves themselves."
(_type_) float) ;; 10
)
)
@@ -2012,6 +1994,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(deftype transformq (transform)
"A transform, but the rotation is represented with a quaternion."
((quat quaternion :inline :offset 16 :score 1)
)
:method-count-assert 9
@@ -2020,6 +2003,7 @@
)
(deftype trsq (trs)
"A trs, but the rotation is represented with a quaternion."
((quat quaternion :inline :offset 32 :score 1)
)
:method-count-assert 9
@@ -2296,8 +2280,6 @@
;; quaternion ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; quaternion is already defined!
(define-extern quaternion-axis-angle!
"Construct a quaternion from an axis and angle. The axis should be normalized."
(function quaternion float float float float quaternion))
@@ -4603,6 +4585,24 @@
)
;; ---pad:pad-buttons
;; +++pad:abutton-idx
(defenum abutton-idx
:type uint8
(right 0)
(left 1)
(up 2)
(down 3)
(triangle 4)
(circle 5)
(x 6)
(square 7)
(l1 8)
(r1 9)
(l2 10)
(r2 11)
)
;; ---pad:abutton-idx
;; +++pad:mouse-buttons
(defenum mouse-buttons
:bitfield #t
@@ -5843,7 +5843,7 @@
(define-extern matrix-remove-z-rot "Remove the z rotation component of a rotation." (function matrix vector matrix))
(define-extern matrix-rot-diff!
"Get the difference of rotation between two matrices, expressed as a quaternion."
(function vector matrix matrix float))
(function quaternion matrix matrix float))
(define-extern quaternion-seek
"Strange quaternion rotate toward function. arg3 is ignored. arg4 is the max seek amount."
(function quaternion quaternion quaternion float float quaternion))
@@ -7523,27 +7523,27 @@
;; +++level-h:bigmap-id
(defenum bigmap-id
:type uint32
(bigmap-id-0 0)
(bigmap-id-1 1)
(city 0)
(comb 1)
(desert 2)
(factory 3)
(forest 4)
(mhcity 5)
(mine 6)
(nest 7)
(bigmap-id-8 8)
(no-map 9)
(precursor 10)
(bigmap-id-11 11)
(nest2 8)
(none 9)
(precursor1 10)
(precursor2 11)
(rubble 12)
(sewer0 13)
(sewer1 14)
(sewer2 15)
(sewer-hum-kg 13)
(sewer-kg-met 14)
(sewer-met-hum 15)
(stadium 16)
(temple 17)
(bigmap-id-18 18)
(bigmap-id-19 19)
(bigmap-id-20 20)
(temple1 17)
(temple2 18)
(temple3 19)
(temple4 20)
(tower 21)
(volcano 22)
(wascity 23)
@@ -7885,7 +7885,7 @@
(update-vis-volumes (_type_) none) ;; 23 ;; (art-group-get-by-name (_type_ string (pointer uint32)) art-group)
(level-group-method-24 (_type_) none) ;; 24 ;; (alt-load-command-get-index (_type_ symbol int) pair)
(print-volume-sizes (_type_) none) ;; 25
(status-of-level-and-borrows "Get the combined status of a level and borrow levels." (_type_ symbol symbol) symbol) ;; 26 ;; (update-vis-volumes-from-nav-mesh (_type_) none)
(level-status? "Get the combined status of a level and borrow levels." (_type_ symbol symbol) symbol) ;; 26 ;; (update-vis-volumes-from-nav-mesh (_type_) none)
(do-nothing "Empty method." (_type_) none) ;; 27
(load-in-progress? "Is there a load happening now?" (_type_) symbol) ;; 28 ;; (level-status (_type_ symbol) symbol)
(is-load-allowed? "Does the exclusive-load setting allow us to load this level?" (_type_ (pointer symbol)) symbol) ;; 29
@@ -8288,7 +8288,7 @@
(define-extern *font-default-matrix* matrix)
(define-extern *font-work* font-work)
(define-extern font-set-tex0 (function (pointer gs-tex0) texture int int int none))
(define-extern set-font-color (function font-color int rgba rgba rgba int))
(define-extern set-font-color (function font-color rgba rgba rgba rgba int))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; decomp-h ;;
@@ -10724,16 +10724,55 @@
:flag-assert #x900000180
)
;; +++bigmap-h:bigmap-flag
(defenum bigmap-flag
:type uint32
:bitfield #t
(bf00 0)
(bf01 1)
(bf02 2)
(bf03 3)
(bf04 4)
(bf05 5)
(bf06 6)
(bf07 7)
(bf08 8)
(bf09 9)
(bf10 10)
(bf11 11)
(bf12 12)
(bf13 13)
(bf14 14)
(bf15 15)
(bf16 16)
(bf17 17)
(ctywide 18)
(waswide 19)
(wasall 20)
(desert 21)
(bf22 22)
(bf23 23)
(bf24 24)
(bf25 25)
(bf26 26)
(bf27 27)
(bf28 28)
(bf29 29)
(bf30 30)
(bf31 31)
)
;; ---bigmap-h:bigmap-flag
(deftype bigmap (basic)
((drawing-flag symbol :offset-assert 4) ;; guessed by decompiler
(loading-flag symbol :offset-assert 8) ;; guessed by decompiler
(bigmap-index uint32 :offset-assert 12)
(bigmap-index bigmap-id :offset-assert 12)
(bigmap-image external-art-buffer :offset-assert 16) ;; guessed by decompiler
(tpage external-art-buffer :offset-assert 20) ;; guessed by decompiler
(tpage2 basic :offset-assert 24)
(tpage2 external-art-buffer :offset-assert 24)
(progress-minimap texture-page :offset-assert 28) ;; guessed by decompiler
(progress-minimap2 texture-page :offset-assert 32)
(load-index uint32 :offset-assert 36)
(load-index bigmap-id :offset-assert 36)
(x0 int32 :offset-assert 40)
(y0 int32 :offset-assert 44)
(x1 int32 :offset-assert 48)
@@ -10748,29 +10787,29 @@
(scroll vector :inline :offset-assert 176)
(pos vector4w :inline :offset-assert 192)
(color vector4w :inline :offset-assert 208)
(corner vector 4 :inline :offset-assert 224) ;; guessed by decompiler
(corner vector 4 :inline :offset-assert 224) ;; guessed by decompiler
(auto-save-icon-flag symbol :offset-assert 288) ;; guessed by decompiler
(global-flags uint32 :offset-assert 292)
(global-flags bigmap-flag :offset-assert 292)
)
:method-count-assert 23
:size-assert #x128
:flag-assert #x1700000128
(:methods
(new (symbol type) _type_) ;; 0 ;; (new (symbol type) _type_)
(bigmap-method-9 () none) ;; 9 ;; (initialize (_type_) none)
(new (symbol type) _type_) ;; 0
(initialize (_type_) none) ;; 9
(update (_type_) none) ;; 10
(bigmap-method-11 (_type_) symbol) ;; 11
(bigmap-method-12 () none) ;; 12 ;; (handle-cpad-inputs (_type_) int)
(bigmap-method-13 () none) ;; 13 ;; (compress-all (_type_) int)
(loaded? (_type_) symbol) ;; 11
(draw! (_type_ int int int int) none) ;; 12 ;; (handle-cpad-inputs (_type_) int)
(handle-cpad-input (_type_) none) ;; 13 ;; (compress-all (_type_) int)
(enable-drawing (_type_) none) ;; 14
(disable-drawing (_type_) int) ;; 15
(bigmap-method-16 (_type_) none) ;; 16 ;; (dump-to-file (_type_) file-stream)
(bigmap-method-17 () none) ;; 17 ;; (set-pos! (_type_ vector) int)
(bigmap-method-18 () none) ;; 18 ;; (decompress-current-masks! (_type_) int)
(bigmap-method-19 () none) ;; 19 ;; (compress-current-masks! (_type_) int)
(bigmap-method-20 () none) ;; 20 ;; (set-enable-from-position! (_type_) int)
(bigmap-method-21 () none) ;; 21 ;; (maybe-fill-for-position (_type_ int int) int)
(bigmap-method-22 () none) ;; 22 ;; (texture-upload-dma (_type_ dma-buffer (pointer uint32) int int int gs-psm) none)
(set-map-indices! (_type_) none) ;; 16 ;; (dump-to-file (_type_) file-stream)
(set-pos! (_type_ vector) none) ;; 17
(bigmap-method-18 (_type_ (pointer int32)) none) ;; 18 ;; (decompress-current-masks! (_type_) int)
(texture-upload-dma (_type_ dma-buffer (pointer uint32) int int int gs-psm) none) ;; 19 ;; (compress-current-masks! (_type_) int)
(bigmap-method-20 (_type_ dma-buffer) symbol) ;; 20 ;; (set-enable-from-position! (_type_) int)
(sprite-dma (_type_ dma-buffer int int int int int int) object) ;; 21 ;; (maybe-fill-for-position (_type_ int int) int)
(draw-from-minimap (_type_ dma-buffer connection-minimap) none) ;; 22
)
)
@@ -11485,13 +11524,13 @@
(scan-tmpl dma-gif-packet :inline :offset-assert 192)
(color vector4w :inline :offset-assert 224)
(line-color uint64 :offset-assert 240)
(scan-colors vector4w 15 :inline :offset-assert 256) ;; guessed by decompiler
(scan-colors vector4w 15 :inline :offset-assert 256) ;; guessed by decompiler
(zoom-blur-pos vector :inline :offset-assert 496)
(zoom-blur-count int32 :offset-assert 512)
(zoom-blur-texels int32 :offset-assert 516)
(zoom-blur-alpha-target float :offset-assert 520)
(zoom-blur-alpha-current float :offset-assert 524)
(zoom-blur-2d basic :offset-assert 528)
(zoom-blur-2d symbol :offset-assert 528)
(menu-mode symbol :offset-assert 532) ;; guessed by decompiler
(screen-copied symbol :offset-assert 536) ;; guessed by decompiler
(vu1-enable-user-menu vu1-renderer-mask :offset-assert 544)
@@ -11509,18 +11548,18 @@
:size-assert #x24c
:flag-assert #x1b0000024c
(:methods
(blit-displays-work-method-9 () none) ;; 9
(blit-displays-work-method-10 () none) ;; 10
(blit-displays-work-method-11 () none) ;; 11
(blit-displays-work-method-12 () none) ;; 12
(blit-displays-work-method-13 () none) ;; 13
(blit-displays-work-method-14 () none) ;; 14
(blit-displays-work-method-15 () none) ;; 15
(blit-displays-work-method-16 () none) ;; 16
(blit-displays-work-method-17 (_type_ vector int float symbol) none) ;; 17
(blit-displays-work-method-18 () none) ;; 18
(blit-displays-work-method-19 (_type_) none) ;; 19 (called from main.gc)
(blit-displays-work-method-20 (_type_) none) ;; 20
(blit-displays-work-method-9 (_type_ dma-buffer int int int) none) ;; 9
(blit-displays-work-method-10 (_type_ dma-buffer int int int) none) ;; 10
(blit-displays-work-method-11 (_type_ dma-buffer int) none) ;; 11
(draw-letterbox (_type_ dma-buffer float int float) none) ;; 12
(blit-displays-work-method-13 (_type_ dma-buffer int int int) none) ;; 13
(blit-displays-work-method-14 (_type_ dma-buffer vector) none) ;; 14
(blit-displays-work-method-15 (_type_ dma-buffer) none) ;; 15
(draw-zoom-blur (_type_ dma-buffer int) none) ;; 16
(setup-zoom-blur-2d (_type_ vector int float symbol) none) ;; 17
(setup-brightness-and-contrast (_type_ dma-buffer float float) none) ;; 18
(do-blit-displays (_type_) none) ;; 19 (called from main.gc)
(draw-sky (_type_ dma-buffer) none) ;; 20
(get-menu-mode (_type_) symbol) ;; 21
(get-screen-copied (_type_) symbol) ;; 22
(get-horizontal-flip-flag (_type_) symbol) ;; 23
@@ -17273,7 +17312,7 @@
(task-node-commands (array game-task-node-command) :offset-assert 416)
(task-node-exclusive (array uint16) :offset-assert 420)
(task-counter uint32 :offset-assert 424)
(unknown-arr4 (array uint16) :offset-assert 428)
(talker-state (array uint16) :offset-assert 428)
(level-opened uint8 32 :offset-assert 432)
(total-deaths int32 :offset-assert 464)
(continue-deaths int32 :offset-assert 468)
@@ -17510,20 +17549,25 @@
(defenum talker-flags
:type uint16
:bitfield #t
(tf0 0)
(tf1 1)
(tf2 2)
(tf3 3)
(tf4 4)
(tf5 5)
(tf6 6)
(tf7 7)
(tf8 8)
(play-only-once 0)
(reduce-volume 1)
(auto-save-on-each-start 2)
(auto-save-once-on-exit 3)
(only-play-in-region 4)
(fade-in 5)
(slide-in 6)
(bigger-font 7)
(long-timeout 8)
)
;; ---ambient-h:talker-flags
(deftype talker-speech-class (structure)
"Contains metadata about a voice line or hint text being played/displayed."
"Contains metadata about a voice line or hint text being played/displayed.
In the talker state, there's a pos-state and neg-state.
Calling yes-play! adjusts the pos-state and no-play! adjusts the neg-state.
Playback is only allowed if the pos-state is less than or equal to pos
and neg-state is greater than or equal to neg.
"
((name string :offset-assert 0)
(channel gui-channel :offset-assert 4)
(flags talker-flags :offset-assert 6)
@@ -17542,11 +17586,11 @@
:flag-assert #xe00000020
;; field on-close uses ~A with a signed load.
(:methods
(talker-speech-class-method-9 (_type_) symbol) ;; 9
(play-communicator-speech! (_type_) none) ;; 10
(talker-speech-class-method-11 (_type_) none) ;; 11
(talker-speech-class-method-12 (_type_ int) none) ;; 12
(talker-speech-class-method-13 (_type_ int) none) ;; 13
(should-play? "Return if the talker is in a state where it should play." (_type_) symbol) ;; 9
(mark-played! "Mark something as played by making its state UINT16_MAX" (_type_) none) ;; 10
(reset-state! "Reset the state of this talker to 0 (the initial value)" (_type_) none) ;; 11
(yes-play! (_type_ int) none) ;; 12
(no-play! (_type_ int) none) ;; 13
)
)
@@ -19409,11 +19453,6 @@
:bitfield #t
:type uint32
(disabled) ;; keep object velocity
(af01)
(af02)
(af03)
(af04)
(af05)
)
;; ---aligner-h:align-flags
@@ -19599,9 +19638,9 @@
(sf23 23)
(sf24 24)
(sf25 25)
(sf26 26)
(hang 26)
(sf27 27)
(sf28 28)
(invisible 28)
(sf29 29)
(sf30 30)
(sf31 31)
@@ -21960,8 +21999,8 @@
(unknown-float37 float :offset 5636)
(unknown-vector37 vector :inline :offset 5648)
(unknown-vector38 vector :inline :offset 5664)
(unknown-vector39 vector :inline :offset 5680)
(unknown-vector40 vector :inline :offset 5696)
(unknown-quat39 quaternion :inline :offset 5680)
(unknown-quat40 quaternion :inline :offset 5696)
(sliding-start-time time-frame :offset 5712)
(unknown-time-frame18 time-frame :offset 5720)
(unknown-sound-id00 sound-id :offset 5776)
@@ -22409,12 +22448,12 @@
:size-assert #xd0
:flag-assert #x1c005000d0
(:methods
(process-mask->search-info-flag (_type_) search-info-flag) ;; 20
(get-search-info-flag "Get search-info-flag for this process." (_type_) search-info-flag) ;; 20
(get-trans "Get the `trans` for this process." (_type_ int) vector) ;; 21
(get-quat "Get the quaternion for this process." (_type_ int) quaternion) ;; 22
(get-transv "Get the `transv` for this process." (_type_) vector) ;; 23
(time-to-apex-or-ground (_type_ int) int) ;; 24
(get-water-height (_type_) meters) ;; 25
(get-water-height "Get the height of the water that we're in." (_type_) meters) ;; 25
(get-notice-time (_type_) time-frame) ;; 26
(get-inv-mass (_type_) float) ;; 27
)
@@ -22494,7 +22533,7 @@
check that the [[collide-spec]] of the focus and the process match."
(_type_ process-focusable) object) ;; 10
(reset-to-collide-spec "Reset this focus with the given [[collide-spec]]." (_type_ collide-spec) none) ;; 11
(try-update-focus "Try to set the `handle` of this focus to the given process." (_type_ process-focusable) symbol) ;; 12
(focus-on! "Set the `handle` of this focus to the given process. Return if the handle changed." (_type_ process-focusable) symbol) ;; 12
)
)
@@ -23068,7 +23107,7 @@
(disable-for-duration (_type_ time-frame) none) ;; 16
(ragdoll-proc-method-17 (_type_ ragdoll-edit-info) none) ;; 17
(ragdoll-proc-method-18 (_type_ ragdoll-edit-info) none) ;; 18
(ragdoll-proc-method-19 (_type_) none) ;; 19
(ragdoll-proc-method-19 (_type_) symbol) ;; 19
)
)
@@ -25737,7 +25776,7 @@
(bit-4 4)
(bit-5 5)
(subtask-complete 6)
(bit-7 7)
(special 7)
(complete 8)
(bit-9 9)
(bit-10 10)
@@ -29075,7 +29114,7 @@
(clamp-vector-to-mesh-no-gaps (_type_ vector nav-poly vector clamp-travel-vector-to-mesh-return-info) none) ;; 21
(find-first-sphere-and-update-avoid-params (_type_ vector nav-avoid-spheres-params) float) ;; 22
(set-spheres-from-nav-ids (_type_) none) ;; 23
(add-root-sphere-to-hash! (_type_ vector int) symbol) ;; 24
(check-sphere-blocked! (_type_ vector int) symbol) ;; 24
(get-max-rotation-rate (_type_) float) ;; 25
(get-sphere-mask (_type_) uint) ;; 26
(get-target-speed (_type_) meters) ;; 27
@@ -29229,7 +29268,7 @@
(add-a-sphere-with-flag (_type_ vector int) int) ;; 27
(update-from-spheres (_type_) none) ;; 28
(sphere-hash-method-29 (_type_ find-nav-sphere-ids-params) none) ;; 29
(find-nav-sphere-ids (_type_ find-nav-sphere-ids-params int int) symbol) ;; 30
(check-sphere-blocked (_type_ vector int int) symbol) ;; 30
(add-sphere-with-mask-and-id (_type_ vector vector float int) symbol) ;; 31
(sphere-hash-method-32 (_type_ sphere int) symbol) ;; 32
)
@@ -31064,7 +31103,7 @@
(define-extern *blit-displays-work* blit-displays-work)
(define-extern draw-color-bars (function blit-displays-work none))
(define-extern draw-raw-image (function bucket-id art-group int vector vector level int none))
(define-extern draw-raw-image (function blit-displays-work bucket-id art-group vector vector level int none))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; font-data ;;
@@ -39229,7 +39268,7 @@
;; bigmap ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (define-extern *bigmap-info-array* object) ;; bigmap-info-array
(define-extern *bigmap-info-array* bigmap-info-array)
(define-extern *bigmap* bigmap)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -41282,11 +41321,11 @@
;; +++enemy-h:enemy-aware
(defenum enemy-aware
:type uint64
(ea0 0)
(ea1 1)
(ea2 2)
(ea3 3)
(ea4 4)
(unaware 0)
(aware1 1)
(aware2 2)
(hostile 3)
(flee 4)
)
;; ---enemy-h:enemy-aware
@@ -41331,6 +41370,7 @@
(death-start 34)
(auto-death-phase-out 35)
(has-gem 36)
;; these seem to be an extension of the flags for nav-enemy.
(ef37 37)
(ef38 38)
(ef39 39)
@@ -41351,8 +41391,10 @@
:size-assert #x20
:flag-assert #xe00000020
(:methods
(try-update-focus (_type_ process-focusable enemy) symbol :replace) ;; 12
(enemy-focus-method-13 (_type_ process-focusable enemy-aware) symbol) ;; 13
(focus-on! "Make this enemy focus on the process-focusable. If already focused, update awareness."
(_type_ process-focusable enemy) symbol :replace) ;; 12
(focus-on-with-awareness! "Focus on the process-focusable, updating the aware."
(_type_ process-focusable enemy-aware) symbol) ;; 13
)
)
@@ -41406,34 +41448,34 @@
(jump-height-min meters :offset-assert 244)
(jump-height-factor float :offset-assert 248)
(knocked-seek-ry-clamp float :offset-assert 252)
(knocked-soft-vxz-lo float :offset-assert 256)
(knocked-soft-vxz-hi float :offset-assert 260)
(knocked-soft-vy-lo float :offset-assert 264)
(knocked-soft-vy-hi float :offset-assert 268)
(knocked-medium-vxz-lo float :offset-assert 272)
(knocked-medium-vxz-hi float :offset-assert 276)
(knocked-medium-vy-lo float :offset-assert 280)
(knocked-medium-vy-hi float :offset-assert 284)
(knocked-hard-vxz-lo float :offset-assert 288)
(knocked-hard-vxz-hi float :offset-assert 292)
(knocked-hard-vy-lo float :offset-assert 296)
(knocked-hard-vy-hi float :offset-assert 300)
(knocked-huge-vxz-lo float :offset-assert 304)
(knocked-huge-vxz-hi float :offset-assert 308)
(knocked-huge-vy-lo float :offset-assert 312)
(knocked-huge-vy-hi float :offset-assert 316)
(knocked-yellow-vxz-lo float :offset-assert 320)
(knocked-yellow-vxz-hi float :offset-assert 324)
(knocked-yellow-vy-lo float :offset-assert 328)
(knocked-yellow-vy-hi float :offset-assert 332)
(knocked-red-vxz-lo float :offset-assert 336)
(knocked-red-vxz-hi float :offset-assert 340)
(knocked-red-vy-lo float :offset-assert 344)
(knocked-red-vy-hi float :offset-assert 348)
(knocked-blue-vxz-lo float :offset-assert 352)
(knocked-blue-vxz-hi float :offset-assert 356)
(knocked-blue-vy-lo float :offset-assert 360)
(knocked-blue-vy-hi float :offset-assert 364)
(knocked-soft-vxz-lo meters :offset-assert 256)
(knocked-soft-vxz-hi meters :offset-assert 260)
(knocked-soft-vy-lo meters :offset-assert 264)
(knocked-soft-vy-hi meters :offset-assert 268)
(knocked-medium-vxz-lo meters :offset-assert 272)
(knocked-medium-vxz-hi meters :offset-assert 276)
(knocked-medium-vy-lo meters :offset-assert 280)
(knocked-medium-vy-hi meters :offset-assert 284)
(knocked-hard-vxz-lo meters :offset-assert 288)
(knocked-hard-vxz-hi meters :offset-assert 292)
(knocked-hard-vy-lo meters :offset-assert 296)
(knocked-hard-vy-hi meters :offset-assert 300)
(knocked-huge-vxz-lo meters :offset-assert 304)
(knocked-huge-vxz-hi meters :offset-assert 308)
(knocked-huge-vy-lo meters :offset-assert 312)
(knocked-huge-vy-hi meters :offset-assert 316)
(knocked-yellow-vxz-lo meters :offset-assert 320)
(knocked-yellow-vxz-hi meters :offset-assert 324)
(knocked-yellow-vy-lo meters :offset-assert 328)
(knocked-yellow-vy-hi meters :offset-assert 332)
(knocked-red-vxz-lo meters :offset-assert 336)
(knocked-red-vxz-hi meters :offset-assert 340)
(knocked-red-vy-lo meters :offset-assert 344)
(knocked-red-vy-hi meters :offset-assert 348)
(knocked-blue-vxz-lo meters :offset-assert 352)
(knocked-blue-vxz-hi meters :offset-assert 356)
(knocked-blue-vy-lo meters :offset-assert 360)
(knocked-blue-vy-hi meters :offset-assert 364)
(ragdoll-info ragdoll-setup :offset-assert 368)
(shadow-size meters :offset-assert 372)
(shadow-max-y meters :offset-assert 376)
@@ -41477,6 +41519,16 @@
(ejf6 6)
(ejf7 7)
)
(defenum jump-stage
:type int32
(init 0)
(winding-up 1)
(takeoff 2)
(in-air 3)
(touchdown 4)
(landing 5)
)
;; ---enemy-h:enemy-jump-flags
(deftype enemy-jump-info (structure)
@@ -41601,109 +41653,125 @@
gun-dark-2-stretch ;; 49
)
(:methods
(enemy-method-50 (_type_ int) none) ;; 50
(accelerate-fall! (_type_ vector) float) ;; 51
(damage-enemy! (_type_ object event-message-block) float) ;; 52
(reset-penetrate! (_type_) none) ;; 53
(get-knockback-dir! (_type_ vector) vector) ;; 54
(get-knockback-angle (_type_) degrees) ;; 55
(knocked-handler (_type_ vector) object) ;; 56
(can-collide-with-focus? (_type_ process-focusable) object) ;; 57
(check-water (_type_) object) ;; 58
(enemy-common-post (_type_) none) ;; 59
(lerp-damage (_type_ float) float) ;; 60
(scale-impact-vel-y! (_type_ vector vector float) vector) ;; 61
(get-damage-from-attack (_type_ object event-message-block) float) ;; 62
(enemy-method-63 (_type_ float) float) ;; 63
(update-awareness! (_type_ process-focusable enemy-best-focus) enemy-aware) ;; 64
(penetrate->next-state (_type_ process event-message-block float) symbol) ;; 65
(get-penetrated-by (_type_) penetrate) ;; 66
(coin-flip? (_type_) symbol) ;; 67
(get-enemy-aware (_type_ enemy-aware) enemy-aware) ;; 68
(enemy-method-69 (_type_) none) ;; 69
(enemy-method-70 (_type_ process-focusable enemy-aware) none) ;; 70
(go-dormant (_type_) object) ;; 71
(go-dormant-aware (_type_) object) ;; 72
(go-idle (_type_) object) ;; 73
(go-ambush-delay (_type_) object) ;; 74
(update-collision-action "Change the collision for certain conditions (knocked, etc)" (_type_ int) none) ;; 50
(adjust-transv-under-water! "Modify the velocity as needed if the enemy is underwater." (_type_ vector) float) ;; 51
(damage-enemy-from-attack! "Given an attack message, apply damage." (_type_ object event-message-block) float) ;; 52
(reset-penetrate-later! "After a little bit, reset the penetrate flags back to default." (_type_) none) ;; 53
(get-knockback-dir! "Compute the knockback direction for an incoming attack." (_type_ vector) vector) ;; 54
(get-knockback-angle "Get the yaw angle for the current knock." (_type_) degrees) ;; 55
(knocked-handler "Called when this enemy is knocked." (_type_ vector) object) ;; 56
(can-focus-on? "Check that this enemy can focus on the given focusable.
This reuses the collide bitmask, but isn't actually a collision." (_type_ process-focusable) object) ;; 57
(check-water "Respond to possibly being in water." (_type_) object) ;; 58
(enemy-common-post "Common implementation of post. Runs ja-post." (_type_) none) ;; 59
(impact-velocity-to-hit-points "Given an impact velocity, compute hit points." (_type_ float) float) ;; 60
(attack-direction-from-impact-vel "Compute the direction of an attack given an impact velocity.
This reduces the vertical component, probably to avoid sending the enemy into the air too much." (_type_ vector vector float) vector) ;; 61
(get-damage-from-attack "Compute hit point damage for an attack message." (_type_ object event-message-block) float) ;; 62
(apply-incoming-hitpoint-mods "Modify the hitpoints from an incoming attack.
Keeps enemy alive for a bit while being shot with a blue gun.
This looks cool because you can shoot them many times." (_type_ float) float) ;; 63
(get-awareness-of-proc "Check what the enemies awareness of this pfoc would be. Optionally return more awareness stats in enemy-best-focus." (_type_ process-focusable enemy-best-focus) enemy-aware) ;; 64
(msg-for-incoming-attack "Given an attack message, what do we do next? Returns a message name that should be sent to self." (_type_ process event-message-block float) symbol) ;; 65
(get-penetrated-by "Figure out the penetrated-by mask for this process." (_type_) penetrate) ;; 66
(coin-flip? "Return #t half the time, #f the other." (_type_) symbol) ;; 67
(modify-awareness "Apply modifications to awareness based on the reaction time of an enemy and other settings." (_type_ enemy-aware) enemy-aware) ;; 68
(focus-on-attacker! "If possible, update this enemies focus to the attacker." (_type_) none) ;; 69
(set-focus! "Change our focus to the given process. Optionally, specify awareness." (_type_ process-focusable enemy-aware) none) ;; 70
(go-dormant "Go to the dormant state. This disables drawing/processing/collision, and runs no logic." (_type_) object) ;; 71
(go-dormant-aware "Go to the dormat aware state.
Similar to dormant, drawing/collision are disabled, but enemies can exit dormant-aware." (_type_) object) ;; 72
(go-idle "Go to an idle state." (_type_) object) ;; 73
(go-ambush "May go to ambush-delay first, if set in the res-lump." (_type_) object) ;; 74
(go-stare (_type_) object) ;; 75
(go-stare2 (_type_) object) ;; 76
(go-directed (_type_) object) ;; 77
(go-hostile (_type_) object) ;; 78
(go-flee (_type_) object) ;; 79
(go-best-state (_type_) object) ;; 80
(go-die (_type_) object) ;; 81
(event-handler (_type_ process int symbol event-message-block) object :behavior enemy) ;; 82
(enemy-touch-handler (_type_ process event-message-block) object) ;; 83
(send-attack-on-jump-or-knocked (_type_ process event-message-block) object) ;; 84
(knocked-anim (_type_ enemy-knocked-info) symbol) ;; 85
(knocked-land-anim (_type_ enemy-knocked-info) symbol) ;; 86
(knocked-anim-handler (_type_ int enemy-knocked-info) symbol) ;; 87
(enemy-method-88 (_type_ enemy-knocked-info) symbol) ;; 88
(within-gspot-range? (_type_) symbol) ;; 89
(enemy-method-90 (_type_ ragdoll-proc) none) ;; 90
(enemy-method-91 (_type_ enemy-jump-info) object) ;; 91
(init-jump-info! (_type_ enemy-jump-info) none) ;; 92
(setup-jump! (_type_ enemy-jump-info) none) ;; 93
(move-to-gspot! (_type_) float) ;; 94
(on-ground? (_type_ enemy-jump-info) symbol) ;; 95
(jump-in-air-anim (_type_ enemy-jump-info) symbol) ;; 96
(jump-land-anim (_type_ enemy-jump-info) symbol) ;; 97
(jump-wind-up-anim (_type_ enemy-jump-info) symbol) ;; 98
(jump-anim-handler (_type_ int enemy-jump-info) symbol) ;; 99
(in-jump-handler (_type_ int enemy-jump-info) none) ;; 100
(enemy-method-101 (_type_ int enemy-jump-info) none) ;; 101
(go-directed2 (_type_) object) ;; 102
(enemy-method-103 (_type_ vector float) symbol) ;; 103
(enemy-method-104 (_type_ vector float) symbol) ;; 104
(enemy-method-105 (_type_ float symbol) symbol) ;; 105
(find-best-focus (_type_) process) ;; 106
(is-pfoc-in-mesh? (_type_ process-focusable vector) symbol) ;; 107
(enemy-method-108 (_type_ process-focusable) symbol) ;; 108
(enemy-method-109 (_type_) symbol) ;; 109
(send-attack (_type_ process touching-shapes-entry uint) symbol) ;; 110
(on-attack (_type_ process-focusable) none) ;; 111
(get-incoming-attack! (_type_ process-drawable event-message-block penetrate attack-info touching-shapes-entry) none) ;; 112
(get-focus! (_type_) process-focusable) ;; 113
(send-attack-to-all-tshapes (_type_ process-focusable event-message-block) int) ;; 114
(set-look-at-mode! (_type_ int) none) ;; 115
(stop-look-at! (_type_) none) ;; 116
(apply-friction (_type_) none) ;; 117
(init-enemy-info! (_type_ enemy-info) none) ;; 118
(init-enemy-defaults! (_type_ enemy-info) none) ;; 119
(init-enemy-collision! (_type_) none) ;; 120
(init-enemy! (_type_) none) ;; 121
(go-idle2 (_type_) object) ;; 122
(enemy-method-123 (_type_) symbol) ;; 123
(disable-ragdoll (_type_) none) ;; 124
(ragdoll-settled? (_type_) object) ;; 125
(ragdoll-spawn! (_type_ symbol symbol) vector) ;; 126
(deactivate-ragdoll! (_type_) none) ;; 127
(rnd-float (_type_) float) ;; 128
(rnd-float-range (_type_ float float) float) ;; 129
(rnd-int (_type_ int) int) ;; 130
(enemy-method-131 (_type_ int int) int) ;; 131
(set-reaction-time! (_type_ time-frame time-frame) time-frame) ;; 132
(rnd-chance? (_type_ float) symbol) ;; 133
(enemy-method-134 (_type_ float) symbol) ;; 134
(go-directed "Go to the directed state which assumes that something else will control the enemy." (_type_) object) ;; 77
(go-hostile "Go to the hostile state, actively trying to attack the target." (_type_) object) ;; 78
(go-flee "Go to the flee state, running away." (_type_) object) ;; 79
(go-state-for-focused "Go to the appropriate state for the current awareness of the focused process." (_type_) object) ;; 80
(go-die "Go to the die state." (_type_) object) ;; 81
(event-handler "Commmon handler for events." (_type_ process int symbol event-message-block) object :behavior enemy) ;; 82
(enemy-touch-handler "General handler for an event when a process intentionally sends a touch event." (_type_ process event-message-block) object) ;; 83
(enemy-touched-handler "General handler for when anything touches an enemy (automatic response)." (_type_ process event-message-block) object) ;; 84
(knocked-anim "start the knocked animation." (_type_ enemy-knocked-info) symbol) ;; 85
(knocked-land-anim "start the knocked-land animation." (_type_ enemy-knocked-info) symbol) ;; 86
(knocked-anim-handler "start or play the approriate animation for an enemy being knocked." (_type_ int enemy-knocked-info) symbol) ;; 87
(done-being-knocked? "has the enemy hit the ground or stopped after being knocked back?" (_type_ enemy-knocked-info) symbol) ;; 88
(invalid-height? "Return #t if the enemy is too high in the air, or below the ground." (_type_) symbol) ;; 89
(copy-ragdoll-orientation-to-root "Apply rotational offset from ragdolling back to the enemy.
Used when disabling a ragdoll to update the enemy
orientation to match the end of ragdoll orientation." (_type_ ragdoll-proc) none) ;; 90
(check-jump-blocked? "Is this jump blocked by something?" (_type_ enemy-jump-info) object) ;; 91
(init-jump-info! "Populate an enemy-jump-info for jumping to this enemy's event-param-point" (_type_ enemy-jump-info) none) ;; 92
(setup-jump-trajectory! "Compute jump trajectory." (_type_ enemy-jump-info) none) ;; 93
(move-to-gspot! "Snap the enemy down onto the cached ground spot (gspot)." (_type_) float) ;; 94
(landed-jump-yet? "Is this on, or close to, the ground?" (_type_ enemy-jump-info) symbol) ;; 95
(jump-in-air-anim "Start playing the in-air anim" (_type_ enemy-jump-info) symbol) ;; 96
(jump-land-anim "Play the landing anim" (_type_ enemy-jump-info) symbol) ;; 97
(jump-wind-up-anim "Start playing the wind-up anim" (_type_ enemy-jump-info) symbol) ;; 98
(jump-anim-handler (_type_ jump-stage enemy-jump-info) symbol) ;; 99
(move-along-ballistic-trajectory-for-jump "Adjust trans, transv for the jump, if we're airborne." (_type_ jump-stage enemy-jump-info) none) ;; 100
(adjust-heading-for-jump "Can be overriden. Yaw the enemy in response to an ongoing jump." (_type_ jump-stage enemy-jump-info) none) ;; 101
(go-next-state-auto "Pick the next state automatically. Will enter directed state if this enemy is directed, or pick based on focus/aware." (_type_) object) ;; 102
(heading-matches-direction? "Does this enemy's heading match the given heading? Threshold in degrees." (_type_ vector float) symbol) ;; 103
(pointing-toward? "Is this enemy pointing toward the given point? Threshold in degrees." (_type_ vector float) symbol) ;; 104
(pointing-toward-focus? "Is this enemy pointing toward its focused process?" (_type_ float symbol) symbol) ;; 105
(find-best-focus "Search for the best thing to focus on." (_type_) process) ;; 106
(can-become-hostile-to? "Return if this enemy can become hostile to the process." (_type_ process-focusable vector) symbol) ;; 107
(should-flee-from? "Return if this enemy should flee from the process." (_type_ process-focusable) symbol) ;; 108
(out-of-bounds? "Has the enemy gone somewhere it shouldn't?
Used to kill some enemies that can be knocked of regions." (_type_) symbol) ;; 109
(send-attack-from-tshape "Send an attack from this enemy to something else." (_type_ process touching-shapes-entry uint) symbol) ;; 110
(on-attack "Handler after this enemy attacks something. By default focuses on the attacked, but could be overriden." (_type_ process-focusable) none) ;; 111
(handle-incoming-attack! "Set up this enemy to handle an incoming attack event." (_type_ process-drawable event-message-block penetrate attack-info touching-shapes-entry) none) ;; 112
(get-focus! "If we're focusing on something alive, return it." (_type_) process-focusable) ;; 113
(find-and-damage-attackers "Find things that have attacked us, then deal damage back.
This is used for attacks that damage both the player and the enemy,
like hitting a guard with a jetboard." (_type_ process-focusable event-message-block) int) ;; 114
(set-look-at-mode! "Pick between 1: look at the focus, or 2: look at where you're going." (_type_ int) none) ;; 115
(stop-look-at! "Stop looking at something. Disables neck joint mod." (_type_) none) ;; 116
(apply-friction "Slow down the enemy due to friction with the ground." (_type_) none) ;; 117
(set-enemy-info! "Set the enemy-info" (_type_ enemy-info) none) ;; 118
(setup-enemy! "Initialize the enemy by setting all the enemy-specific fields." (_type_ enemy-info) none) ;; 119
(init-enemy-collision! "Typical place to construct collision shapes" (_type_) none) ;; 120
(init-enemy! "Typical place for shared init code. Runs from entity or process style init." (_type_) none) ;; 121
(go-fallback-init "If there's no specific settings for initial state, go to this state after spawning." (_type_) object) ;; 122
(allow-ragdoll? "Can this enemy ragdoll now?" (_type_) symbol) ;; 123
(disable-ragdoll "Smoothly disable the ragdoll and transition back to normal control." (_type_) none) ;; 124
(ragdoll-settled? "Has the ragdoll stopped moving?" (_type_) object) ;; 125
(ragdoll-spawn! "If possible, spawn ragdoll and start using it." (_type_ symbol symbol) vector) ;; 126
(deactivate-ragdoll! "Deactivate the ragdoll process." (_type_) none) ;; 127
(rnd-float "Get a random number from 0 to 1" (_type_) float) ;; 128
(rnd-float-range "Get a random float in the range" (_type_ float float) float) ;; 129
(rnd-int "Get a random int from to to the specified int" (_type_ int) int) ;; 130
(rnd-int-excluding-masked "Get a random int in the range. Exclude a value n by setting the n-th bit of the mask."(_type_ int int) int) ;; 131
(rnd-time-frame "Get a random time frame." (_type_ time-frame time-frame) time-frame) ;; 132
(rnd-chance? "Returns true with the given probability." (_type_ float) symbol) ;; 133
(rnd-chance-for-idle?
"Like rnd-chance, but is more likely to return true when the game is close to not fitting in frame rate.
This makes enemies start idling more if the game isn't running fast enough." (_type_ float) symbol) ;; 134
(enemy-method-135 (_type_) none) ;; 135
(set-ground-pat! (_type_ collide-query collide-spec float float float process) pat-surface) ;; 136
(enemy-above-ground? (_type_ collide-query vector collide-spec float float float) symbol) ;; 137
(try-locate-ground (_type_ meters meters symbol collide-spec) symbol) ;; 138
(move-above-ground! (_type_ vector move-above-ground-params) none) ;; 139
(update-focus (_type_) process) ;; 140
(enemy-method-141 (_type_ float) symbol) ;; 141
(penetrate->knocked-type (_type_ penetrate) knocked-type) ;; 142
(find-ground-and-set-pat! "Figure out what ground we're standing on and update the ground-pat.
Usually this will be done automatically by the collision system.
This method should be called after manually repositioning an enemy." (_type_ collide-query collide-spec float float float process) pat-surface) ;; 136
(enemy-above-ground? "Is this enemy above the ground?" (_type_ collide-query vector collide-spec float float float) symbol) ;; 137
(move-to-ground "Snap the enemy to the ground below." (_type_ meters meters symbol collide-spec) symbol) ;; 138
(move-above-ground! "Move the enemy. May keep the enemy snapped to the ground depending on flags." (_type_ vector move-above-ground-params) none) ;; 139
(update-focus "Potentially update the focus, if there is something better to focus on." (_type_) process) ;; 140
(check-awareness-trigger "Check triggering logic for awareness to see if this enemy can become aware yet." (_type_ float) symbol) ;; 141
(penetrate->knocked-type "Based on the penetrate of an attacker, pick the knocked-type." (_type_ penetrate) knocked-type) ;; 142
(on-dying (_type_) none) ;; 143
(falling? (_type_) symbol) ;; 144
(find-offending-pfoc (_type_ process attack-info) process-focusable) ;; 145
(play-damage-sound (_type_ int) sound-id) ;; 146
(check-victory (_type_) none) ;; 147
(go-gun-dark-2-stretch (_type_) object) ;; 148
(have-more-than-10-joints? (_type_) object) ;; 149
(enemy-method-150 (_type_) symbol) ;; 150
(should-move-to-ground? (_type_) symbol) ;; 151
(enemy-method-152 (_type_) float) ;; 152
(find-offending-pfoc "Figure out the attacker process from the attack message sender and attack-info.
This is to handle cases where the attacker process is a non-focusable subprocess,
or the attacker is driving a vehicle."(_type_ process attack-info) process-focusable) ;; 145
(play-damage-sound "Pick and play the damage/death sound." (_type_ int) sound-id) ;; 146
(clear-stale-victory "Remove victory flag if needed." (_type_) none) ;; 147
(go-gun-dark-2-stretch "Go to the gun-dark-2-stretch state." (_type_) object) ;; 148
(have-more-than-10-joints? "Does what it says, unused" (_type_) object) ;; 149
(can-be-nuked? "Can this enemy be instantly destroyed by the nuke?" (_type_) symbol) ;; 150
(should-move-to-ground? "Should this enemy be moved to the ground while moving?" (_type_) symbol) ;; 151
(gem-chance "The chance of this enemy having a gem." (_type_) float) ;; 152
(get-gem-pool-idx (_type_) int) ;; 153
(mark-as-dead (_type_) none) ;; 154
)
@@ -41777,8 +41845,8 @@
debug-control ;; 159
)
(:methods
(init-enemy-info! (_type_ nav-enemy-info) none :replace) ;; 118
(init-enemy-defaults! (_type_ nav-enemy-info) object :replace) ;; 125
(set-enemy-info! (_type_ nav-enemy-info) none :replace) ;; 118
(setup-enemy! (_type_ nav-enemy-info) object :replace) ;; 125
(normalize-heading! (_type_ nav-control) none) ;; 160
(nav-enemy-method-161 (_type_ nav-control) none) ;; 161
(nav-enemy-method-162 (_type_) none) ;; 162
@@ -41827,13 +41895,16 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-extern *enemy-dummy-shadow-control* shadow-control)
(define-extern get-penetrate-using-from-attack-event (function process-drawable event-message-block penetrate))
(define-extern enemy-setup-gem (function object :behavior enemy))
(define-extern enemy-init-by-other (function process-drawable enemy-init-by-other-params object :behavior enemy))
(define-extern enemy-event-handler (function process int symbol event-message-block object :behavior enemy))
(define-extern enemy-simple-post (function none :behavior enemy))
(define-extern enemy-falling-post (function none :behavior enemy))
(define-extern enemy-die-falling-post (function none :behavior enemy))
(define-extern get-penetrate-using-from-attack-event "Given an attack event to an enemy, return the penetrate that should be applied to the enemy"
(function process-drawable event-message-block penetrate))
(define-extern enemy-setup-gem "Determine if the enemy should have a gem and set drawing masks/particles as needed." (function object :behavior enemy))
(define-extern enemy-init-by-other "Function to initialize an enemy from a parent process." (function process-drawable enemy-init-by-other-params object :behavior enemy))
(define-extern enemy-event-handler "Default event handler for enemy." (function process int symbol event-message-block object :behavior enemy))
(define-extern enemy-simple-post "Default post for enemy." (function none :behavior enemy))
(define-extern enemy-falling-post "Post function that simply makes the enemy go down.
Collision is enabled, so enemy will bounce off of walls or similar." (function none :behavior enemy))
(define-extern enemy-die-falling-post "Post function that causes the enemy to go down until it hits the ground.
Doesn't use full collision system - enemy will stop moving as soon as it hits any ground."(function none :behavior enemy))
(define-extern *shockwave-knock-scalar* curve2d-fast)
(define-extern ja-group-index? (function int symbol :behavior enemy))
@@ -42123,6 +42194,12 @@
;; rigid-body ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(deftype rigid-body-stack (structure)
((vec vector :inline)
(mat matrix :inline)
)
)
(deftype rigid-body-work (structure)
((max-ang-momentum float :offset-assert 0)
(max-ang-velocity float :offset-assert 4)
@@ -44394,9 +44471,9 @@
(within-outer-ring symbol :offset-assert 136)
(within-inner-ring symbol :offset-assert 140)
(ouched symbol :offset-assert 144)
(bound-cam basic :offset-assert 148)
(bound-cam string :offset-assert 148)
(trans vector :inline :offset-assert 160)
(state-time uint64 :offset-assert 176)
(state-time time-frame :offset-assert 176)
(jak-in-hint-region symbol :offset-assert 184)
(watchers-vulnerable symbol :offset-assert 188)
)
@@ -44429,7 +44506,7 @@
standing-down ;; 31
)
(:methods
(tpl-watcher-method-32 (_type_) none) ;; 32
(init-collision! (_type_) none) ;; 32
)
)
@@ -49308,7 +49385,7 @@
in-ditch ;; 192
)
(:methods
(init-enemy-defaults! (_type_ nav-enemy-info) none :replace)
;(init-enemy-defaults! (_type_ nav-enemy-info) none :replace)
(set-squad (_type_) none) ;; 193
(citizen-method-194 (_type_) none) ;; 194
(citizen-method-195 (_type_) none) ;; 195
+1 -1
View File
@@ -73,7 +73,7 @@
"write_hex_near_instructions": false,
// to write out "scripts", which are currently just all the linked lists found. mostly a jak 2/3 thing
"write_scripts": true,
"write_scripts": false,
// hex dump of code/data files.
"hexdump_code": false,
@@ -1000,5 +1000,10 @@
[12, "(function none :behavior scene-player)"],
[13, "(function none :behavior scene-player)"],
[14, "(function none :behavior scene-player)"]
],
"bigmap": [
[15, "(function external-art-buffer object)"],
[16, "(function external-art-buffer object)"],
[17, "(function external-art-buffer object)"]
]
}
@@ -735,10 +735,6 @@
// 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],
+248 -5
View File
@@ -186,18 +186,18 @@
"DGO/PRECA.DGO",
"DGO/PRECB.DGO",
"DGO/PRECC.DGO",
// "DGO/PRECD.DGO",
// // title/intro
"DGO/PRECD.DGO",
// title/intro
"DGO/WIN.DGO", // wasintro
"DGO/TITLE.DGO",
"DGO/INTTITLE.DGO",
"DGO/INTPALRF.DGO", // intro-palace-roof
"DGO/IPF.DGO", // intro-palace-fall
"DGO/INTROCST.DGO",
// // outro
// outro
"DGO/OUTCAST3.DGO",
"DGO/OUTROCST.DGO",
// // museum
// museum
"DGO/MUSEUM.DGO",
"DGO/MUSEUM2.DGO",
"DGO/MUSEUM3.DGO",
@@ -311,8 +311,245 @@
"DGO/LWSTDPCK.DGO"
],
// STR files containing a texture that should be used by
// FR3 creation.
"str_texture_file_names": ["STR/PRMINIMA.STR"],
// some objects are part of STR files (streaming data).
"str_file_names": [],
"str_file_names": [
"STR/ARF1INTR.STR",
"STR/ARF1RES.STR",
"STR/ARF2INTR.STR",
"STR/ARF2RES.STR",
"STR/ARF3INTR.STR",
"STR/ARF3RES.STR",
"STR/AROUTRO.STR",
"STR/ART1INTR.STR",
"STR/CAGSHIEL.STR",
"STR/CATRES.STR",
"STR/CAWRRES.STR",
"STR/CIATIDES.STR",
"STR/CIATOUT.STR",
"STR/CIBBINTR.STR",
"STR/CIBBRES.STR",
"STR/CIBTINTR.STR",
"STR/CIDGRES.STR",
"STR/CIFCEINT.STR",
"STR/CIGC1RES.STR",
"STR/CIGC2INT.STR",
"STR/CIGC2RES.STR",
"STR/CIGCINTR.STR",
"STR/CIGDPUNC.STR",
"STR/CIGTCINT.STR",
"STR/CIHVRES.STR",
"STR/CIPAIB.STR",
"STR/CIPAINTR.STR",
"STR/CIPARES.STR",
"STR/CIPFINTR.STR",
"STR/CIPGINTR.STR",
"STR/CIPGRES.STR",
"STR/CIPHINTR.STR",
"STR/CIPHRES.STR",
"STR/CISFINTR.STR",
"STR/COETEMPL.STR",
"STR/COEXIT.STR",
"STR/DAD06.STR",
"STR/DAD07.STR",
"STR/DAD10.STR",
"STR/DAD12.STR",
"STR/DAD13.STR",
"STR/DAD14.STR",
"STR/DAD16.STR",
"STR/DAD17.STR",
"STR/DAD18.STR",
"STR/DAD20.STR",
"STR/DAD21.STR",
"STR/DAD24.STR",
"STR/DAD31.STR",
"STR/DAD35.STR",
"STR/DAD38.STR",
"STR/DAD57.STR",
"STR/DAD58.STR",
"STR/DAD61.STR",
"STR/DAMOLE.STR",
"STR/DEAR1INT.STR",
"STR/DEAR1RES.STR",
"STR/DEAR2INT.STR",
"STR/DEATIN.STR",
"STR/DEATOUT.STR",
"STR/DEBBINTR.STR",
"STR/DECLINTR.STR",
"STR/DECRINTR.STR",
"STR/DECWIN.STR",
"STR/DEFBIA.STR",
"STR/DEFBINTR.STR",
"STR/DEFBRB.STR",
"STR/DEFBRES.STR",
"STR/DEGRES.STR",
"STR/DEHINTRO.STR",
"STR/DEHRES.STR",
"STR/DEJGOTA.STR",
"STR/DEJGOTB.STR",
"STR/DEJGOTC.STR",
"STR/DEJMINTR.STR",
"STR/DELC2.STR",
"STR/DELC3.STR",
"STR/DELCATCH.STR",
"STR/DEODRB.STR",
"STR/DEODRES.STR",
"STR/DERINTRO.STR",
"STR/DERRA.STR",
// "STR/DESCREEN.STR",
"STR/DPBTURRE.STR",
"STR/FABINTRO.STR",
"STR/FABRES.STR",
"STR/FAI1INTR.STR",
"STR/FAI2INTR.STR",
"STR/FAI3INTR.STR",
"STR/FAI4INTR.STR",
"STR/FASBIB.STR",
"STR/FASBINTR.STR",
"STR/FASBRES.STR",
"STR/FORB.STR",
"STR/FORCRES.STR",
"STR/FOTOMRES.STR",
"STR/FOTOWER.STR",
"STR/GRMANIMS.STR",
"STR/INDROP.STR",
"STR/INFFHQ.STR",
"STR/INLOST.STR",
"STR/INPALACE.STR",
"STR/INRESCUE.STR",
"STR/INTIRED.STR",
"STR/INTRAINI.STR",
"STR/JAA1.STR",
"STR/JAA2.STR",
"STR/JAA3.STR",
"STR/JAA4.STR",
"STR/JAA5.STR",
"STR/JAA6.STR",
"STR/JAA7.STR",
"STR/JABOARD.STR",
"STR/JACARRY.STR",
"STR/JAD1.STR",
"STR/JAD2.STR",
"STR/JAD3.STR",
"STR/JAD4.STR",
"STR/JAD5.STR",
"STR/JADARK.STR",
"STR/JADON.STR",
"STR/JADUMMY.STR",
"STR/JAEBOARD.STR",
"STR/JAEDARK.STR",
"STR/JAEGC.STR",
"STR/JAEGNORM.STR",
"STR/JAEGOLD.STR",
"STR/JAELIGHT.STR",
"STR/JAENORMA.STR",
// "STR/JAEXTERN.STR",
"STR/JAFLDAX.STR",
"STR/JAFLUT.STR",
"STR/JAGUN.STR",
"STR/JAICE.STR",
"STR/JAINDAX.STR",
"STR/JAKANGA.STR",
"STR/JALADDER.STR",
"STR/JALIGHT.STR",
"STR/JAMECH.STR",
"STR/JAPEGASU.STR",
"STR/JAPGLIDE.STR",
"STR/JAPGUN.STR",
"STR/JAPHCAR.STR",
"STR/JAPIDAX.STR",
"STR/JAPILOT.STR",
"STR/JAPOLE.STR",
"STR/JAPWCAR.STR",
"STR/JARACER.STR",
"STR/JASWIM.STR",
"STR/JATENTAC.STR",
"STR/JATUBE.STR",
"STR/JATURRET.STR",
"STR/KRWB1.STR",
"STR/KRWB2.STR",
"STR/KRWB3.STR",
"STR/MIBINTRO.STR",
"STR/MIBRES.STR",
"STR/MIERES.STR",
"STR/MIGEXIT.STR",
"STR/MITINTRO.STR",
"STR/MITRES.STR",
"STR/MU2ANIMS.STR",
"STR/MU3ANIMS.STR",
"STR/MU4ANIMS.STR",
"STR/MUANIMS.STR",
"STR/NEDBARRI.STR",
"STR/NEEINTRO.STR",
"STR/NEHINTRO.STR",
"STR/NEHRES.STR",
"STR/NSB1BREA.STR",
"STR/NSB2BREA.STR",
"STR/PARAINTR.STR",
"STR/PARARA.STR",
"STR/PARARES.STR",
"STR/PARPINTR.STR",
"STR/PEFLY.STR",
"STR/POAINTRO.STR",
"STR/PRDSERES.STR",
"STR/PRDSLOSE.STR",
"STR/PRDSRES.STR",
"STR/PRHA.STR",
"STR/PRHB.STR",
"STR/PRHC.STR",
"STR/PRHFINAL.STR",
// "STR/PRMINIMA.STR",
"STR/PRTRES.STR",
"STR/RATA1INT.STR",
"STR/RATA2INT.STR",
// "STR/SCBOOK.STR",
"STR/SEEINTRO.STR",
"STR/SEGENTRA.STR",
"STR/SEHKENTR.STR",
"STR/SEHKRES.STR",
"STR/SEKENTRA.STR",
"STR/SEKEXIT.STR",
"STR/SEKMINTR.STR",
"STR/SEMEXIT.STR",
"STR/SEMHINTR.STR",
"STR/SEPEXIT.STR",
"STR/SESGRUNT.STR",
"STR/SEWATERS.STR",
"STR/TECINTRO.STR",
"STR/TECRES.STR",
"STR/TEDINTRO.STR",
"STR/TEDRES.STR",
"STR/TEEANIMS.STR",
"STR/TEELAANI.STR",
"STR/TEELODS.STR",
"STR/TEJGLGLI.STR",
"STR/TEOINTRO.STR",
"STR/TEORES.STR",
"STR/TETINTRO.STR",
"STR/TETRA.STR",
"STR/TETRB.STR",
"STR/TEWDESER.STR",
"STR/TODINTRO.STR",
"STR/TODRB.STR",
"STR/TODRES.STR",
"STR/VODRES.STR",
"STR/VOI1INTR.STR",
"STR/VOI1RES.STR",
"STR/VOI2INTR.STR",
"STR/VOI2RES.STR",
"STR/WACINTRO.STR",
"STR/WADRES.STR",
"STR/WAGINTRO.STR",
"STR/WAGRES.STR",
"STR/WALRINTR.STR",
"STR/WALRRES.STR",
"STR/WAPGINTR.STR",
"STR/WAPGRES.STR"
// "STR/WOMAP.STR"
],
// streaming "art" that should be added to GAME.FR3.
"str_art_file_names": ["STR/JAEXTERN.STR"],
@@ -343,6 +580,12 @@
"VAGWAD.INT"
],
// tpages that should always be possible to access.
"common_tpages": [
17, // PRMINIMA progress-minimap
3349 // PRMINIMA progress-minimap2
],
"animated_textures": [
// dark jak
"jakc-arm",
@@ -1046,7 +1046,7 @@
"desertf-obs": [["L99", "(inline-array vector)", 2]],
"desert-dust-storm": [["L89", "vector"]],
"artifact-race": [
["L162", "(inline-array talker-speech-class)", 16],
["L162", "(inline-array talker-speech-class)", 32],
["L160", "vector"],
["L159", "vector"],
["L158", "vector"],
@@ -429,7 +429,7 @@
"(method 22 rigid-body-control)": [[16, ["inline-array", "vector", 2]]],
"(method 23 rigid-body-control)": [[16, ["inline-array", "vector", 2]]],
"(method 24 rigid-body-control)": [[16, ["inline-array", "vector", 2]]],
"(method 28 rigid-body-control)": [[16, "rigid-body-impact"]],
"(method 28 rigid-body-control)": [[16, "rigid-body-stack"]],
"(method 50 rigid-body-object)": [[16, "rigid-body-impact"]],
"(method 51 rigid-body-object)": [[16, "rigid-body-impact"]],
"ptest": [[16, "vector"]],
@@ -1067,7 +1067,7 @@
[208, ["array", "uint32", 1]]
],
"(method 35 was-squad-control)": [
[16, ["inline-array", "matrix", 2]],
[16, ["inline-array", "matrix", 4]],
[240, "cquery-with-5vec"]
],
"(method 39 vehicle-wheel)": [[16, "rigid-body-move-work"]],
@@ -2513,5 +2513,12 @@
[80, "matrix"],
[144, "matrix"],
[208, "matrix"]
],
"(method 12 bigmap)": [[32, "matrix"]],
"(method 22 bigmap)": [
[16, "vector4w"],
[32, "vector"],
[48, "vector"],
[64, "vector"]
]
}
@@ -1 +1 @@
[[224067587,{"idx":3,"name":"common-gray-dark","tpage_name":"museum4-water"}],[224067586,{"idx":2,"name":"common-glass","tpage_name":"museum4-water"}],[223936522,{"idx":10,"name":"bab-skin","tpage_name":"museum4b-pris"}],[223936521,{"idx":9,"name":"bab-shoulderstrap","tpage_name":"museum4b-pris"}],[223936520,{"idx":8,"name":"bab-pendant","tpage_name":"museum4b-pris"}],[223936519,{"idx":7,"name":"bab-nail-01","tpage_name":"museum4b-pris"}],[223936518,{"idx":6,"name":"bab-longfur","tpage_name":"museum4b-pris"}],[223936517,{"idx":5,"name":"bab-furtrans","tpage_name":"museum4b-pris"}],[223936516,{"idx":4,"name":"bab-furskin-trans","tpage_name":"museum4b-pris"}],[223936515,{"idx":3,"name":"bab-fur","tpage_name":"museum4b-pris"}],[223936514,{"idx":2,"name":"bab-eye","tpage_name":"museum4b-pris"}],[223936513,{"idx":1,"name":"bab-diaper","tpage_name":"museum4b-pris"}],[223936512,{"idx":0,"name":"bab-allfur","tpage_name":"museum4b-pris"}],[223871035,{"idx":59,"name":"environment-oldmetal","tpage_name":"museum3b-pris2"}],[223871034,{"idx":58,"name":"daxter-furhilite","tpage_name":"museum3b-pris2"}],[223871033,{"idx":57,"name":"charHOLD","tpage_name":"museum3b-pris2"}],[223871032,{"idx":56,"name":"brut-toenails","tpage_name":"museum3b-pris2"}],[223871031,{"idx":55,"name":"brut-ties","tpage_name":"museum3b-pris2"}],[223871030,{"idx":54,"name":"brut-teeth","tpage_name":"museum3b-pris2"}],[223871029,{"idx":53,"name":"brut-shirt","tpage_name":"museum3b-pris2"}],[223871028,{"idx":52,"name":"brut-metalrim","tpage_name":"museum3b-pris2"}],[223871027,{"idx":51,"name":"brut-lens","tpage_name":"museum3b-pris2"}],[223871026,{"idx":50,"name":"brut-legfur","tpage_name":"museum3b-pris2"}],[223871025,{"idx":49,"name":"brut-jaw","tpage_name":"museum3b-pris2"}],[223871024,{"idx":48,"name":"brut-jacket","tpage_name":"museum3b-pris2"}],[223871023,{"idx":47,"name":"brut-headtop","tpage_name":"museum3b-pris2"}],[223871022,{"idx":46,"name":"brut-handpalm","tpage_name":"museum3b-pris2"}],[223871021,{"idx":45,"name":"brut-hair","tpage_name":"museum3b-pris2"}],[223871020,{"idx":44,"name":"brut-foottop","tpage_name":"museum3b-pris2"}],[223871019,{"idx":43,"name":"brut-footstrap","tpage_name":"museum3b-pris2"}],[223871018,{"idx":42,"name":"brut-footbottom","tpage_name":"museum3b-pris2"}],[223871017,{"idx":41,"name":"brut-finger","tpage_name":"museum3b-pris2"}],[223871016,{"idx":40,"name":"brut-feather","tpage_name":"museum3b-pris2"}],[223871015,{"idx":39,"name":"brut-eyelid","tpage_name":"museum3b-pris2"}],[223871014,{"idx":38,"name":"brut-eye","tpage_name":"museum3b-pris2"}],[223871013,{"idx":37,"name":"brut-diaper","tpage_name":"museum3b-pris2"}],[223871012,{"idx":36,"name":"brut-cloaktop","tpage_name":"museum3b-pris2"}],[223871011,{"idx":35,"name":"brut-cloaktail","tpage_name":"museum3b-pris2"}],[223871010,{"idx":34,"name":"brut-button","tpage_name":"museum3b-pris2"}],[223871009,{"idx":33,"name":"brut-armsleeve","tpage_name":"museum3b-pris2"}],[223805572,{"idx":132,"name":"krew-rteye","tpage_name":"museum3b-pris"}],[223805571,{"idx":131,"name":"krew-lfteye","tpage_name":"museum3b-pris"}],[223805570,{"idx":130,"name":"krew-eyelid","tpage_name":"museum3b-pris"}],[223805569,{"idx":129,"name":"vin-waistband","tpage_name":"museum3b-pris"}],[223805568,{"idx":128,"name":"vin-teeth-01","tpage_name":"museum3b-pris"}],[223805567,{"idx":127,"name":"vin-suspendercenter","tpage_name":"museum3b-pris"}],[223805566,{"idx":126,"name":"vin-shoe-02","tpage_name":"museum3b-pris"}],[223805565,{"idx":125,"name":"vin-shoe-01","tpage_name":"museum3b-pris"}],[223805564,{"idx":124,"name":"vin-shirt-02","tpage_name":"museum3b-pris"}],[223805563,{"idx":123,"name":"vin-shirt-01","tpage_name":"museum3b-pris"}],[223805562,{"idx":122,"name":"vin-pants","tpage_name":"museum3b-pris"}],[223805561,{"idx":121,"name":"vin-metal","tpage_name":"museum3b-pris"}],[223805560,{"idx":120,"name":"vin-ltbrownstrap","tpage_name":"museum3b-pris"}],[223805559,{"idx":119,"name":"vin-lens","tpage_name":"museum3b-pris"}],[223805558,{"idx":118,"name":"vin-hair-02","tpage_name":"museum3b-pris"}],[223805557,{"idx":117,"name":"vin-hair-01","tpage_name":"museum3b-pris"}],[223805556,{"idx":116,"name":"vin-gunhandle-01","tpage_name":"museum3b-pris"}],[223805555,{"idx":115,"name":"vin-gunbarrel-02","tpage_name":"museum3b-pris"}],[223805554,{"idx":114,"name":"vin-gunbarrel","tpage_name":"museum3b-pris"}],[223805553,{"idx":113,"name":"vin-glove-02","tpage_name":"museum3b-pris"}],[223805552,{"idx":112,"name":"vin-glove-01","tpage_name":"museum3b-pris"}],[223805551,{"idx":111,"name":"vin-finger-01","tpage_name":"museum3b-pris"}],[223805550,{"idx":110,"name":"vin-face-01","tpage_name":"museum3b-pris"}],[223805549,{"idx":109,"name":"vin-emblem","tpage_name":"museum3b-pris"}],[223805548,{"idx":108,"name":"vin-ear","tpage_name":"museum3b-pris"}],[223805547,{"idx":107,"name":"vin-clip","tpage_name":"museum3b-pris"}],[223805546,{"idx":106,"name":"vin-blackstrap","tpage_name":"museum3b-pris"}],[223805545,{"idx"Line truncated
[[1114251,{"idx":139,"name":"arena-04","tpage_name":"progress-minimap"}],[1114250,{"idx":138,"name":"arena-03","tpage_name":"progress-minimap"}],[1114246,{"idx":134,"name":"precursor-03","tpage_name":"progress-minimap"}],[1114245,{"idx":133,"name":"precursor-02","tpage_name":"progress-minimap"}],[1114238,{"idx":126,"name":"rubble-03","tpage_name":"progress-minimap"}],[1114235,{"idx":123,"name":"comb-04","tpage_name":"progress-minimap"}],[1114220,{"idx":108,"name":"factory-01","tpage_name":"progress-minimap"}],[1114150,{"idx":38,"name":"hud-bronzecup","tpage_name":"progress-minimap"}],[1114144,{"idx":32,"name":"forest-04","tpage_name":"progress-minimap"}],[1114143,{"idx":31,"name":"forest-03","tpage_name":"progress-minimap"}],[1114142,{"idx":30,"name":"forest-02","tpage_name":"progress-minimap"}],[1114141,{"idx":29,"name":"forest-01","tpage_name":"progress-minimap"}],[1114132,{"idx":20,"name":"default-jak-04","tpage_name":"progress-minimap"}],[1114131,{"idx":19,"name":"default-jak-03","tpage_name":"progress-minimap"}],[1114130,{"idx":18,"name":"default-jak-02","tpage_name":"progress-minimap"}],[1114129,{"idx":17,"name":"default-jak-01","tpage_name":"progress-minimap"}],[1114124,{"idx":12,"name":"city-04","tpage_name":"progress-minimap"}],[1114123,{"idx":11,"name":"city-03","tpage_name":"progress-minimap"}],[1114122,{"idx":10,"name":"city-02","tpage_name":"progress-minimap"}],[1114121,{"idx":9,"name":"city-01","tpage_name":"progress-minimap"}],[1114116,{"idx":4,"name":"big-map-icons","tpage_name":"progress-minimap"}],[1114113,{"idx":1,"name":"map-target-marker","tpage_name":"progress-minimap"}],[1114112,{"idx":0,"name":"hud-race-vehicle-01","tpage_name":"progress-minimap"}],[116916234,{"idx":10,"name":"sewcurved-door-06","tpage_name":"sewk-vis-pris"}],[99483714,{"idx":66,"name":"dp-bipedal-power-hose","tpage_name":"lformach-vis-pris"}],[106954794,{"idx":42,"name":"vola-rising-step-base","tpage_name":"volcanoa-vis-tfrag"}],[116916233,{"idx":9,"name":"sewcurved-door-05","tpage_name":"sewk-vis-pris"}],[99483713,{"idx":65,"name":"dp-bipedal-nose-01","tpage_name":"lformach-vis-pris"}],[106954793,{"idx":41,"name":"vola-cable","tpage_name":"volcanoa-vis-tfrag"}],[116916232,{"idx":8,"name":"sewcurved-door-04","tpage_name":"sewk-vis-pris"}],[99483712,{"idx":64,"name":"dp-bipedal-finger-plate-01","tpage_name":"lformach-vis-pris"}],[106954792,{"idx":40,"name":"vola-slide-metal","tpage_name":"volcanoa-vis-tfrag"}],[116916231,{"idx":7,"name":"sewcurved-door-01","tpage_name":"sewk-vis-pris"}],[99483711,{"idx":63,"name":"dp-bipedal-eye-01","tpage_name":"lformach-vis-pris"}],[116916230,{"idx":6,"name":"airlock-door-cog1","tpage_name":"sewk-vis-pris"}],[99483710,{"idx":62,"name":"dp-bipedal-dk-stomach-plate-01","tpage_name":"lformach-vis-pris"}],[106954790,{"idx":38,"name":"vola-grass-fringe-05-HI","tpage_name":"volcanoa-vis-tfrag"}],[116916228,{"idx":4,"name":"airlockl-door-metalframe","tpage_name":"sewk-vis-pris"}],[99483708,{"idx":60,"name":"dp-bipedal-dk-plate-04","tpage_name":"lformach-vis-pris"}],[116916227,{"idx":3,"name":"airlock-door-metal2","tpage_name":"sewk-vis-pris"}],[99483707,{"idx":59,"name":"dp-bipedal-dk-plate-03","tpage_name":"lformach-vis-pris"}],[116916226,{"idx":2,"name":"airlock-door-main","tpage_name":"sewk-vis-pris"}],[99483706,{"idx":58,"name":"dp-bipedal-dk-plate-02","tpage_name":"lformach-vis-pris"}],[106954786,{"idx":34,"name":"vola-rock-side-wall","tpage_name":"volcanoa-vis-tfrag"}],[116916225,{"idx":1,"name":"airlock-door-cog","tpage_name":"sewk-vis-pris"}],[99483705,{"idx":57,"name":"dp-bipedal-dk-plate-01","tpage_name":"lformach-vis-pris"}],[116916224,{"idx":0,"name":"airlock-door-bolt","tpage_name":"sewk-vis-pris"}],[99483704,{"idx":56,"name":"dp-bipedal-dk-hose-01","tpage_name":"lformach-vis-pris"}],[106954784,{"idx":32,"name":"vol-metal-01","tpage_name":"volcanoa-vis-tfrag"}],[116850690,{"idx":2,"name":"sewer-shrub-pitting-01","tpage_name":"sewk-vis-shrub"}],[99418170,{"idx":58,"name":"tpl-glider-metal02","tpage_name":"volcanox-pris"}],[111869970,{"idx":18,"name":"stadiumb-hud-ord-rd","tpage_name":"wasleapr-minimap"}],[116850689,{"idx":1,"name":"sewer-nut","tpage_name":"sewk-vis-shrub"}],[99418169,{"idx":57,"name":"tpl-glider-metal01","tpage_name":"volcanox-pris"}],[111869969,{"idx":17,"name":"stadiumb-hud-ord-o","tpage_name":"wasleapr-minimap"}],[116850688,{"idx":0,"name":"sewer-pipe-small-01","tpage_name":"sewk-vis-shrub"}],[99418168,{"idx":56,"name":"tpl-glider-grip01","tpage_name":"volcanox-pris"}],[111869968,{"idx":16,"name":"stadiumb-hud-ord-nd","tpage_name":"wasleapr-minimap"}],[115867650,{"idx":2,"name":"nst-spiderweb","tpage_name":"lnstcst-water"}],[115867649,{"idx":1,"name":"desert-nest-egg-piping","tpage_name":"lnstcst-water"}],[115867648,{"idx":0,"name":"sig-flatfangs","tpage_name":"lnstcst-water"}],[115802142,{"idx":30,"name":"vin-teeth-01","tpage_name":"lnstcst-pris2"}],[103350342,{"idx":70,"name":"jakchires-shoeteop","tpage_name":"comba-pris"}],[115802141,{"idx":29,"name":"sLine truncated
+98 -18
View File
@@ -3160,6 +3160,9 @@
[27, "a0", "process-focusable"],
[30, "a0", "process-focusable"]
],
"(method 20 enemy)": [
[[0, 30], "v0", "search-info-flag"]
],
"(method 59 enemy)": [
[57, "a0", "process-focusable"],
[60, "a0", "process-focusable"]
@@ -3191,8 +3194,20 @@
[93, "a1", "process-focusable"],
[140, "a1", "process-focusable"]
],
"(method 106 bot)": [
[[16, 31], "v1", "process-focusable"],
[[40, 58], "v1", "process-focusable"],
[[92, 95], "v1", "process-focusable"]
],
"(method 106 ashelin)": [
[[16, 21], "v1", "process-focusable"],
[[40, 57], "v1", "process-focusable"],
[[92, 95], "v1", "process-focusable"]
],
"(method 140 enemy)": [[18, "a1", "process-focusable"]],
"(method 142 enemy)": [[[0, 40], "v0", "knocked-type"]],
"get-penetrate-using-from-attack-event": [
[[20, 40], "v0", "penetrate"],
[2, "v1", "attack-info"],
[5, "v1", "attack-info"],
[25, "v1", "collide-shape"]
@@ -3202,6 +3217,9 @@
[67, "s3", "process-drawable"],
[68, "a1", "collide-shape"]
],
"(method 68 enemy)": [
[[0, 50], "v0", "enemy-aware"]
],
"(method 82 enemy)": [
[80, "v1", "process-drawable"],
[122, "v1", "attack-info"],
@@ -4910,14 +4928,8 @@
[96, "s5", "collide-shape-moving"]
],
"(anon-function 74 target-flut)": [
[6, "gp", "target"],
[10, "gp", "target"],
[16, "gp", "target"],
[24, "gp", "target"],
[33, "gp", "target"],
[42, "a0", "target"],
[49, "gp", "target"],
[56, "gp", "target"]
[[0, 56], "gp", "target"],
[42, "a0", "target"]
],
"(anon-function 21 target-flut)": [[58, "v1", "art-joint-anim"]],
"(code target-flut-death)": [
@@ -6605,8 +6617,7 @@
[40, "a0", "process-focusable"]
],
"(method 26 task-manager-temple-climb)": [
[126, "s5", "process-focusable"],
[130, "s5", "process-focusable"]
[[0, 148], "s5", "process-focusable"]
],
"(method 26 task-manager-desert-beast-battle)": [
[39, "a0", "process-focusable"]
@@ -9788,12 +9799,7 @@
[319, "a1", "ff-squad-control"]
],
"(method 252 crimson-guard)": [
[74, "s5", "process-focusable"],
[69, "s5", "process-focusable"],
[126, "s5", "process-focusable"],
[146, "s5", "process-focusable"],
[202, "s5", "process-focusable"],
[205, "s5", "process-focusable"]
[[0, 223], "s5", "process-focusable"]
],
"(method 51 ff-squad-control)": [
[13, "v1", "connection"],
@@ -10857,7 +10863,6 @@
["_stack_", 76, "float"],
["_stack_", 100, "float"]
],
"real-wang-texture-anim-func": [[[3, 31], "v1", "mood-context"]],
"(method 24 sky-work)": [
[256, "s4", "(pointer int32)"],
[261, "s4", "(pointer int32)"]
@@ -11266,5 +11271,80 @@
[[191, 249], "gp", "shadow-dcache"],
[96, "v1", "shadow-dcache"]
],
"real-fog-texture-anim-func": [[[6, 160], "s2", "(pointer uint32)"]]
"real-fog-texture-anim-func": [[[6, 160], "s2", "(pointer uint32)"]],
"(method 22 bigmap)": [
[22, "s3", "process-drawable"],
[[46, 49], "v1", "entity-actor"],
[58, "a0", "process-drawable"],
[65, "a0", "entity-actor"],
[42, "v1", "entity-actor"],
[55, "s3", "process-drawable"],
[[201, 243], "a1", "(inline-array vector4w)"]
],
"(method 20 bigmap)": [
[[3, 95], "s4", "(pointer uint32)"],
[99, "a2", "(pointer uint32)"],
[54, "a2", "(pointer uint32)"]
],
"(method 12 bigmap)": [
[85, "v1", "(pointer uint32)"],
[100, "v1", "(pointer uint32)"],
[[142, 145], "s0", "(pointer uint128)"],
["_stack_", 96, "(inline-array vector4w)"]
],
"(method 21 bigmap)": [[[10, 38], "v1", "(inline-array vector4w)"]],
"(method 19 blit-displays-work)": [
[764, "v1", "float"],
[759, "v1", "float"],
[[935, 954], "a1", "(inline-array vector4w)"],
[[857, 875], "a1", "(inline-array vector4w)"],
[[844, 847], "a0", "dma-gif-packet"],
[[921, 924], "v1", "dma-gif-packet"]
],
"(method 9 blit-displays-work)": [[[2, 36], "v1", "(inline-array vector4w)"]],
"(method 10 blit-displays-work)": [
[[2, 141], "v1", "(inline-array vector4w)"]
],
"(method 11 blit-displays-work)": [
[[2, 30], "v1", "(inline-array vector4w)"]
],
"(method 12 blit-displays-work)": [
[[4, 41], "v1", "(inline-array vector4w)"],
[[60, 112], "v1", "(inline-array vector4w)"]
],
"(method 13 blit-displays-work)": [
[[41, 44], "v1", "(inline-array vector4w)"],
[[53, 71], "a0", "(inline-array vector4w)"]
],
"(method 18 blit-displays-work)": [
[[28, 33], "v1", "dma-gif-packet"],
[[174, 177], "v1", "dma-gif-packet"],
[[186, 202], "a0", "(inline-array vector4w)"]
],
"draw-raw-image": [[[104, 154], "v1", "(inline-array vector4w)"]],
"draw-color-bars": [
[[11, 16], "v1", "dma-gif-packet"],
[[28, 54], "v1", "(inline-array vector4w)"]
],
"(method 20 blit-displays-work)": [
[[57, 89], "a3", "(inline-array vector4w)"],
[[102, 134], "t1", "(inline-array vector4w)"],
[[176, 209], "t1", "(inline-array vector4w)"],
[[310, 338], "t2", "(inline-array vector4w)"],
[[385, 422], "v1", "(inline-array vector4w)"]
],
"(method 14 blit-displays-work)": [
[[88, 91], "v1", "dma-gif-packet"],
[[100, 120], "a0", "(inline-array vector4w)"]
],
"(method 16 blit-displays-work)": [
[[35, 79], "s2", "(inline-array vector4w)"],
[[134, 178], "s2", "(inline-array vector4w)"]
],
"(method 15 blit-displays-work)": [
[[60, 63], "v1", "dma-gif-packet"],
[[81, 99], "a0", "(inline-array vector4w)"],
[[165, 190], "a0", "(inline-array vector4w)"]
],
"(event idle progress)": [[[10, 80], "v1", "mc-status-code"]]
}
@@ -173,12 +173,27 @@
"(method 9 process-tree)": {
"args": ["this", "active-tree", "name", "stack-pointer"]
},
"(method 9 align-control)": {
"vars": {
"s5-0":"num-chans",
"s4-0":"chan-idx",
"a0-4":"chan",
"v1-7":"frame-group",
"a0-9":"root-chan",
"v1-18":"root-frame-group",
"f0-0":"root-frame-num",
"a0-10":"disable?"
}
},
"(method 9 process)": {
"args": ["this", "active-tree", "name", "stack-pointer"]
},
"(method 10 process-tree)": {
"args": ["this", "ent"]
},
"(method 106 bot)": {
"vars": {"v1-3": ["v1-3", "process-focusable"]}
},
"(method 0 clock)": {
"args": ["allocation", "type-to-make", "index"]
},
@@ -1903,6 +1918,11 @@
"v1-8": "ii"
}
},
"(method 20 enemy)": {
"vars": {
"v0-0": ["flag", "search-info-flag"]
}
},
"(method 119 enemy)": {
"vars": {
"a1-5": ["cspec", "collide-spec"]
@@ -2135,5 +2155,14 @@
"vars": {
"v0-0": ["type", "assault-target-type"]
}
},
"(method 22 bigmap)": {
"vars": {
"a2-1": ["a2-1", "uint"],
"a3-0": ["a3-0", "uint"]
}
},
"set-font-color": {
"args": ["idx", "clr0", "clr1", "clr2", "clr3"]
}
}
+3 -4
View File
@@ -166,7 +166,7 @@ FullName extract_name(const std::string& file_info_name) {
name.name = name.name.substr(0, name.name.length() - 6);
int chunk_id = 0;
int place = 0;
for (int i = 2; i-- > 0;) {
for (int i = 3; i-- > 0;) {
char c = name.name.back();
if (c >= '0' && c <= '9') {
int val = (c - '0');
@@ -258,9 +258,8 @@ std::string StrFileReader::get_full_name(const std::string& short_name) const {
return result;
}
std::string StrFileReader::get_texture_name() const {
ASSERT(m_chunks.size() == 1);
const auto& chunk = m_chunks[0];
std::string StrFileReader::get_chunk_texture_name(int idx) const {
const auto& chunk = m_chunks[idx];
auto find_string = get_texture_page_file_info_string();
int offset;
if (find_string_in_data(chunk.data(), int(chunk.size()), find_string, &offset)) {
+3 -2
View File
@@ -22,7 +22,7 @@ class StrFileReader {
std::string get_chunk_art_name(int idx) const;
std::string get_full_name(const std::string& short_name) const;
std::string get_texture_name() const;
std::string get_chunk_texture_name(int idx) const;
private:
void init_jak1(const fs::path& file_path);
@@ -46,8 +46,9 @@ class StrFileReader {
std::string get_texture_page_file_info_string() const {
switch (m_version) {
case GameVersion::Jak2:
case GameVersion::Jak3:
return "/src/jak2/final/texture-page8/";
case GameVersion::Jak3:
return "/src/jak3/final/texture-page8/";
default:
ASSERT_MSG(false, "NYI get_file_info_string version");
break;
+6 -6
View File
@@ -454,7 +454,7 @@ std::string write_spool_subtitles(
bool has_spools = false;
for (auto& [spool_name, subs] : data) {
result += " \"" + spool_name + "\": {\n";
result += " \"scene\": true,\n";
// result += " \"scene\": true,\n";
result += " \"lines\": [\n";
bool has_subs = false;
for (auto& sub : subs) {
@@ -463,20 +463,20 @@ std::string write_spool_subtitles(
continue;
}
result += " {\n";
result += " \"end\": " + float_to_string(sub.end_frame) + ",\n";
result += " \"frame_end\": " + float_to_string(sub.end_frame) + ",\n";
result += " \"frame_start\": " + float_to_string(sub.start_frame) + ",\n";
if (dump_text) {
result += " \"merge\": false,\n";
} else {
result += " \"merge\": true,\n";
}
result += " \"offscreen\": false,\n";
result += " \"speaker\": \"none\",\n";
result += " \"start\": " + float_to_string(sub.start_frame) + ",\n";
if (dump_text) {
result += " \"text\": \"" + msg.text + "\"\n";
result += " \"text\": \"" + msg.text + "\",\n";
} else {
result += " \"text\": \"\"\n";
// result += " \"text\": \"\",\n";
}
result += " \"speaker\": \"none\"\n";
result += " },\n";
has_subs = true;
}
+6 -3
View File
@@ -164,13 +164,16 @@ AudioDir read_audio_dir(const decompiler::Config& config, const fs::path& path)
u64 data;
struct {
u64 name : 42;
bool stereo : 1;
bool international : 1;
u8 param : 4;
u64 stereo : 1;
u64 international : 1;
u64 param : 4;
u64 offset : 16;
};
};
};
static_assert(sizeof(DirEntryJak3) == sizeof(u64));
dir = reader.read<VagDirJak3>();
ASSERT(dir.id[0] == 0x41574756);
ASSERT(dir.id[1] == 0x52494444);
+1
View File
@@ -12,6 +12,7 @@
enum class ExtractorErrorCode {
SUCCESS = 0,
INVALID_CLI_INPUT = 3990,
INVALID_CLI_INPUT_MISSING_FOLDER = 3991,
VALIDATION_CANT_LOCATE_ELF = 4000,
VALIDATION_SERIAL_MISSING_FROM_DB = 4001,
VALIDATION_ELF_MISSING_FROM_DB = 4002,
+3 -3
View File
@@ -225,7 +225,7 @@ int main(int argc, char** argv) {
if (!project_path_override.empty()) {
if (!fs::exists(project_path_override)) {
lg::error("Error: project path override '{}' does not exist", project_path_override.string());
return static_cast<int>(ExtractorErrorCode::INVALID_CLI_INPUT);
return static_cast<int>(ExtractorErrorCode::INVALID_CLI_INPUT_MISSING_FOLDER);
}
auto ok = file_util::setup_project_path(project_path_override);
if (!ok) {
@@ -255,7 +255,7 @@ int main(int argc, char** argv) {
// - INPUT VALIDATION
if (!fs::exists(input_file_path)) {
lg::error("Error: input game file path '{}' does not exist", input_file_path.string());
return static_cast<int>(ExtractorErrorCode::INVALID_CLI_INPUT);
return static_cast<int>(ExtractorErrorCode::INVALID_CLI_INPUT_MISSING_FOLDER);
}
if (data_subfolders.count(game_name) == 0) {
lg::error("Error: input game name '{}' is not valid", game_name);
@@ -325,7 +325,7 @@ int main(int argc, char** argv) {
} else if (fs::is_directory(input_file_path)) {
if (!flag_folder) {
// if we didn't request a folder explicitly, but we got one, assume something went wrong.
lg::error("got a folder, but didn't get folder flag");
lg::error("got a folder, but didn't provide the folder flag");
return static_cast<int>(ExtractorErrorCode::INVALID_CLI_INPUT);
}
iso_data_path = input_file_path;
+22 -1
View File
@@ -1017,7 +1017,8 @@ void PrototypeBucketTie::read_from_file(TypedRef ref,
for (int i = 0; i < 4; i++) {
u32 start = index_start[i];
u32 end = start + frag_count[i];
ASSERT(num_color_qwcs <= end);
// precd tie has a bug where geo 3's
// ASSERT(num_color_qwcs <= end);
num_color_qwcs = std::max(end, num_color_qwcs);
}
@@ -1987,6 +1988,13 @@ void HFragment::read_from_file(TypedRef ref, const decompiler::DecompilerTypeSys
size = read_plain_data_field<u32>(ref, "size", dts);
}
void AdgifShaderArray::read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts) {
auto length = read_plain_data_field<s32>(ref, "length", dts);
adgifs.resize(length);
memcpy_plain_data((u8*)adgifs.data(), get_field_ref(ref, "data", dts),
sizeof(AdGifData) * length);
}
void BspHeader::read_from_file(const decompiler::LinkedObjectFile& file,
const decompiler::DecompilerTypeSystem& dts,
GameVersion version,
@@ -2001,6 +2009,19 @@ void BspHeader::read_from_file(const decompiler::LinkedObjectFile& file,
bsphere.read_from_file(get_field_ref(ref, "bsphere", dts));
name = read_symbol_field(ref, "name", dts);
if (version == GameVersion::Jak1) {
adgifs.read_from_file(get_and_check_ref_to_basic(ref, "adgifs", "adgif-shader-array", dts),
dts);
}
texture_page_count = read_plain_data_field<s32>(ref, "texture-page-count", dts);
if (texture_page_count > 0) {
auto tex_id_ptr = deref_label(get_field_ref(ref, "texture-ids", dts));
for (int i = 0; i < texture_page_count; i++) {
texture_ids.push_back(deref_u32(tex_id_ptr, i));
}
}
texture_remap_table.clear();
s32 tex_remap_len = read_plain_data_field<s32>(ref, "texture-remap-table-len", dts);
if (tex_remap_len > 0) {
+9
View File
@@ -840,6 +840,12 @@ struct DrawableTreeArray {
std::vector<std::unique_ptr<DrawableTree>> trees;
};
struct AdgifShaderArray {
std::vector<AdGifData> adgifs;
void read_from_file(TypedRef ref, const decompiler::DecompilerTypeSystem& dts);
};
// The "file info"
struct FileInfo {
std::string file_type;
@@ -884,7 +890,9 @@ struct BspHeader {
u16 texture_flags[kNumTextureFlags]; // jak 2 only
//
// (texture-ids (pointer texture-id) :offset-assert 60)
std::vector<u32> texture_ids;
// (texture-page-count int32 :offset-assert 64)
s32 texture_page_count;
//
// (unk-zero-0 basic :offset-assert 68)
//
@@ -907,6 +915,7 @@ struct BspHeader {
// (unk-data-4 float :offset-assert 160)
// (unk-data-5 float :offset-assert 164)
// (adgifs adgif-shader-array :offset-assert 168)
AdgifShaderArray adgifs;
// (actor-birth-order (pointer uint32) :offset-assert 172)
// (split-box-indices (pointer uint16) :offset-assert 176)
// (unk-data-8 uint32 55 :offset-assert 180)
@@ -19,4 +19,5 @@ void extract_collide_frags(const level_tools::CollideHash& chash,
const decompiler::DecompilerTypeSystem& dts,
tfrag3::Level& out);
void set_vertices_for_tri(tfrag3::CollisionMesh::Vertex* out, const math::Vector4f* in);
} // namespace decompiler
+23 -9
View File
@@ -112,10 +112,22 @@ void extract_art_groups_from_level(const ObjectFileDB& db,
std::map<std::string, level_tools::ArtData>& art_group_data) {
if (db.obj_files_by_dgo.count(dgo_name)) {
const auto& files = db.obj_files_by_dgo.at(dgo_name);
MercSwapInfo swapped_info;
// build list of models to replace
auto merc_replacements_path = file_util::get_jak_project_dir() / "custom_assets" /
game_version_names[db.version()] / "merc_replacements";
if (file_util::file_exists(merc_replacements_path.string())) {
auto custom_models =
file_util::find_files_in_dir(merc_replacements_path, std::regex(".*\\.glb"));
for (auto& mdl : custom_models) {
swapped_info.add_to_swap_list(mdl.stem().string());
}
}
for (const auto& file : files) {
if (file.name.length() > 3 && !file.name.compare(file.name.length() - 3, 3, "-ag")) {
const auto& ag_file = db.lookup_record(file);
extract_merc(ag_file, tex_db, db.dts, tex_remap, level_data, false, db.version());
extract_merc(ag_file, tex_db, db.dts, tex_remap, level_data, false, db.version(),
swapped_info);
extract_joint_group(ag_file, db.dts, db.version(), art_group_data);
}
}
@@ -279,20 +291,25 @@ void extract_common(const ObjectFileDB& db,
extract_art_groups_from_level(db, tex_db, {}, "ARTSPOOL", tfrag_level, art_group_data);
std::set<std::string> textures_we_have;
std::set<u32> textures_we_have_id;
// put _all_ index textures in common.
for (const auto& [id, tex] : tex_db.index_textures_by_combo_id) {
tfrag_level.index_textures.push_back(tex);
}
// remember which textures we already added.
// textures with the same name or the same ID always have the same data.
for (const auto& t : tfrag_level.textures) {
textures_we_have.insert(t.debug_name);
textures_we_have_id.insert(t.combo_id);
}
// for common textures, add if the ID isn't there - common textures are looked up by ID.
for (const auto& [id, normal_texture] : tex_db.textures) {
if (config.common_tpages.count(normal_texture.page) &&
!textures_we_have.count(normal_texture.name)) {
if (config.common_tpages.count(normal_texture.page) && !textures_we_have_id.count(id)) {
textures_we_have.insert(normal_texture.name);
textures_we_have_id.insert(id);
tfrag_level.textures.push_back(
make_texture(id, normal_texture, tex_db.tpage_names.at(normal_texture.page), true));
}
@@ -323,8 +340,7 @@ void extract_common(const ObjectFileDB& db,
if (config.rip_levels) {
auto file_path = file_util::get_jak_project_dir() / "glb_out" /
game_version_names[config.game_version] / "common.glb";
file_util::create_dir_if_needed_for_file(file_path);
game_version_names[config.game_version] / "common";
save_level_foreground_as_gltf(tfrag_level, art_group_data, file_path);
}
}
@@ -361,14 +377,12 @@ void extract_from_level(const ObjectFileDB& db,
if (config.rip_levels) {
auto back_file_path = file_util::get_jak_project_dir() / "glb_out" /
game_version_names[config.game_version] /
game_version_names[config.game_version] / level_data.level_name /
fmt::format("{}-background.glb", level_data.level_name);
file_util::create_dir_if_needed_for_file(back_file_path);
save_level_background_as_gltf(level_data, back_file_path);
auto fore_file_path = file_util::get_jak_project_dir() / "glb_out" /
game_version_names[config.game_version] /
fmt::format("{}-foreground.glb", level_data.level_name);
file_util::create_dir_if_needed_for_file(fore_file_path);
game_version_names[config.game_version] / level_data.level_name;
save_level_foreground_as_gltf(level_data, art_group_data, fore_file_path);
}
file_util::write_text_file(entities_folder / fmt::format("{}-actors.json", level_data.level_name),
@@ -10,6 +10,47 @@
namespace decompiler {
// info about what models have been replaced/added per level
struct MercSwapInfo {
std::vector<std::string> swap_list;
std::map<std::string, std::vector<std::string>> per_level_merc_swaps;
std::map<std::string, std::vector<std::string>> per_level_custom_mdls;
bool should_swap(const std::string& model) {
return std::find(swap_list.begin(), swap_list.end(), model) != swap_list.end();
}
bool already_swapped(const std::string& model, const std::string& level) {
auto mdls_it = per_level_merc_swaps.find(level);
if (mdls_it != per_level_merc_swaps.end()) {
auto& mdls = mdls_it->second;
auto mdl = std::find(mdls.begin(), mdls.end(), model);
return mdl != mdls.end();
}
return false;
}
bool already_added(const std::string& model, const std::string& level) {
auto mdls_it = per_level_custom_mdls.find(level);
if (mdls_it != per_level_custom_mdls.end()) {
auto& mdls = mdls_it->second;
auto mdl = std::find(mdls.begin(), mdls.end(), model);
return mdl != mdls.end();
}
return false;
}
void add_to_swap_list(const std::string& model) { swap_list.push_back(model); }
void add_to_swapped_list(const std::string& model, const std::string& level) {
per_level_merc_swaps[level].push_back(model);
}
void add_to_custom_list(const std::string& model, const std::string& level) {
per_level_custom_mdls[level].push_back(model);
}
};
// extract everything
void extract_all_levels(const ObjectFileDB& db,
const TextureDB& tex_db,
@@ -26,4 +67,7 @@ tfrag3::Texture make_texture(u32 id,
bool pool_load);
std::vector<level_tools::TextureRemap> extract_tex_remap(const ObjectFileDB& db,
const std::string& dgo_name);
std::optional<ObjectFileRecord> get_bsp_file(const std::vector<ObjectFileRecord>& records,
const std::string& dgo_name);
bool is_valid_bsp(const LinkedObjectFile& file);
} // namespace decompiler
+50 -28
View File
@@ -853,12 +853,19 @@ ConvertedMercEffect convert_merc_effect(const MercEffect& input_effect,
u32 tidx = (env >> 8) & 0b1111'1111'1111;
tex_combo = (((u32)tpage) << 16) | tidx;
} break;
case GameVersion::Jak2:
case GameVersion::Jak3: {
case GameVersion::Jak2: {
u32 tpage = 0x1f;
u32 tidx = 2;
tex_combo = (((u32)tpage) << 16) | tidx;
} break;
case GameVersion::Jak3: {
// (define *generic-envmap-texture* (get-texture pal-environment-front environment-generic))
// (defconstant environment-generic 2) tpage
// (def-tex pal-environment-front environment-generic 1) texture
u32 tpage = 2;
u32 tidx = 1;
tex_combo = (((u32)tpage) << 16) | tidx;
} break;
default:
ASSERT_NOT_REACHED();
}
@@ -1617,7 +1624,7 @@ void replace_model(tfrag3::Level& lvl, tfrag3::MercModel& model, const fs::path&
}
}
auto swap_info = load_replacement_merc_model(model.name, lvl.merc_data.indices.size(),
auto swap_info = load_replacement_merc_model(model, lvl.merc_data.indices.size(),
lvl.merc_data.vertices.size(), lvl.textures.size(),
mdl_path.string(), old_verts, false);
model = swap_info.new_model;
@@ -1640,8 +1647,8 @@ void add_custom_model_to_level(tfrag3::Level& lvl,
auto lvl_name = lvl.level_name == "" ? "common" : lvl.level_name;
lg::info("Adding custom model {} to {}", name, lvl_name);
auto merc_data =
load_replacement_merc_model(name, lvl.merc_data.indices.size(), lvl.merc_data.vertices.size(),
lvl.textures.size(), mdl_path.string(), {}, true);
load_custom_merc_model(name, lvl.merc_data.indices.size(), lvl.merc_data.vertices.size(),
lvl.textures.size(), mdl_path.string(), {}, true);
for (auto& idx : merc_data.new_indices) {
lvl.merc_data.indices.push_back(idx);
}
@@ -1662,7 +1669,8 @@ void extract_merc(const ObjectFileData& ag_data,
const std::vector<level_tools::TextureRemap>& map,
tfrag3::Level& out,
bool dump_level,
GameVersion version) {
GameVersion version,
MercSwapInfo& swapped_info) {
if (dump_level) {
file_util::create_dir_if_needed(file_util::get_file_path({"debug_out/merc"}));
}
@@ -1788,31 +1796,45 @@ void extract_merc(const ObjectFileData& ag_data,
}
}
// do model replacements if present
auto merc_replacement_folder = file_util::get_jak_project_dir() / "custom_assets" /
game_version_names[version] / "merc_replacements";
if (file_util::file_exists(merc_replacement_folder.string())) {
auto merc_replacements =
file_util::find_files_in_dir(merc_replacement_folder, std::regex(".*\\.glb"));
for (auto& path : merc_replacements) {
auto name = path.stem().string();
auto it = std::find_if(out.merc_data.models.begin(), out.merc_data.models.end(),
[&](const auto& m) { return m.name == name; });
if (it != out.merc_data.models.end()) {
auto& model = *it;
replace_model(out, model, path);
// do model replacement if present
for (auto& ctrl : ctrls) {
if (swapped_info.should_swap(ctrl.name)) {
auto merc_replacements_path = file_util::get_jak_project_dir() / "custom_assets" /
game_version_names[version] / "merc_replacements";
if (!swapped_info.already_swapped(ctrl.name, out.level_name)) {
if (file_util::file_exists(merc_replacements_path.string())) {
std::string file_name(ctrl.name + ".glb");
auto mdl_path = merc_replacements_path / file_name;
if (file_util::file_exists(mdl_path.string())) {
auto it = std::find_if(out.merc_data.models.begin(), out.merc_data.models.end(),
[&](const auto& m) { return m.name == ctrl.name; });
if (it != out.merc_data.models.end()) {
auto& model = *it;
replace_model(out, model, mdl_path);
swapped_info.add_to_swapped_list(ctrl.name, out.level_name);
}
}
} else {
lg::info("{} in level {} was already swapped, skipping", ctrl.name, out.level_name);
}
}
}
}
// add custom models if present
auto lvl_name = out.level_name == "" ? "common" : out.level_name;
auto models_folder = file_util::get_jak_project_dir() / "custom_assets" /
game_version_names[version] / "models" / lvl_name;
if (file_util::file_exists(models_folder.string())) {
auto custom_models = file_util::find_files_in_dir(models_folder, std::regex(".*\\.glb"));
for (auto& mdl : custom_models) {
add_custom_model_to_level(out, mdl.stem().string(), mdl);
// add custom models if present
auto lvl_name = out.level_name == "" ? "common" : out.level_name;
auto models_folder = file_util::get_jak_project_dir() / "custom_assets" /
game_version_names[version] / "models" / lvl_name;
if (file_util::file_exists(models_folder.string())) {
auto custom_models = file_util::find_files_in_dir(models_folder, std::regex(".*\\.glb"));
for (auto& mdl : custom_models) {
auto name = mdl.stem().string();
if (!swapped_info.already_added(name, lvl_name)) {
add_custom_model_to_level(out, name, mdl);
swapped_info.add_to_custom_list(name, lvl_name);
} else {
lg::info("custom model {} was already added to level {}, skipping", name, lvl_name);
}
}
}
}
}
+4 -1
View File
@@ -1,5 +1,7 @@
#pragma once
#include "extract_level.h"
#include "common/custom_data/Tfrag3Data.h"
#include "decompiler/ObjectFile/ObjectFileDB.h"
@@ -14,5 +16,6 @@ void extract_merc(const ObjectFileData& ag_data,
const std::vector<level_tools::TextureRemap>& map,
tfrag3::Level& out,
bool dump_level,
GameVersion version);
GameVersion version,
MercSwapInfo& swapped_info);
} // namespace decompiler
@@ -2032,6 +2032,20 @@ s32 find_or_add_texture_to_level(u32 combo_tex_id,
if (ok_to_miss) {
// we're missing a texture, just use the first one.
tex_it = tdb.textures.begin();
// some tfrags in jak 3 are missing textures, so we use some suitable
// replacements instead of the default eye texture
static std::map<std::string, std::string> per_level_tex_hacks = {
{"wasintro", "des-rock-01"},
{"intpfall", "common-black"},
{"powergd", "common-black"},
};
auto it = std::find_if(tdb.textures.begin(), tdb.textures.end(),
[&](const std::pair<u32, TextureDB::TextureData> val) {
return val.second.name == per_level_tex_hacks[level_name];
});
if (it != tdb.textures.end()) {
tex_it = it;
}
} else {
ASSERT_MSG(
false,
+20 -10
View File
@@ -2339,7 +2339,7 @@ TieCategoryInfo get_jak1_tie_category(u32 flags) {
return result;
}
u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb) {
s32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb) {
if (combo_tex == 0) {
// untextured
combo_tex = (((u32)TextureDB::kPlaceholderWhiteTexturePage) << 16) |
@@ -2348,7 +2348,7 @@ u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb)
// try looking it up in the existing textures that we have in the C++ renderer data.
// (this is shared with tfrag)
u32 idx_in_lev_data = UINT32_MAX;
s32 idx_in_lev_data = INT32_MAX;
for (u32 i = 0; i < lev.textures.size(); i++) {
if (lev.textures[i].combo_id == combo_tex) {
idx_in_lev_data = i;
@@ -2356,7 +2356,7 @@ u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb)
}
}
if (idx_in_lev_data == UINT32_MAX) {
if (idx_in_lev_data == INT32_MAX) {
// didn't find it, have to add a new one texture.
auto tex_it = tdb.textures.find(combo_tex);
if (tex_it == tdb.textures.end()) {
@@ -2378,14 +2378,20 @@ u32 get_or_add_texture(u32 combo_tex, tfrag3::Level& lev, const TextureDB& tdb)
new_tex.debug_tpage_name = tdb.tpage_names.at(tex_it->second.page);
new_tex.data = tex_it->second.rgba_bytes;
}
const auto& level_tex = lev.textures.at(idx_in_lev_data);
const auto& it = tdb.animated_tex_output_to_anim_slot.find(level_tex.debug_name);
if (it != tdb.animated_tex_output_to_anim_slot.end()) {
// lg::warn("TIE animated texture: {}", level_tex.debug_name);
return -int(it->second) - 1;
}
return idx_in_lev_data;
}
void handle_wind_draw_for_strip(
tfrag3::TieTree& tree,
std::unordered_map<u32, std::vector<u32>>& wind_draws_by_tex,
std::unordered_map<s32, std::vector<u32>>& wind_draws_by_tex,
const std::vector<std::vector<std::pair<int, int>>>& packed_vert_indices,
u32 idx_in_lev_data,
s32 idx_in_lev_data,
DrawMode mode,
const TieStrip& strip,
const TieInstanceInfo& inst,
@@ -2452,7 +2458,7 @@ void handle_wind_draw_for_strip(
}
void handle_draw_for_strip(tfrag3::TieTree& tree,
std::unordered_map<u32, std::vector<u32>>& static_draws_by_tex,
std::unordered_map<s32, std::vector<u32>>& static_draws_by_tex,
std::vector<tfrag3::StripDraw>& category_draws,
const std::vector<std::vector<std::pair<int, int>>>& packed_vert_indices,
DrawMode mode,
@@ -2542,8 +2548,8 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
GameVersion version) {
// our current approach for static draws is just to flatten to giant mesh, except for wind stuff.
// this map sorts these two types of draws by texture.
std::unordered_map<u32, std::vector<u32>> static_draws_by_tex;
std::unordered_map<u32, std::vector<u32>> wind_draws_by_tex;
std::unordered_map<s32, std::vector<u32>> static_draws_by_tex;
std::unordered_map<s32, std::vector<u32>> wind_draws_by_tex;
std::array<std::vector<tfrag3::StripDraw>, tfrag3::kNumTieCategories> draws_by_category;
@@ -2632,7 +2638,7 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
for (size_t strip_idx = 0; strip_idx < frag.strips.size(); strip_idx++) {
auto& strip = frag.strips[strip_idx];
u32 idx_in_lev_data = get_or_add_texture(strip.adgif.combo_tex, lev, tdb);
s32 idx_in_lev_data = get_or_add_texture(strip.adgif.combo_tex, lev, tdb);
// determine the draw mode
DrawMode mode = process_draw_mode(strip.adgif, frag.prog_info.misc_x == 0,
frag.has_magic_tex0_bit, version, info.category);
@@ -2649,7 +2655,7 @@ void add_vertices_and_static_draw(tfrag3::TieTree& tree,
draws_by_category.at((int)info.category), packed_vert_indices,
mode, idx_in_lev_data, strip, inst, ifrag, proto_idx, frag_idx,
strip_idx, matrix_idx);
u32 envmap_tex_idx =
s32 envmap_tex_idx =
get_or_add_texture(proto.envmap_adgif.value().combo_tex, lev, tdb);
// second pass envmap draw mode, in envmap bucket, envmap-specific draw list
@@ -2747,6 +2753,10 @@ void extract_tie(const level_tools::DrawableTreeInstanceTie* tree,
bool dump_level,
GameVersion version) {
for (int geo = 0; geo < GEOM_MAX; ++geo) {
// as far as I can tell, this one has bad colors
if (debug_name == "PRECD.DGO-2-tie" && geo == 3) {
continue;
}
tfrag3::TieTree this_tree;
// sanity check the vis tree (not a perfect check, but this is used in game and should be right)
+121 -118
View File
@@ -93,36 +93,33 @@ void unstrip_tie_wind(std::vector<u32>& unstripped,
}
/*!
* Convert merc strips. Doesn't assume anything about strips. Output is [model][effect][draw] format
* Convert merc strips. Doesn't assume anything about strips. Output is [effect][draw] format (done
* for each model)
*/
void unstrip_merc_draws(const std::vector<u32>& stripped_indices,
const std::vector<tfrag3::MercModel>& models,
const tfrag3::MercModel& model,
std::vector<u32>& unstripped,
std::vector<std::vector<std::vector<u32>>>& draw_to_start,
std::vector<std::vector<std::vector<u32>>>& draw_to_count) {
for (auto& model : models) {
auto& model_dts = draw_to_start.emplace_back();
auto& model_dtc = draw_to_count.emplace_back();
for (auto& effect : model.effects) {
auto& effect_dts = model_dts.emplace_back();
auto& effect_dtc = model_dtc.emplace_back();
for (auto& draw : effect.all_draws) {
effect_dts.push_back(unstripped.size());
std::vector<std::vector<u32>>& draw_to_start,
std::vector<std::vector<u32>>& draw_to_count) {
for (auto& effect : model.effects) {
auto& effect_dts = draw_to_start.emplace_back();
auto& effect_dtc = draw_to_count.emplace_back();
for (auto& draw : effect.all_draws) {
effect_dts.push_back(unstripped.size());
for (size_t i = 2; i < draw.index_count; i++) {
int idx = i + draw.first_index;
u32 a = stripped_indices[idx];
u32 b = stripped_indices[idx - 1];
u32 c = stripped_indices[idx - 2];
if (a == UINT32_MAX || b == UINT32_MAX || c == UINT32_MAX) {
continue;
}
unstripped.push_back(a);
unstripped.push_back(b);
unstripped.push_back(c);
for (size_t i = 2; i < draw.index_count; i++) {
int idx = i + draw.first_index;
u32 a = stripped_indices[idx];
u32 b = stripped_indices[idx - 1];
u32 c = stripped_indices[idx - 2];
if (a == UINT32_MAX || b == UINT32_MAX || c == UINT32_MAX) {
continue;
}
effect_dtc.push_back(unstripped.size() - effect_dts.back());
unstripped.push_back(a);
unstripped.push_back(b);
unstripped.push_back(c);
}
effect_dtc.push_back(unstripped.size() - effect_dts.back());
}
}
}
@@ -485,12 +482,12 @@ int make_shrub_index_buffer_view(const std::vector<u32>& indices,
}
int make_merc_index_buffer_view(const std::vector<u32>& indices,
const std::vector<tfrag3::MercModel>& models,
const tfrag3::MercModel& mmodel,
tinygltf::Model& model,
std::vector<std::vector<std::vector<u32>>>& draw_to_start,
std::vector<std::vector<std::vector<u32>>>& draw_to_count) {
std::vector<std::vector<u32>>& draw_to_start,
std::vector<std::vector<u32>>& draw_to_count) {
std::vector<u32> unstripped;
unstrip_merc_draws(indices, models, unstripped, draw_to_start, draw_to_count);
unstrip_merc_draws(indices, mmodel, unstripped, draw_to_start, draw_to_count);
// first create a buffer:
int buffer_idx = (int)model.buffers.size();
@@ -884,6 +881,7 @@ int make_inv_matrix_bind_poses(const std::vector<level_tools::Joint>& joints,
void add_merc(const tfrag3::Level& level,
const std::map<std::string, level_tools::ArtData>& art_data,
const tfrag3::MercModel& mmodel,
tinygltf::Model& model,
std::unordered_map<int, int>& tex_image_map) {
const auto& mverts = level.merc_data.vertices;
@@ -892,92 +890,89 @@ void add_merc(const tfrag3::Level& level,
int position_buffer_accessor = make_position_buffer_accessor(mverts, model);
int texture_buffer_accessor = make_tex_buffer_accessor(mverts, model, 1.f);
std::vector<std::vector<std::vector<u32>>> draw_to_start, draw_to_count;
int index_buffer_view = make_merc_index_buffer_view(
level.merc_data.indices, level.merc_data.models, model, draw_to_start, draw_to_count);
std::vector<std::vector<u32>> draw_to_start, draw_to_count;
int index_buffer_view = make_merc_index_buffer_view(level.merc_data.indices, mmodel, model,
draw_to_start, draw_to_count);
int colors = make_color_buffer_accessor(mverts, model);
auto joints_accessor = make_bones_accessor(mverts, model);
auto weights_accessor = make_weights_accessor(mverts, model);
for (size_t model_idx = 0; model_idx < level.merc_data.models.size(); model_idx++) {
const auto& mmodel = level.merc_data.models[model_idx];
const auto& art = art_data.find(mmodel.name);
int node_idx = (int)model.nodes.size();
auto& node = model.nodes.emplace_back();
model.scenes.at(0).nodes.push_back(node_idx);
node.name = mmodel.name;
int mesh_idx = (int)model.meshes.size();
auto& mesh = model.meshes.emplace_back();
mesh.name = node.name;
node.mesh = mesh_idx;
const auto& art = art_data.find(mmodel.name);
int node_idx = (int)model.nodes.size();
auto& node = model.nodes.emplace_back();
model.scenes.at(0).nodes.push_back(node_idx);
node.name = mmodel.name;
int mesh_idx = (int)model.meshes.size();
auto& mesh = model.meshes.emplace_back();
mesh.name = node.name;
node.mesh = mesh_idx;
if (art != art_data.end() && !art->second.joint_group.empty()) {
node.skin = model.skins.size();
auto& skin = model.skins.emplace_back();
const auto& game_bones = art->second.joint_group;
int n_bones = game_bones.size();
std::vector<std::vector<int>> children(n_bones);
for (size_t i = 0; i < game_bones.size(); i++) {
if (game_bones[i].parent_idx >= 0) {
children.at(game_bones[i].parent_idx).push_back(i);
}
if (art != art_data.end() && !art->second.joint_group.empty()) {
node.skin = model.skins.size();
auto& skin = model.skins.emplace_back();
const auto& game_bones = art->second.joint_group;
int n_bones = game_bones.size();
std::vector<std::vector<int>> children(n_bones);
for (size_t i = 0; i < game_bones.size(); i++) {
if (game_bones[i].parent_idx >= 0) {
children.at(game_bones[i].parent_idx).push_back(i);
}
skin.skeleton = model.nodes.size();
for (int i = 0; i < n_bones; i++) {
const auto& gbone = game_bones[i];
skin.joints.push_back(skin.skeleton + i);
auto& snode = model.nodes.emplace_back();
snode.name = gbone.name;
}
skin.skeleton = model.nodes.size();
for (int i = 0; i < n_bones; i++) {
const auto& gbone = game_bones[i];
skin.joints.push_back(skin.skeleton + i);
auto& snode = model.nodes.emplace_back();
snode.name = gbone.name;
// bind pose is bind_T_w
// for glb we want bind_parent_T_bind_child
// so bindp_T_w * inverse(bindc_T_w)
math::Matrix4f matrix;
if (gbone.parent_idx >= 0) {
matrix = unscale_translation(game_bones.at(gbone.parent_idx).bind_pose_T_w) *
inverse(unscale_translation(gbone.bind_pose_T_w));
} else {
// I think this value is ignored anyway.
for (int r = 0; r < 4; r++) {
for (int c = 0; c < 4; c++) {
matrix(r, c) = (r == c) ? 1 : 0;
}
}
}
// bind pose is bind_T_w
// for glb we want bind_parent_T_bind_child
// so bindp_T_w * inverse(bindc_T_w)
math::Matrix4f matrix;
if (gbone.parent_idx >= 0) {
matrix = unscale_translation(game_bones.at(gbone.parent_idx).bind_pose_T_w) *
inverse(unscale_translation(gbone.bind_pose_T_w));
} else {
// I think this value is ignored anyway.
for (int r = 0; r < 4; r++) {
for (int c = 0; c < 4; c++) {
snode.matrix.push_back(matrix(c, r));
matrix(r, c) = (r == c) ? 1 : 0;
}
}
for (auto child : children.at(i)) {
snode.children.push_back(skin.skeleton + child);
}
for (int r = 0; r < 4; r++) {
for (int c = 0; c < 4; c++) {
snode.matrix.push_back(matrix(c, r));
}
}
ASSERT(skin.skeleton + n_bones == (int)model.nodes.size());
skin.inverseBindMatrices = make_inv_matrix_bind_poses(game_bones, model);
}
for (size_t effect_idx = 0; effect_idx < mmodel.effects.size(); effect_idx++) {
const auto& effect = mmodel.effects[effect_idx];
for (size_t draw_idx = 0; draw_idx < effect.all_draws.size(); draw_idx++) {
const auto& draw = effect.all_draws[draw_idx];
auto& prim = mesh.primitives.emplace_back();
prim.material =
add_material_for_tex(level, model, draw.tree_tex_id, tex_image_map, draw.mode);
prim.indices = make_index_buffer_accessor(
model, draw_to_start[model_idx][effect_idx][draw_idx],
draw_to_count[model_idx][effect_idx][draw_idx], index_buffer_view);
prim.attributes["POSITION"] = position_buffer_accessor;
prim.attributes["TEXCOORD_0"] = texture_buffer_accessor;
prim.attributes["COLOR_0"] = colors;
prim.attributes["JOINTS_0"] = joints_accessor;
prim.attributes["WEIGHTS_0"] = weights_accessor;
prim.mode = TINYGLTF_MODE_TRIANGLES;
for (auto child : children.at(i)) {
snode.children.push_back(skin.skeleton + child);
}
}
ASSERT(skin.skeleton + n_bones == (int)model.nodes.size());
skin.inverseBindMatrices = make_inv_matrix_bind_poses(game_bones, model);
}
for (size_t effect_idx = 0; effect_idx < mmodel.effects.size(); effect_idx++) {
const auto& effect = mmodel.effects[effect_idx];
for (size_t draw_idx = 0; draw_idx < effect.all_draws.size(); draw_idx++) {
const auto& draw = effect.all_draws[draw_idx];
auto& prim = mesh.primitives.emplace_back();
prim.material =
add_material_for_tex(level, model, draw.tree_tex_id, tex_image_map, draw.mode);
prim.indices =
make_index_buffer_accessor(model, draw_to_start[effect_idx][draw_idx],
draw_to_count[effect_idx][draw_idx], index_buffer_view);
prim.attributes["POSITION"] = position_buffer_accessor;
prim.attributes["TEXCOORD_0"] = texture_buffer_accessor;
prim.attributes["COLOR_0"] = colors;
prim.attributes["JOINTS_0"] = joints_accessor;
prim.attributes["WEIGHTS_0"] = weights_accessor;
prim.mode = TINYGLTF_MODE_TRIANGLES;
}
}
}
} // namespace
@@ -1026,30 +1021,38 @@ void save_level_background_as_gltf(const tfrag3::Level& level, const fs::path& g
void save_level_foreground_as_gltf(const tfrag3::Level& level,
const std::map<std::string, level_tools::ArtData>& art_data,
const fs::path& glb_file) {
// the top level container for everything is the model.
tinygltf::Model model;
const fs::path& glb_path) {
for (size_t model_idx = 0; model_idx < level.merc_data.models.size(); model_idx++) {
const auto& mmodel = level.merc_data.models[model_idx];
// a "scene" is a traditional scene graph, made up of Nodes.
// sadly, attempting to nest stuff makes the blender importer unhappy, so we just dump
// everything into the top level.
model.scenes.emplace_back();
// the top level container for everything is the model.
tinygltf::Model model;
// hack, add a default material.
tinygltf::Material mat;
mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 0.9f, 0.9f, 1.0f};
mat.doubleSided = true;
model.materials.push_back(mat);
// a "scene" is a traditional scene graph, made up of Nodes.
// sadly, attempting to nest stuff makes the blender importer unhappy, so we just dump
// everything into the top level.
model.scenes.emplace_back();
std::unordered_map<int, int> tex_image_map;
// hack, add a default material.
tinygltf::Material mat;
mat.pbrMetallicRoughness.baseColorFactor = {1.0f, 0.9f, 0.9f, 1.0f};
mat.doubleSided = true;
model.materials.push_back(mat);
add_merc(level, art_data, model, tex_image_map);
std::unordered_map<int, int> tex_image_map;
model.asset.generator = "opengoal";
tinygltf::TinyGLTF gltf;
gltf.WriteGltfSceneToFile(&model, glb_file.string(),
true, // embedImages
true, // embedBuffers
true, // pretty print
true); // write binary
add_merc(level, art_data, mmodel, model, tex_image_map);
model.asset.generator = "opengoal";
auto glb_file = glb_path / fmt::format("{}.glb", mmodel.name);
file_util::create_dir_if_needed_for_file(glb_file);
tinygltf::TinyGLTF gltf;
gltf.WriteGltfSceneToFile(&model, glb_file.string(),
true, // embedImages
true, // embedBuffers
true, // pretty print
true); // write binary
}
}
+1 -1
View File
@@ -13,4 +13,4 @@
void save_level_background_as_gltf(const tfrag3::Level& level, const fs::path& glb_file);
void save_level_foreground_as_gltf(const tfrag3::Level& level,
const std::map<std::string, level_tools::ArtData>& art_data,
const fs::path& glb_file);
const fs::path& glb_path);
+259 -52
View File
@@ -3,18 +3,27 @@
using namespace gltf_util;
namespace decompiler {
void extract(const std::string& name,
void extract(tfrag3::MercModel& mdl,
MercExtractData& out,
const tinygltf::Model& model,
const std::vector<NodeWithTransform>& all_nodes,
u32 index_offset,
u32 vertex_offset,
u32 tex_offset) {
u32 tex_offset,
bool& has_custom_weights) {
ASSERT(out.new_vertices.empty());
std::map<int, tfrag3::MercDraw> draw_by_material;
int mesh_count = 0;
int prim_count = 0;
int joints = 3;
auto skin_idx = find_single_skin(model, all_nodes);
if (skin_idx) {
joints += get_joint_count(model, *skin_idx);
}
bool copy_eye_draws = false;
bool copy_mod_draws = false;
for (const auto& n : all_nodes) {
const auto& node = model.nodes[n.node_idx];
@@ -24,6 +33,12 @@ void extract(const std::string& name,
if (node.mesh >= 0) {
const auto& mesh = model.meshes[node.mesh];
mesh_count++;
has_custom_weights = node.extras.Has("enable_custom_weights") &&
node.extras.Get("enable_custom_weights").Get<int>();
copy_eye_draws =
node.extras.Has("copy_eye_draws") && node.extras.Get("copy_eye_draws").Get<int>();
copy_mod_draws =
node.extras.Has("copy_mod_draws") && node.extras.Get("copy_mod_draws").Get<int>();
for (const auto& prim : mesh.primitives) {
prim_count++;
// extract index buffer
@@ -39,6 +54,21 @@ void extract(const std::string& name,
out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end());
ASSERT(out.new_colors.size() == out.new_vertices.size());
if (prim.attributes.count("JOINTS_0") && prim.attributes.count("WEIGHTS_0")) {
auto joints_and_weights = gltf_util::extract_and_flatten_joints_and_weights(model, prim);
ASSERT(joints_and_weights.size() == verts.vtx.size());
out.joints_and_weights.insert(out.joints_and_weights.end(), joints_and_weights.begin(),
joints_and_weights.end());
} else {
// add fake data for vertices without this data
gltf_util::JointsAndWeights dummy;
dummy.joints[0] = 3;
dummy.weights[0] = 1.f;
for (size_t i = 0; i < out.new_vertices.size(); i++) {
out.joints_and_weights.push_back(dummy);
}
}
// TODO: just putting it all in one material
auto& draw = draw_by_material[prim.material];
draw.mode = gltf_util::make_default_draw_mode(); // todo rm
@@ -54,42 +84,176 @@ void extract(const std::string& name,
}
tfrag3::MercEffect e;
out.new_model.name = name;
out.new_model.max_bones = 120;
out.new_model.max_draws = 200;
tfrag3::MercEffect envmap_eff;
envmap_eff.has_envmap = false;
out.new_model.name = mdl.name;
// if we have a skeleton, use that joint count, otherwise use a high default value since the model
// we replace can have more
out.new_model.max_bones = joints != 3 ? joints : 100;
out.new_model.max_draws = 0;
for (const auto& [mat_idx, d_] : draw_by_material) {
e.all_draws.push_back(d_);
auto& draw = e.all_draws.back();
draw.mode = make_default_draw_mode();
if (mat_idx == -1) {
lg::warn("Draw had a material index of -1, using default texture.");
draw.tree_tex_id = 0;
continue;
}
const auto& mat = model.materials[mat_idx];
int tex_idx = mat.pbrMetallicRoughness.baseColorTexture.index;
if (tex_idx == -1) {
lg::warn("Material {} has no texture, using default texture.", mat.name);
draw.tree_tex_id = 0;
if (mat_idx < 0 || !gltf_util::material_has_envmap(model.materials[mat_idx]) ||
!gltf_util::envmap_is_valid(model.materials[mat_idx])) {
gltf_util::process_normal_merc_draw(model, out, tex_offset, e, mat_idx, d_);
} else {
envmap_eff.has_envmap = true;
gltf_util::process_envmap_merc_draw(model, out, tex_offset, envmap_eff, mat_idx, d_);
}
}
// in case a model only has envmap draws, we don't push the normal merc effect
if (!e.all_draws.empty()) {
out.new_model.effects.push_back(e);
}
if (envmap_eff.has_envmap) {
out.new_model.effects.push_back(envmap_eff);
}
// copy any effects from the old model that used mod or eye draws
if (copy_eye_draws || copy_mod_draws) {
for (auto& old_eff : mdl.effects) {
tfrag3::MercEffect eff;
bool has_eye_draw = false;
if (copy_eye_draws) {
for (auto& draw : old_eff.all_draws) {
if (draw.eye_id != 0xff) {
has_eye_draw = true;
eff.all_draws.push_back(draw);
}
}
}
if (copy_mod_draws && old_eff.has_mod_draw) {
eff.has_mod_draw = true;
eff.mod = old_eff.mod;
eff.mod.fix_draw.clear();
}
if ((copy_eye_draws || copy_mod_draws) && (eff.has_mod_draw || has_eye_draw)) {
lg::info("adding old effect for {} (mod draw {}, eye draw {})", mdl.name,
old_eff.has_mod_draw, has_eye_draw);
out.new_model.effects.push_back(eff);
}
}
}
for (auto& effect : out.new_model.effects) {
out.new_model.max_draws += effect.all_draws.size();
}
lg::info("total of {} unique materials ({} normal, {} envmap)", out.new_model.max_draws,
e.all_draws.size(), envmap_eff.all_draws.size());
lg::info("Merged {} meshes and {} prims into {} vertices", mesh_count, prim_count,
out.new_vertices.size());
}
void extract(const std::string& name,
MercExtractData& out,
const tinygltf::Model& model,
const std::vector<NodeWithTransform>& all_nodes,
u32 index_offset,
u32 vertex_offset,
u32 tex_offset,
bool& has_custom_weights) {
ASSERT(out.new_vertices.empty());
std::map<int, tfrag3::MercDraw> draw_by_material;
int mesh_count = 0;
int prim_count = 0;
int joints = 3;
auto skin_idx = find_single_skin(model, all_nodes);
if (skin_idx) {
joints += get_joint_count(model, *skin_idx);
}
for (const auto& n : all_nodes) {
const auto& node = model.nodes[n.node_idx];
if (node.extras.Has("set_invisible") && node.extras.Get("set_invisible").Get<int>()) {
continue;
}
if (node.mesh >= 0) {
const auto& mesh = model.meshes[node.mesh];
mesh_count++;
has_custom_weights = node.extras.Has("enable_custom_weights") &&
node.extras.Get("enable_custom_weights").Get<int>();
for (const auto& prim : mesh.primitives) {
prim_count++;
// extract index buffer
std::vector<u32> prim_indices = gltf_util::gltf_index_buffer(
model, prim.indices, out.new_vertices.size() + vertex_offset);
ASSERT_MSG(prim.mode == TINYGLTF_MODE_TRIANGLES, "Unsupported triangle mode");
// extract vertices
auto verts =
gltf_util::gltf_vertices(model, prim.attributes, n.w_T_node, true, true, mesh.name);
out.new_vertices.insert(out.new_vertices.end(), verts.vtx.begin(), verts.vtx.end());
out.new_colors.insert(out.new_colors.end(), verts.vtx_colors.begin(),
verts.vtx_colors.end());
out.normals.insert(out.normals.end(), verts.normals.begin(), verts.normals.end());
ASSERT(out.new_colors.size() == out.new_vertices.size());
const auto& tex = model.textures[tex_idx];
ASSERT(tex.sampler >= 0);
ASSERT(tex.source >= 0);
draw.mode = draw_mode_from_sampler(model.samplers.at(tex.sampler));
if (prim.attributes.count("JOINTS_0") && prim.attributes.count("WEIGHTS_0")) {
auto joints_and_weights = gltf_util::extract_and_flatten_joints_and_weights(model, prim);
ASSERT(joints_and_weights.size() == verts.vtx.size());
out.joints_and_weights.insert(out.joints_and_weights.end(), joints_and_weights.begin(),
joints_and_weights.end());
} else {
// add fake data for vertices without this data
gltf_util::JointsAndWeights dummy;
dummy.joints[0] = 3;
dummy.weights[0] = 1.f;
for (size_t i = 0; i < out.new_vertices.size(); i++) {
out.joints_and_weights.push_back(dummy);
}
}
const auto& img = model.images[tex.source];
draw.tree_tex_id = tex_offset + texture_pool_add_texture(&out.tex_pool, img);
// TODO: just putting it all in one material
auto& draw = draw_by_material[prim.material];
draw.mode = gltf_util::make_default_draw_mode(); // todo rm
draw.tree_tex_id = 0; // todo rm
draw.num_triangles += prim_indices.size() / 3;
draw.no_strip = true;
draw.index_count = prim_indices.size();
draw.first_index = index_offset + out.new_indices.size();
out.new_indices.insert(out.new_indices.end(), prim_indices.begin(), prim_indices.end());
}
}
}
lg::info("total of {} unique materials", e.all_draws.size());
e.has_mod_draw = false;
out.new_model.effects.push_back(e);
out.new_model.effects.push_back(e);
out.new_model.effects.push_back(e);
out.new_model.effects.push_back(e);
tfrag3::MercEffect e;
tfrag3::MercEffect envmap_eff;
envmap_eff.has_envmap = false;
out.new_model.name = name;
// if we have a skeleton, use that joint count, otherwise use a high default value since the model
// we replace can have more
out.new_model.max_bones = joints != 3 ? joints : 100;
out.new_model.max_draws = 0;
for (const auto& [mat_idx, d_] : draw_by_material) {
const auto& mat = model.materials[mat_idx];
if (mat_idx < 0 || !gltf_util::material_has_envmap(model.materials[mat_idx]) ||
!gltf_util::envmap_is_valid(model.materials[mat_idx])) {
gltf_util::process_normal_merc_draw(model, out, tex_offset, e, mat_idx, d_);
} else {
envmap_eff.has_envmap = true;
gltf_util::process_envmap_merc_draw(model, out, tex_offset, envmap_eff, mat_idx, d_);
}
}
// in case a model only has envmap draws, we don't push the normal merc effect
if (!e.all_draws.empty()) {
out.new_model.effects.push_back(e);
}
if (envmap_eff.has_envmap) {
out.new_model.effects.push_back(envmap_eff);
}
for (auto& effect : out.new_model.effects) {
out.new_model.max_draws += effect.all_draws.size();
}
lg::info("total of {} unique materials ({} normal, {} envmap)", out.new_model.max_draws,
e.all_draws.size(), envmap_eff.all_draws.size());
lg::info("Merged {} meshes and {} prims into {} vertices", mesh_count, prim_count,
out.new_vertices.size());
}
@@ -99,9 +263,9 @@ const tfrag3::MercVertex& find_closest(const std::vector<tfrag3::MercVertex>& ol
float y,
float z) {
float best_dist = 1e10;
int best_idx = 0;
size_t best_idx = 0;
for (int i = 0; i < old.size(); i++) {
for (size_t i = 0; i < old.size(); i++) {
auto& v = old[i];
float dx = v.pos[0] - x;
float dy = v.pos[1] - y;
@@ -118,7 +282,8 @@ const tfrag3::MercVertex& find_closest(const std::vector<tfrag3::MercVertex>& ol
void merc_convert_replacement(MercSwapData& out,
const MercExtractData& in,
const std::vector<tfrag3::MercVertex>& old_verts) {
const std::vector<tfrag3::MercVertex>& old_verts,
bool use_custom_weights) {
out.new_model = in.new_model;
out.new_indices = in.new_indices;
out.new_textures = in.tex_pool.textures_by_idx;
@@ -126,26 +291,36 @@ void merc_convert_replacement(MercSwapData& out,
// convert vertices
for (size_t i = 0; i < in.new_vertices.size(); i++) {
const auto& y = in.new_vertices[i];
const auto& copy_from = find_closest(old_verts, y.x, y.y, y.z);
auto& x = out.new_vertices.emplace_back();
x.pos[0] = y.x;
x.pos[1] = y.y;
x.pos[2] = y.z;
x.normal[0] = copy_from.normal[0];
x.normal[1] = copy_from.normal[1];
x.normal[2] = copy_from.normal[2];
x.weights[0] = copy_from.weights[0];
x.weights[1] = copy_from.weights[1];
x.weights[2] = copy_from.weights[2];
x.normal[0] = in.normals.at(i).x();
x.normal[1] = in.normals.at(i).y();
x.normal[2] = in.normals.at(i).z();
if (use_custom_weights) {
x.weights[0] = in.joints_and_weights.at(i).weights[0];
x.weights[1] = in.joints_and_weights.at(i).weights[1];
x.weights[2] = in.joints_and_weights.at(i).weights[2];
x.mats[0] = in.joints_and_weights.at(i).joints[0];
x.mats[1] = in.joints_and_weights.at(i).joints[1];
x.mats[2] = in.joints_and_weights.at(i).joints[2];
} else {
x.weights[0] = copy_from.weights[0];
x.weights[1] = copy_from.weights[1];
x.weights[2] = copy_from.weights[2];
x.mats[0] = copy_from.mats[0];
x.mats[1] = copy_from.mats[1];
x.mats[2] = copy_from.mats[2];
}
x.st[0] = y.s;
x.st[1] = y.t;
x.rgba[0] = in.new_colors[i][0];
x.rgba[1] = in.new_colors[i][1];
x.rgba[2] = in.new_colors[i][2];
x.rgba[3] = in.new_colors[i][3];
x.mats[0] = copy_from.mats[0];
x.mats[1] = copy_from.mats[1];
x.mats[2] = copy_from.mats[2];
}
}
@@ -164,22 +339,22 @@ void merc_convert_custom(MercSwapData& out, const MercExtractData& in) {
x.normal[0] = in.normals.at(i).x();
x.normal[1] = in.normals.at(i).y();
x.normal[2] = in.normals.at(i).z();
x.weights[0] = 1.0f;
x.weights[1] = 0.0f;
x.weights[2] = 0.0f;
x.weights[0] = in.joints_and_weights.at(i).weights[0];
x.weights[1] = in.joints_and_weights.at(i).weights[1];
x.weights[2] = in.joints_and_weights.at(i).weights[2];
x.st[0] = y.s;
x.st[1] = y.t;
x.rgba[0] = in.new_colors[i][0];
x.rgba[1] = in.new_colors[i][1];
x.rgba[2] = in.new_colors[i][2];
x.rgba[3] = in.new_colors[i][3];
x.mats[0] = 3;
x.mats[1] = 0;
x.mats[2] = 0;
x.mats[0] = in.joints_and_weights.at(i).joints[0];
x.mats[1] = in.joints_and_weights.at(i).joints[1];
x.mats[2] = in.joints_and_weights.at(i).joints[2];
}
}
MercSwapData load_replacement_merc_model(const std::string& name,
MercSwapData load_replacement_merc_model(tfrag3::MercModel& mdl,
u32 current_idx_count,
u32 current_vtx_count,
u32 current_tex_count,
@@ -198,12 +373,44 @@ MercSwapData load_replacement_merc_model(const std::string& name,
auto all_nodes = flatten_nodes_from_all_scenes(model);
MercExtractData extract_data;
extract(name, extract_data, model, all_nodes, current_idx_count, current_vtx_count,
current_tex_count);
auto has_custom_weights = false;
extract(mdl, extract_data, model, all_nodes, current_idx_count, current_vtx_count,
current_tex_count, has_custom_weights);
if (custom_mdl) {
merc_convert_custom(result, extract_data);
} else {
merc_convert_replacement(result, extract_data, old_verts);
merc_convert_replacement(result, extract_data, old_verts, has_custom_weights);
}
return result;
}
MercSwapData load_custom_merc_model(const std::string& name,
u32 current_idx_count,
u32 current_vtx_count,
u32 current_tex_count,
const std::string& path,
const std::vector<tfrag3::MercVertex>& old_verts,
bool custom_mdl) {
MercSwapData result;
lg::info("Reading gltf mesh: {}", path);
tinygltf::TinyGLTF loader;
tinygltf::Model model;
std::string err, warn;
bool res = loader.LoadBinaryFromFile(&model, &err, &warn, path);
ASSERT_MSG(warn.empty(), warn.c_str());
ASSERT_MSG(err.empty(), err.c_str());
ASSERT_MSG(res, "Failed to load GLTF file!");
auto all_nodes = flatten_nodes_from_all_scenes(model);
MercExtractData extract_data;
auto has_custom_weights = false;
extract(name, extract_data, model, all_nodes, current_idx_count, current_vtx_count,
current_tex_count, has_custom_weights);
if (custom_mdl) {
merc_convert_custom(result, extract_data);
} else {
merc_convert_replacement(result, extract_data, old_verts, has_custom_weights);
}
return result;
+15 -23
View File
@@ -4,29 +4,21 @@
#include "common/util/gltf_util.h"
namespace decompiler {
struct MercExtractData {
gltf_util::TexturePool tex_pool;
std::vector<u32> new_indices;
std::vector<tfrag3::PreloadedVertex> new_vertices;
std::vector<math::Vector<u8, 4>> new_colors;
std::vector<math::Vector3f> normals;
tfrag3::MercModel new_model;
};
gltf_util::MercSwapData load_replacement_merc_model(
tfrag3::MercModel& mdl,
u32 current_idx_count,
u32 current_vtx_count,
u32 current_tex_count,
const std::string& path,
const std::vector<tfrag3::MercVertex>& old_verts,
bool custom_mdl);
// Data produced by loading a replacement model
struct MercSwapData {
std::vector<u32> new_indices;
std::vector<tfrag3::MercVertex> new_vertices;
std::vector<tfrag3::Texture> new_textures;
tfrag3::MercModel new_model;
};
MercSwapData load_replacement_merc_model(const std::string& name,
u32 current_idx_count,
u32 current_vtx_count,
u32 current_tex_count,
const std::string& path,
const std::vector<tfrag3::MercVertex>& old_verts,
bool custom_mdl);
gltf_util::MercSwapData load_custom_merc_model(const std::string& name,
u32 current_idx_count,
u32 current_vtx_count,
u32 current_tex_count,
const std::string& path,
const std::vector<tfrag3::MercVertex>& old_verts,
bool custom_mdl);
} // namespace decompiler
+1
View File
@@ -1616,6 +1616,7 @@ void types2_for_expr(types2::Type& type_out,
case SimpleExpression::Kind::VECTOR_CROSS:
case SimpleExpression::Kind::VECTOR_MINUS:
case SimpleExpression::Kind::VECTOR_PLUS:
case SimpleExpression::Kind::VECTOR_XYZ_PRODUCT:
types2_for_vector_in_and_out(type_out, expr, input_types, dts, extras);
break;
case SimpleExpression::Kind::VECTOR_FLOAT_PRODUCT:
Loaded 100 of 3774 files, more files were not shown because too many files have changed in this diff. Show more