Compare commits

...
102 Commits
Author SHA1 Message Date
Tyler Wilding 1e307c8a9e i18n: add finnish to menus 2024-07-31 22:34:55 -04:00
Tyler Wilding 3a67f40098 i18n: remove meta line 2024-07-31 22:21:04 -04:00
Aloqas cbfa65c78a Update text-id-h.gc 2024-07-31 23:43:55 +03:00
Aloqas 681c419f17 Update subtitle_meta_fi-FI.json 2024-07-31 23:43:42 +03:00
Aloqas a4e108cca6 city-save-lurkers-intro 2024-07-31 23:41:08 +03:00
Aloqas f1ee25c640 Merge branch 'master' into test2 2024-07-31 18:55:20 +03:00
Tyler Wilding af6de539b5 jak1/jak2: Persist sound settings, play-hints, subtitles and vibration settings in pc-settings instead of the memory card file (#3612)
In the original game, they had no choice but to use the memory card file
as their method of persisting settings. We are not limited by such
things.

It's inconvenient to have to load your save-file when launching the game
to initialize these settings to your liking, it's also confusing
behaviour to even some players that have played the game heavily for
over a decade. We can do better by globally saving these settings to the
`pc-settings` file instead.

Originally I only migrated the volume settings, then i figured it would
be nice to also have play-hints and subtitles settings persisted. More
could debatably be moved (language is a big one...) but these were the
low hanging fruit.

I also reduced the default volumes as that is something else that has
come up a few times.
2024-07-31 00:01:18 -04:00
Tyler Wilding c72a086e49 jak2: support mirror mode (#3616)
Fixes #3210


![image](https://github.com/user-attachments/assets/86bb6a67-bc6a-4169-aa82-d6a46ecd43d7)

TIL that on the PS4/PS5, mirror mode breaks the upscaling
2024-07-30 23:30:53 -04:00
Hat Kid a66d832b2f jak3: add more prim buckets (#3618)
Used by `prebot`
2024-07-30 19:50:00 +02:00
Tyler Wilding d29ab77892 g/j1: fix menu labelling issue in jak1 (#3613)
Fixes #3393
2024-07-29 21:57:26 -04:00
Tyler Wilding e975eab15a decompiler: Apply docstring indentation fix to all game versions (#3614)
Previously was only applying to game versions above Jak 2, Fixes #3342
2024-07-29 21:57:07 -04:00
OpenGOAL BotandOpenGOALBot 441952186c CI: Periodic Controller Database Update (#3615)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-07-29 19:14:02 -04:00
Tyler Wilding d819d6da05 game: cleanup some display settings related code, forbid invalid game-size resolutions (#3601)
Fixes https://github.com/open-goal/jak-project/issues/3563

These users have the following spamming in logs:
> OpenGL error 0x502 S8246 T824C: GL_INVALID_OPERATION error generated.
Source and destination dimensions must be identical with the current
filtering modes.

And the solution is to correctly set their game-size. The way this
change accomplishes that is by confirming whether or not the set
`game-size` is a valid resolution informed by SDL, if not, it defaults
to the monitor's currently set display mode's resolution.

This also moves the selected display id, and the display mode into the
C++ settings -- closer to where it's actually managed and used. I'm
tempted to do this eventually for the resolutions as well but that stuff
is much more burdensome. This hopefully simplifies debugging, reduces
startup flickering, and removes back-and-forth complexity. Hopefully
this makes debugging display related problems easier. It also adds a
bunch more logging to the related code.
2024-07-27 22:29:14 -04:00
Hat Kid ce978638fe jak3: add darkjak highres texture anim (#3611)
Eyes don't work yet
2024-07-28 02:45:00 +02:00
water111 9d0009715e [jak3] Fix alpha for prims, entity-table (#3609)
Fix issue where light-trail is invisible and some actors not spawning
due to out of memory.
2024-07-27 12:46:33 -04:00
water111 3856ae505a [jak3] Some cleanup/fixes around curve and light-trail (#3608)
They still don't work yet, this is just naming/comments to help with
debug.

The vehicle tracks are now at least trying to draw, but like the others,
don't actually show up.
2024-07-27 11:17:39 -04:00
Tyler Wilding 92c4390f0a jak1: Adjust sprite positioning or hide them where appropriate when using non-standard aspect ratios (#3596)
This attempts to do a best-effort quick fix for the sprite alignment in
the menus and first person views on higher aspect ratios. This:
- Hides the binocular borders completely when using a non-standard ratio
![Screenshot 2024-07-20
021430](https://github.com/user-attachments/assets/c56d3a6c-13b0-43e1-b99b-83292993728c)
- Hides the borders in jak's first person view when using a non-standard
ratio
![Screenshot 2024-07-20
021310](https://github.com/user-attachments/assets/fefca993-960b-4741-87b7-6d7c17efe89d)
- Uses a combination of manual alignment and approximation to get the
pause menu closer.
![Screenshot 2024-07-20
151725](https://github.com/user-attachments/assets/2c8aa759-b33a-4fbe-abc6-b5861fc33208)
> 32:9 screenshot.

I accomplished the last one by manually aligning all of the core sprites
and text for the most popular aspect ratios. This means that from a
practical standpoint, things should align "perfectly". However, I then
used all of those values to derive a polynomial for each adjustment
based on the aspect ratio. This allows the game to do a half-decent
approximation/interpolation for every aspect ratio in-between the common
ones. It won't be perfect, but it will be better than this:

![image](https://github.com/user-attachments/assets/420b1e38-6f88-436a-8e8c-21df6b49428e)
2024-07-26 23:15:51 -04:00
zakfaulk a7c9151c6c Jak1: Add Autosplitting options for tasks completed in one level and turned in in another (#3595)
For the FJ Mirrors, Muse, Lightning Moles, and Gambler's race the tasks
are completed in one level, then turned in at the hub. This presents a
spot of confusion for new players with the autosplitter and requires
hacky workarounds for those who want to split on these conditions. This
pull request adds in the necessary code to the autosplit-h.gc and
autosplit.gc files so that the autosplitter can identify these events,
similar to the talk to fisherman and catch fish options in the current
autosplitter.
2024-07-26 23:12:30 -04:00
water111 82a23c747e [jak3] prim rendering for cloth (#3607) 2024-07-26 20:31:32 -04:00
water111 f0b46ff2e5 [jak3] A few bug fixes (#3606)
A few minor fixes:

- Fix crash in overlord3 during final boss
https://github.com/open-goal/jak-project/issues/3605
- Update goal_src for `scene-actor.gc`, which was not updated after a
bug fix for decompiling skelgroups, making some cutscene actors
invisible due to using the wrong joint for culling checks.
- Stop using `-1` as an invalid value for texture id's in Merc.cpp. This
could sometimes cause Merc2.cpp to accidentally skip updating the OpenGL
texture. This fixes the bug where skull gems sometimes didn't have the
animated textures.
2024-07-26 13:48:43 -04:00
water111 9d80ada016 [jak3] Fix eye slot assignment and textures (#3603)
I found two issues with Jak 3 eyes. The first was simple - we were
missing a `-pc` texture upload in `texture.gc` for `pris2` textures,
which has eye textures for a few characters, like torn or damas.

The second was a little more annoying. Unlike jak 2 and jak 1, jak 3 can
dynamically assign eye slots when merc models are loaded. This involves
modifying eye data to tell the eye renderer where to render, and
modifying the merc model's adgif shaders to point to the correct eye
texture. The modification to the merc adgif shader is problematic since
our PC port of merc assumes this slot is constant.

My solution here was to bypass this whole slot system entirely for jak
3. I modified the GOAL eye renderer to tell the c++ eye renderer the
name of the merc-ctrl containing the eye. Then, the PC C++ Merc renderer
can just look up the merc-ctrl by name. To make this fit nicely in the
existing memory layout, I used a 64-bit fnv hash of the name. (which
honestly is how we should have handled a lot of other texture/model
names stuff...)

Unrelated fix to Overlord2 so it handles the case where file size
changes after the game starts, I had this in jak2/jak1 and forgot it for
jak 3.
2024-07-26 11:42:52 -04:00
water111 e81431bd21 [wip] Jak 3 Overlord (#3567) 2024-07-26 09:42:28 -04:00
OpenGOAL BotandOpenGOALBot 57772c59a0 CI: Periodic Controller Database Update (#3600)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-07-23 20:36:54 -04:00
Hat Kid edae60d58d decompiler: support merc model replacements and adding custom actor models to vanilla fr3s (#3597)
This adds support for replacing existing merc models in FR3 files with
custom GLB model files. The replacements go in
`custom_assets/<GAME>/merc_replacements`, similar to texture
replacements. When a `.glb` file with a file name that matches any model
present in an FR3 is detected (e.g. `eichar-lod0` for Jak), all merc
model data is replaced with the given model.

Additionally, models for custom actors can now also be added to vanilla
FR3s. The models for this go in
`custom_assets/<GAME>/models/<LEVEL_NAME>` (e.g.
`custom_assets/jak1/models/jungleb/test-actor-lod0.glb`) and will be
added to the FR3 that has a matching name (exception: to add things to
the common level file, the folder should be named `common` instead of
`GAME`).
For custom levels, these now go in
`custom_assets/<GAME>/models/custom_levels` (previously
`custom_assets/<GAME>/models`).

Another small change: When level ripping is enabled, the resulting model
files will now be stored in game name subfolders inside of `glb_out`.
2024-07-21 01:51:31 +02:00
Hat Kid 365fae4913 jak3: fix bbush rings (#3593)
Fixes #3592
2024-07-17 21:49:07 +02:00
OpenGOAL BotandOpenGOALBot 3d04ac958c CI: Periodic Controller Database Update (#3585)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-07-16 19:45:50 -04:00
Tyler Wilding 849ba391d4 game: log more OpenGL info (#3588)
Logs the OpenGL vendor and renderer, in most cases this helps identify
what GPU the game is using, which is something that comes up from
time-to-time in support.


![image](https://github.com/user-attachments/assets/4d9ca6fa-f3ea-440e-bce2-7d22dab21ec6)
2024-07-16 19:40:50 -04:00
Hat Kid c8fbe26c7d jak3: fix texture anim alpha (#3587) 2024-07-15 21:39:44 +02:00
Hat Kid fbab87b0fe jak3: fix opengl error spam (#3586) 2024-07-15 20:21:52 +02:00
Hat Kid 1c170b741c jak3: fix robo-hover hand cannon nans (#3584)
Fixes #3583.

The callback function for the hand cannon joint mods was initialized
prior to calling `ja-post`, propagating NaNs.
2024-07-15 16:28:28 +02:00
Brent HickeyandHat Kid b8f1ee5289 [high fps] Increase input buffer for jak1 and jak3 (#3578)
Applying https://github.com/open-goal/jak-project/pull/3178 to jak1 and
jak3

This also fixes cloud speed in jak3

---------

Co-authored-by: Hat Kid <[email protected]>
2024-07-15 02:56:10 +02:00
Hat Kid bdded9ad8c jak3: add missing texture animations (#3577)
This refactors some of the texture animation code a bit to better
support multiple games and adds most of the missing texture animations
for Jak 3 with a couple of exceptions/bugs:

- `hanga-sprite`: Despite `move_to_pool` being set for this anim, it's
not showing up in-game, but it does display properly in the ImGUI debug
window.

![image](https://github.com/open-goal/jak-project/assets/6624576/29df8e17-8831-412b-b9b7-7704d6bd7813)
- `factoryc-alpha`: Some conveyors do not have the animation for some
reason.

![image](https://github.com/open-goal/jak-project/assets/6624576/209ef073-2a81-4e2c-b020-dc2ae0b01196)
- This spot in Spargus seems to use texture animations, but it looks
like it maps to the `fora-water-dest` texture/slot, which comes from
`foresta-water`. Because the texture is not initialized, the texture
shows up black on first load, but it does show up after loading
`foresta`.

![image](https://github.com/open-goal/jak-project/assets/6624576/1e54bab2-f97c-47d5-a92a-a98a52c30178)

![image](https://github.com/open-goal/jak-project/assets/6624576/240b0137-1e9e-4e65-8446-0f78df9802dd)
- `hfrag` texture anim is not handled yet. Probably needs some special
casing.
2024-07-15 02:25:18 +02:00
Hat Kid 08a23793c8 jak3: fix some nan bugs (#3581)
Fixes a couple of NaN bugs, making the Arena and Marauder Stronghold
missions, the leaper corralling mission and final boss playable:

- Fixes #3579:
- After catching a leaper, the `flut` that spawns would have a NaN
`world-sphere`
- Fixes #3580:
- `vf0` was being clobbered after a `suspend`, causing them to spawn at
the origin.
- The Terraformer's `world-sphere` would be NaN until an animation
started playing.
2024-07-15 01:54:52 +02:00
ZedB0T 291c89a851 Update volume in sound-group sog3 to sfx-volume (#3574)
Adds a way to override certain sounds that don't respect the settings
that they should...



https://github.com/open-goal/jak-project/assets/89345505/97d9518d-aafd-4227-b25f-82c5d32e811e
2024-07-09 01:24:03 +02:00
Tyler Wilding b4113dda67 decompiler: Cleanup duplication in extractor/decompiler and make it easier to enable streamed audio ripping from CLI (#3560)
This centralizes the code that both `extractor` and the decompiler
executes. In the past this code was partially-duplicated, meaning that
the `extractor` could only do _some_ operations and not others (ie.
could not extract the audio files).

I also simplified the process to enable audio streaming in the
configuration. This is to support a new feature in the launcher that
allows you to enable these options for the decompiler:


![image](https://github.com/open-goal/jak-project/assets/13153231/8e6c20a1-8b5b-46f0-bceb-7644f713989f)
2024-06-29 01:18:39 -04:00
OpenGOAL BotandOpenGOALBot a485c236d6 CI: Periodic Controller Database Update (#3564)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-06-24 14:44:01 -04:00
Tyler Wilding 73ff53f01d debugging: Improve event profiler utility (#3561)
- Can make the event buffer larger or smaller
- UI shows the current event index / size, so you know how fast it's
filling up
- Can save compressed, 10x reduction in filesize and Windows 11 explorer
actually supports ZSTD natively now so this isn't inconvenient at all

![Screenshot 2024-06-22
000343](https://github.com/open-goal/jak-project/assets/13153231/2f7dfa41-d931-4170-a848-840cbed9be9f)
> An example of almost 1 million events.  Results in a 4mb file.
2024-06-22 22:01:33 -04:00
Aloqas 495a8bc26f rewording stuff 2024-06-20 18:26:15 +03:00
OpenGOAL BotandOpenGOALBot 90c11bde8f CI: Periodic Controller Database Update (#3557)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-06-19 19:24:47 -04:00
Matt Dallmeyer 86979e3d06 [jak1] Enforce certain pc-settings in speedrunner mode (#3553)
Currently PS2 Actor Vis and FPS are only enforced when starting a run -
this enforces them on every frame similar to cheats.
In the progress menu, FPS is already disabled in speedrunner mode - this
adds the same restriction for PS2 Actor Vis.

Jak 2 already does this properly, no change needed there
2024-06-15 14:54:53 -04:00
OpenGOAL BotandOpenGOALBot 29849a4fbb CI: Periodic Controller Database Update (#3555)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-06-15 00:13:41 -04:00
RoyalForgotten b0b9fc4311 Jak 2 3rd update subtitle_lines_fr-FR.json (#3546)
Fixed several translation errors
2024-06-05 23:19:10 -04:00
Tyler Wilding c162c66118 g/j1: Cleanup all main issues in the formatter and format all of goal_src/jak1 (#3535)
This PR does two main things:
1. Work through the main low-hanging fruit issues in the formatter
keeping it from feeling mature and usable
2. Iterate and prove that point by formatting all of the Jak 1 code
base. **This has removed around 100K lines in total.**
- The decompiler will now format it's results for jak 1 to keep things
from drifting back to where they were. This is controlled by a new
config flag `format_code`.

How am I confident this hasn't broken anything?:
- I compiled the entire project and stored it's `out/jak1/obj` files
separately
- I then recompiled the project after formatting and wrote a script that
md5's each file and compares it (`compare-compilation-outputs.py`
- The results (eventually) were the same:

![Screenshot 2024-05-25
132900](https://github.com/open-goal/jak-project/assets/13153231/015e6f20-8d19-49b7-9951-97fa88ddc6c2)
> This proves that the only difference before and after is non-critical
whitespace for all code/macros that is actually in use.

I'm still aware of improvements that could be made to the formatter, as
well as general optimization of it's performance. But in general these
are for rare or non-critical situations in my opinion and I'll work
through them before doing Jak 2. The vast majority looks great and is
working properly at this point. Those known issues are the following if
you are curious:

![image](https://github.com/open-goal/jak-project/assets/13153231/0edfaba1-6d36-40f5-ab23-0642209867c4)
2024-06-05 22:17:31 -04:00
ManDude 37762c5fb7 wrap sprite rgba to 0-255 (#3549) 2024-06-04 07:57:52 +01:00
OpenGOAL BotandOpenGOALBot a18d9dd4d0 CI: Periodic Controller Database Update (#3548)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-06-03 23:00:48 -04:00
Tyler Wilding a9bdb0136e New Crowdin updates (#3547)
People seem to be translating lines that aren't in the base english one,
such as `mtn-plat-buried-rocks-a`

This is fine, but Crowdin will continue to remove these every sync PR
because they aren't in the base english file. So some kind of
segregation needs to happen.

If we didn't want these scenes translated, then they should be banned
from being translated via the editor / etc in the first place (shouldn't
have been included in the metadata).
2024-06-03 01:01:58 -04:00
Tyler Wilding eb703ee96e REPL related improvements and fixes (#3545)
Motivated by - https://github.com/open-goal/opengoal-vscode/pull/358

This addresses the following:
- Fixes #2939 spam edge-case
- Stop picking a different nREPL port based on the game mode by default,
this causes friction for tools in the average usecase (having a REPL
open for a single game, and wanting to connect to it). `goalc` spins up
fine even if the port is already bound to.
- For people that need/want this behaviour, adding per-game
configuration to the `repl-config.json` is on my todo list.
- Allows `goalc` to permit redefining symbols, including functions. This
is defaulted to off via the `repl-config.json` but it allows you to for
example, change the definition of a function without having to restart
and rebuild the entire game.
![Screenshot 2024-06-02
124558](https://github.com/open-goal/jak-project/assets/13153231/28f81f6e-b7b8-4172-9787-f96e4ab1305b)
- Updates the welcome message to include a bunch of useful metadata
up-front. Cleaned up all the startup logs that appear when starting
goalc, many of whom's information is now included in the welcome
message.
  - Before:

![image](https://github.com/open-goal/jak-project/assets/13153231/814c2374-4808-408e-9ed6-67114902a1d9)

  - After:
![Screenshot 2024-06-01
235954](https://github.com/open-goal/jak-project/assets/13153231/f3f459fb-2cbb-46ba-a90f-318243d4b3b3)
2024-06-03 00:14:52 -04:00
ManDude 39786482a1 jak3: airlock speed hacks + make cutscenes skip properly (#3543) 2024-06-02 15:03:58 +01:00
ManDude f586cb9af2 fix nav mesh debugging crash (#3542) 2024-06-01 00:50:14 +01:00
ManDude ea1271cfd0 [jak3] implement autocollect and city turbo board cheats, fix actor heap and level flags (#3541) 2024-05-31 16:41:35 +01:00
AloqasandTyler Wilding cefb371681 [jak2] new subtitle speakers (#3536)
for specific cutscene scenarios

---------

Co-authored-by: Tyler Wilding <[email protected]>
2024-05-30 22:02:44 -04:00
Matt Dallmeyer 70ea2a1f67 jak3 - fill out some text-id entries (#3494)
Slam Dozer > Ram Rod
2024-05-30 21:49:10 -04:00
Hat Kid c64eea6337 [buildactor] support generating collide-meshes for custom models (#3540)
This adds support for generating collide meshes when importing custom
models. A couple of things to keep in mind:

- A single `collide-mesh` may only have up to 255 vertices.
- When exporting a GLTF file in Blender, a `collide-mesh` will be
generated for every mesh object that has collision properties applied
(ideally, you would set all visual meshes to `ignore` and your collision
meshes to `invisible` in the OpenGOAL plugin's custom properties).
- Ensure that your actor using the model properly allocates enough
`collide-shape-prim-mesh`es for each `collide-mesh` ([example from the
original game that uses multiple
meshes](https://github.com/open-goal/jak-project/blob/f6688659f2ef85f5ceaacea6271580c9f4d91ed1/goal_src/jak1/levels/finalboss/robotboss.gc#L2628-L2806)).

~One annoying problem that I haven't fully figured out yet (unrelated to
the actual functionality):
`collide-mesh`es are stored in art groups as an `(array collide-mesh)`
in the `art-joint-geo`'s `extra`, so I had to add a new `Res` type to
support this. The way that `array`s are stored in `res-lump`s is a bit
of a hack right now. The lump only stores a pointer to the array, so the
size of that is 4 bytes, but because we have to generate all the actual
array data too, the current `ResLump` code in C++ doesn't handle this
case well and would assert, so I decided to omit the asserts if an
`array` tag is present and "fake" the size so the object file is
generated more closely to how the game expects it until we figure out
something better.~
This was fixed by generating the array data beforehand and creating a
`ResRef` class that takes the pointer to the array data and adds it to
the lump.
2024-05-29 06:09:20 +02:00
Tyler Wilding f1de2c9bc5 g/j2: add some debug menu options to unlock things and give orbs/gems/ammo (#3539)
Adds some debug options that make it easier to quickly complete the
game, get orbs, unlock cheats, etc.


![image](https://github.com/open-goal/jak-project/assets/13153231/8854dc42-084a-457e-ae9b-e9ba2dd7917c)
2024-05-27 22:58:52 -04:00
Tyler Wilding f6688659f2 game: fix the path the--portable flag determines (#3537)
`--portable` was using the path to the executable's file, instead of the
directory that contains the executable
2024-05-26 00:40:33 -04:00
OpenGOAL BotandOpenGOALBot 12ce274226 CI: Periodic Controller Database Update (#3528)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-05-25 10:51:09 -04:00
Matthew Wells bd2db7b15a Add periods to lines in code_status.md for consistency (#3521) 2024-05-25 10:51:01 -04:00
Aloqas c2cccc48cd another change 2024-05-24 15:35:17 +03:00
Aloqas c5effb2395 small change 2024-05-24 12:14:29 +03:00
Aloqas 5f3671b8a3 small fixes 2024-05-24 11:02:02 +03:00
ManDude 645e649a9c jak3: shadow culling hack + finish region debugging tools + fix bigmap crashes (#3532) 2024-05-23 23:43:38 +01:00
Aloqas 26bfac8555 Jak 2: Finnish subtitles and game text 2024-05-23 22:54:42 +03:00
ManDude dd765b41cb jak 3 shadows (#3530)
![image](https://github.com/open-goal/jak-project/assets/7569514/e48dbbb8-82d9-4b9d-8ae4-3f48f7c35ced)
2024-05-23 18:29:42 +01:00
ManDude 0db7be55e6 jak3: sprite limit increase + add bsphere toggle for region faces (#3529) 2024-05-22 16:27:00 +01:00
Hat Kid 62ef9fe49d [wip] build actor tool (#3266)
This does a couple of things:

- The `custom_levels` folder was renamed to `custom_assets` and contains
`levels`, `models` and `texture_replacements` folders for Jak 1, 2 and 3
in order to keep everything regarding custom stuff in one place.
- With this, texture replacements now use separate folders for all games
- A build actor tool was added that generates art groups for custom
actors
- Custom levels can now specify what custom models from the `models`
folder they want to import, this will add them to the level's FR3.
- A `test-zone-obs.gc` file was added, containing a `test-actor` process
that uses a custom model as an example.

The build actor tool is still very WIP, the joints and the default
animation are hardcoded, but it allows for importing any GLB file as a
merc model.
2024-05-18 18:18:25 +02:00
water111 271007e552 Start setting up texture animation for jak 3. (#3524)
For now, this just adds sky (clouds and fog), darkjak, and skull gem.

There are some unknown issues with drawing the skull gems still, but I
think it's unrelated to texture animations.

Also fixes https://github.com/open-goal/jak-project/issues/3523
2024-05-18 11:23:48 -04:00
Hat Kid a61f24a168 jak3: custom level support (#3522) 2024-05-16 21:15:54 +02:00
Hat Kid c12a5d777c decomp3: decompile remaining mission code (#3515)
This should make all missions playable with the exception of the end of
`precursor-destroy-ship` because `precurd` asserts on level extraction.

- `trail`
- `trail-graph`
- `wastrail-graph`
- `cty-protect`
- `protect-gunship`
- `protect-path`
- `protect-script`
- `assault-cams`
- `assault-enemies`
- `assault-path`
- `assault-script`
- `assault-shared`
- `assault-task`
- `hover-nav-precura`
- `precura-mood`
- `precura-obs`
- `precura-obs2`
- `precura-part`
- `precurc-mood`
- `precurc-obs`
- `precurc-part`
- `precurd-obs`
- `precurd-part`
- `precurd-scenes`
2024-05-16 16:21:44 +02:00
Tyler Wilding 456d1ba536 goalc: add a performance report feature (#3519)
Adds a quick perf report feature to `goalc` that lets you compare how
much faster / slower it takes to compile the projects, with some simple
features like filtering the files, adjusting for how large of a margin
of error in the speeds you care about, and which test iteration you want
to compare against.

This is something I plan to use as I work more in `goalc` as an easy way
to track / show the results.


![image](https://github.com/open-goal/jak-project/assets/13153231/26f140c7-66d7-4162-994a-a71061e22857)
2024-05-15 22:52:16 -04:00
OpenGOAL BotandOpenGOALBot 4aafab2fc9 CI: Periodic Controller Database Update (#3517)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-05-13 20:37:21 -04:00
ManDude ebbbedabc5 jak3: fix hud sprite crash + add entity debugger (#3516) 2024-05-13 04:09:25 +01:00
Tyler Wilding d1ece445d4 Dependency graph work - Part 1 - Preliminary work (#3505)
Relates to #1353 

This adds no new functionality or overhead to the compiler, yet. This is
the preliminary work that has:
- added code to the compiler in several spots to flag when something is
used without being properly required/imported/whatever (disabled by
default)
- that was used to generate project wide file dependencies (some
circulars were manually fixed)
- then that graph underwent a transitive reduction and the result was
written to all `jak1` source files.

The next step will be making this actually produce and use a dependency
graph. Some of the reasons why I'm working on this:
- eliminates more `game.gp` boilerplate. This includes the `.gd` files
to some extent (`*-ag` files and `tpage` files will still need to be
handled) this is the point of the new `bundles` form. This should make
it even easier to add a new file into the source tree.
- a build order that is actually informed from something real and
compiler warnings that tell you when you are using something that won't
be available at build time.
- narrows the search space for doing LSP actions -- like searching for
references. Since it would be way too much work to store in the compiler
every location where every symbol/function/etc is used, I have to do
ad-hoc searches. By having a dependency graph i can significantly reduce
that search space.
- opens the doors for common shared code with a legitimate pattern.
Right now jak 2 shares code from the jak 1 folder. This is basically a
hack -- but by having an explicit require syntax, it would be possible
to reference arbitrary file paths, such as a `common` folder.

Some stats:
- Jak 1 has about 2500 edges between files, including transitives
- With transitives reduced at the source code level, each file seems to
have a modest amount of explicit requirements.

Known issues:
- Tracking the location for where `defmacro`s and virtual state
definitions were defined (and therefore the file) is still problematic.
Because those forms are in a macro environment, the reader does not
track them. I'm wondering if a workaround could be to search the
reader's text_db by not just the `goos::Object` but by the text
position. But for the purposes of finishing this work, I just statically
analyzed and searched the code with throwaway python code.
2024-05-12 12:37:59 -04:00
water111 e0b1d8c21e Jak3 sky (#3514) 2024-05-12 09:36:50 -04:00
Hat Kid 6b3844bf99 decomp3: more misc files (#3513)
4 missions to go!

- `ctygenb-part`
- `power-game`
- `vinroom-part`
- `vinroom-scenes`
- `gungame-part`
- `gungame-scenes`
- `hiphog-obs`
- `hiphog-part`
- `hiphog-scenes`
- `hover-nav-lpattack`
- `king-rider`
- `rubble-attack`
- `rubble-obs`
- `rubble-part`
- `rubblea-init`
- `rublcst-scenes`
- `mood-funcs2`
- `gun-dummy-art`
- `gun-dummy-part`
- `gun-dummy`
- `gungame-data`
- `gungame-manager`
- `gungame-obs`
- `blow-tower-data`
- `blow-tower-extra`
- `blow-tower-obs2`
- `blow-tower-obs`
- `blow-tower-part`
- `blow-tower-script`
- `blow-tower-shared`
- `blow-tower-speech`
- `cty-blow-tower`
2024-05-11 17:57:26 -04:00
BreakPoints 24490c042e Intro palace DGOs (#3512)
Now needed to extract and compile from scratch
2024-05-11 10:21:45 -04:00
Hat Kid 4dd2bab06e jak3: fix local space particle info crash (#3511) 2024-05-10 16:14:50 +02:00
water111 5b04be2fa0 Add hfrag, clean up some background renderer stuff (#3509)
This adds hfrag, but with a few remaining issues:
- The textures aren't animated. Instead, it just uses one texture.
- The texture filtering isn't as good as at it could be.

I also cleaned up a few issues with the background renderers:
- Cleaned up some stuff that is common to hfrag, tie, tfrag, shrub
- Moved time-of-day color packing stuff to FR3 creation, rather than at
level load. This appears to reduce the frame time spikes when a level is
first drawn by about 5 or 6 ms in big levels.
- Cleaned up the x86 specific stuff used in time of day. Now there's
only one place where we have an `ifdef`, rather than spreading it all
over the rendering code.
2024-05-09 20:11:43 -04:00
Hat Kid 949508d0ed decomp3: traffic/citizen/faction code, desert-rescue (#3506)
- `cty-faction-h`
- `nav-graph`
- `citizen-h`
- `citizen`
- `civilian`
- `traffic-engine`
- `traffic-manager`
- `cty-attack-controller`
- `cty-faction`
- `formation-object`
- `formations`
- `squad-control-city-h`
- `squad-control-city`
- `traffic-util`
- `wlander-female`
- `wlander-h`
- `wlander-male`
- `speech-manager`
- `desert-rescue`
- `desresc-path`
- `neo-satellite`
- `rope-prim-system-h`
- `rope-prim-system`
- `rope-system`
- `wland-passenger`
- `cty-guard-projectile`
- `ctywide-init`
- `ff-squad-control`
- `guard-grenade`
- `guard-rifle`
- `guard-states`
- `guard-tazer`
- `ctywide-speech`
- `citizen-chick`
- `citizen-fat`
- `citizen-norm`
- `guard`
- `bike`
- `car`
- `test-bike`
- `vehicle-rider`
- `desert-rescue-bbush`
- `ff-squad-control-h`
- `flee-info`
- `guard-h`
- `mission-squad-control`
- `kg-squad-control`
- `kg-squad-member-h`
- `kg-squad-member`
- `mh-squad-control`
- `mh-squad-member-h`
- `mh-squad-member`
- `ctywide-obs-h`
- `ctywide-obs`
- `ctywide-part`
- `ctywide-scenes`
- `ctywide-tasks`
- `ctywide-texture`
- `billiards`
- `guide-arrow`
- `kg-vehicles`
- `flying-turret`
- `roboguard-city`
- `citizen-enemy`
- `metalhead-flitter`
- `metalhead-grunt`
- `metalhead-predator`
- `spydroid`
- `kg-squad-control-h`
- `mh-squad-control-h`
- `krimson-wall`
- `ctyport-obs`
- `ctyinda-obs`
- `ctyinda-part`
- `ctyindb-obs`
- `ctyindb-part`
- `ctyport-attack`
- `h-torpedo`
- `ctyport-part`
- `ctyport-scenes`
- `external-player-control`
- `desert-chase-path-h`
- `desert-chase-path`
- `desert-chase`
- `desert-jump`
- `wcar-catapult`
- `bombbot-h`
- `bombbot`
- `bombbot-path`
- `cty-hijack-missile`
- `cty-hijack`
- `ctyport-attack-bbush`
- `ctysluma-part`
- `ctyslumb-part`
- `ctyslumc-obs`
- `ctyslumc-part`
- `searchlight`
- `cty-destroy-grid`
- `ctyfarm-obs`
- `ctyfarma-part`
- `ctyfarmb-part`
- `freehq-part`
- `freehq-scenes`
- `onintent-scenes`
- `onintent-part`
- `cty-sniper-battery`
- `cty-sniper-turret`
- `intro-obs`
- `intro-part`
- `intro-scenes`
- `palcab-part`
- `palroof-part`
2024-05-09 19:18:55 -04:00
OpenGOAL BotandOpenGOALBot f479cef939 CI: Periodic Controller Database Update (#3507)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-05-06 14:22:45 -04:00
water111andManDude 807ca7465f fix c++ compiler warnings, extract_merc assert (#3488)
Co-authored-by: ManDude <[email protected]>
2024-05-03 17:29:18 +01:00
ManDude cf79ca04e9 fix another jak 1 level name (#3503) 2024-05-03 08:34:36 +01:00
Tyler Wilding 6569636abf ci: pin to avx for macos (#3502)
Related to #3439

Will see after a few weeks if the problem resurfaces. All macos related
caches have been purged to eliminate that as a possibility.
2024-05-01 22:00:56 -04:00
Hat Kid f9e0aa82bc jak3: fix mirage shot (#3501) 2024-05-01 21:57:13 +02:00
dependabot[bot]andTyler Wilding 39f3549640 build(deps): bump hendrikmuhs/ccache-action from 1.2.12 to 1.2.13 (#3497)
Bumps
[hendrikmuhs/ccache-action](https://github.com/hendrikmuhs/ccache-action)
from 1.2.12 to 1.2.13.
<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.13</h2>
<h2>What's Changed</h2>
<ul>
<li>add emscripten to the compiler list by <a
href="https://github.com/mmomtchev"><code>@​mmomtchev</code></a> in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/187">hendrikmuhs/ccache-action#187</a></li>
<li>Bump <code>@​actions/cache</code> from 3.2.3 to 3.2.4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/183">hendrikmuhs/ccache-action#183</a></li>
<li>Bump typescript from 5.3.3 to 5.4.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/190">hendrikmuhs/ccache-action#190</a></li>
<li>Bump typescript from 5.4.2 to 5.4.3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/191">hendrikmuhs/ccache-action#191</a></li>
<li>fix: early exit process so node doesn't wait for hanging promises by
<a
href="https://github.com/chirag-droid"><code>@​chirag-droid</code></a>
in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/182">hendrikmuhs/ccache-action#182</a></li>
<li>Bump typescript from 5.4.3 to 5.4.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/193">hendrikmuhs/ccache-action#193</a></li>
<li>Update windows by <a
href="https://github.com/virtuald"><code>@​virtuald</code></a> in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/180">hendrikmuhs/ccache-action#180</a></li>
<li>Bump <code>@​types/node</code> from 20.11.10 to 20.12.7 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/194">hendrikmuhs/ccache-action#194</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/mmomtchev"><code>@​mmomtchev</code></a>
made their first contribution in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/187">hendrikmuhs/ccache-action#187</a></li>
<li><a
href="https://github.com/chirag-droid"><code>@​chirag-droid</code></a>
made their first contribution in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/182">hendrikmuhs/ccache-action#182</a></li>
<li><a href="https://github.com/virtuald"><code>@​virtuald</code></a>
made their first contribution in <a
href="https://redirect.github.com/hendrikmuhs/ccache-action/pull/180">hendrikmuhs/ccache-action#180</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/hendrikmuhs/ccache-action/compare/v1.2.12...v1.2.13">https://github.com/hendrikmuhs/ccache-action/compare/v1.2.12...v1.2.13</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/c92f40bee50034e84c763e33b317c77adaa81c92"><code>c92f40b</code></a>
Bump <code>@​types/node</code> from 20.11.10 to 20.12.7 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/194">#194</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/ff9f6cc67d49b9acaa9e102f80d1ea8a0c86a6dd"><code>ff9f6cc</code></a>
update checksum</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/985163732c9a0ab6be742a4db87bb36d07d6ca9f"><code>9851637</code></a>
update code</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/40738ee8f3bcf20e438d29f613fb2ef1b5cff79d"><code>40738ee</code></a>
Update windows (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/180">#180</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/ba6e323cc10f37a14582696e025efe365df0b125"><code>ba6e323</code></a>
Bump typescript from 5.4.3 to 5.4.5 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/193">#193</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/550708f4f24caa1472defc821c356d0e72d45643"><code>550708f</code></a>
fix: early exit process so node doesn't wait for hanging promises (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/182">#182</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/259dcb3149e7662420f6b796600eac9008bb2d4e"><code>259dcb3</code></a>
Bump typescript from 5.4.2 to 5.4.3 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/191">#191</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/a16392ef06bb17357c33855e071f12873d87b163"><code>a16392e</code></a>
update code</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/3818c2034d1b62be7cc5e8e097c7c3996d94a068"><code>3818c20</code></a>
Bump typescript from 5.3.3 to 5.4.2 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/190">#190</a>)</li>
<li><a
href="https://github.com/hendrikmuhs/ccache-action/commit/b647aa998265c7332fbcd30509be75d7ed682458"><code>b647aa9</code></a>
Bump <code>@​actions/cache</code> from 3.2.3 to 3.2.4 (<a
href="https://redirect.github.com/hendrikmuhs/ccache-action/issues/183">#183</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/hendrikmuhs/ccache-action/compare/v1.2.12...v1.2.13">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.12&new-version=1.2.13)](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>
Co-authored-by: Tyler Wilding <[email protected]>
2024-05-01 15:53:40 -04:00
Hat Kid 3ff3760621 jak3: add discord rpc and fix some decomp (#3500) 2024-05-01 13:49:26 +02:00
ManDude 5705359df9 [jak3] fix some flag names and a wcar crash (#3498) 2024-05-01 08:44:26 +01:00
Hat Kid cbf75a96f7 custom levels: don't uppercase FR3 filename (#3496) 2024-04-30 22:51:36 +02:00
ManDude 8344ac6963 use only the real level name in the Loader (#3495)
This fixes issues with certain Jak 3 levels not rendering because there
is a mismatch between the DGO name, nickname and real level name (bsp
name).

FR3s use a different filename, so you can delete the ones you have after
this is merged.

This affects custom levels, but I don't have that toolchain set up so
someone else will have to test that.
2024-04-30 17:12:57 +01:00
OpenGOAL BotandOpenGOALBot a527afdc5a CI: Periodic Controller Database Update (#3491)
Updating Controller Database

Co-authored-by: OpenGOALBot <[email protected]>
2024-04-29 19:21:43 -04:00
Matt Dallmeyer 0d4e3928eb decomp3 title-obs, credits-h (#3476) 2024-04-29 20:23:31 +02:00
ManDude e4c57d6ac9 more debug information when RPC buffers exhaust (#3490) 2024-04-29 16:37:04 +01:00
Tyler Wilding a021c392ec game: allow overriding the config directory location (#3477)
This is primarily driven for proper mod-support. Mods would like to
isolate their settings and saves (potentially) and that is currently
done by find-and-replacing code before building. Bad!

Additionally, this has the side-effect of allowing for portable
installations of the game so, win-win.

Testing in progress, i'll merge once it is ready.
2024-04-28 15:29:20 -04:00
Tyler Wilding fee0a435fc extractor: support extracting using a folder path (#3422)
Patching up the extractor while working on the launcher, fixes:
- makes it so you can compile successfully given a folder path
(currently assumes your project path contains `iso_data`)
- ignore `buildinfo.json` from validation code.
- fixes an edge-case that could recursively fill up your entire
hard-drive!
- allows overriding the decompilation configuration via flag
- adds a way to specify where the ISO should be extracted to
2024-04-28 15:02:29 -04:00
Hat Kid e2e5289788 decomp3: font widescreen and shadow hacks, generic renderer, misc files (#3483)
- `pecker-ingame`
- `des-bbush-tasks`
- `des-burning-bush`
- `des-bush-part`
- `des-bush`
- `mh-centipede`
- `mh-centipede-part`
- `mh-wasp`
- `mh-wasp-part`
- `needle-fish`
- `des-bush-time-chase`
- `timer-path`
- `mission-squad-control-h`
- `mh-bat`
- `hover-nav-factoryd`
- `hover-nav-factoryc`
- `conveyor`
- `fac-part`
- `factory-part`
- `factoryc-mood`
- `factoryc-obs`
- `factoryc-obs2`
- `lfaccar-init`
- `factory-boss-part`
- `factory-boss-scenes`
- `factory-boss-setup`
- `factory-boss-states`
- `factory-mood`
- `factoryc-manager`
- `lfacrm1-mood`
- `lfacrm2-mood`
- `missile-bot`
- `sew-laser-turret`
- `ai-task-h`
- `ash-h`
- `ash-shot`
- `ash-states`
- `ash-task`
- `ash`
- `bot-h`
- `bot-states`
- `bot`
- `ash-oasis-course`
- `oasis-defense`
- `comb-field`
- `comb-mood`
- `comb-obs`
- `comb-part`
- `comb-scenes`
- `comb-sentry`
- `comb-travel`
- `comba-init`
- `combx-scenes`
- `h-sled`
- `destroy-dark-eco`
- `fac-gunturret`
- `fac-robotank-turret`
- `fac-robotank`
- `fac-tower`
- `factory-h`
- `factory-hud`
- `factory-manager`
- `factorya-init`
- `ffight-projectile`
- `ftank-projectile`
- `fturret-projectile`
- `h-warf`
- `warf-projectile`
2024-04-28 08:59:46 -04:00
ManDude 1a058b418a jak3: hack level heap sizes (#3487) 2024-04-27 21:48:49 +01:00
Matt Dallmeyer 86d770aeeb Fix "logical not is only applied to the left hand side of comparison" warnings (#3484) 2024-04-26 16:27:11 +01:00
ManDude 889fdcd79c jak3: fix some collide decomp + fix projectiles aiming at intangible objects (#3485)
Say goodbye to half of the laser needle shots spinning around doing
nothing. This is toggleable with `fix-projectile-focus` in the pc
settings.
2024-04-26 16:22:26 +01:00
ManDude 667553850d jak2/3: re-implement screenshot system through goal (#3482) 2024-04-25 01:46:18 +01:00
ManDude d9d4cc5405 fix minimap icon misalign (#3481) 2024-04-23 18:20:31 +01:00
ManDude 728cb4b6c9 jak3 pc: math-camera, letterbox, led and auto-save (#3479) 2024-04-22 22:57:09 +01:00
Hat Kid 9d359ed84a jak3: fix type (#3478) 2024-04-22 19:53:04 +02:00
Hat Kid 58a5440c8a decomp3: more misc files (#3466)
Makes a bunch of missions mostly playable, including:
- `arena-training-1`
- `arena-fight-1`
- `wascity-chase`
- `arena-fight-2`
- `arena-fight-3`
- `volcano-darkeco`
- `desert-hover`
- `nest-eggs`
- `temple-climb`
- `temple-oracle`
- `temple-tests`
- `desert-beast-battle`
- `desert-turtle-training`
- `desert-course-race`
- `desert-artifact-race1`
- `wascity-leaper-race`
- `wascity-pre-game`
- `sewer-met-hum`
- `forest-kill-plants`
- `forest-ring-chase`
- `temple-defend`
- `tower-destroy`
- `desert-glide`

---
Files:

- `ripple`
- `waswide-mood`
- `sig-rider`
- `nst-tasks`
- `nst-part`
- `nst-gas`
- `nst-eggs-h`
- `nst-obs`
- `nst-mood`
- `egg-spider`
- `wasdoors-init`
- `wasall-tasks`
- `wvehicle-race`
- `wcar-marauder`
- `wcar-marauder-b`
- `turret-control`
- `was-squad-control`
- `turtle-training`
- `kleever-rider`
- `course-race`
- `artifact-race`
- `desert-hover`
- `desbeast-path-h`
- `des-beast`
- `desertg-obs`
- `desertf-obs`
- `desertd-obs`
- `desert-dust-storm`
- `des-cactus`
- `race-hud`
- `race-info`
- `race-manager`
- `tizard`
- `flyingsaw`
- `hover-training`
- `temple-mood`
- `temple-obs`
- `temple-obs2`
- `temple-part`
- `temple-scenes`
- `templex-mood`
- `templex-obs`
- `templex-part`
- `tomb-baby-spider`
- `target-turret-shot`
- `target-turret`
- `beast-battle-path`
- `des-beast-2`
- `mh-flyer`
- `scorpion-gun`
- `hover-enemy-h`
- `hover-enemy`
- `hover-formation-h`
- `hover-formation`
- `hover-nav-control-h`
- `hover-nav-control`
- `flamer-hover`
- `hover-nav-templea`
- `robo-hover`
- `hover-nav-sewb`
- `hover-nav-sewg`
- `hover-nav-sewj`
- `hover-nav-sewl`
- `hover-nav-sewo`
- `hover-nav-towera`
- `tower-mood`
- `tower-obs`
- `tower-scenes`
- `tower-part`
- `eco-green-collider`
- `forest-bridges`
- `forest-kill-plants`
- `forest-mood`
- `forest-ring-chase`
- `forest-tasks`
- `forest-part`
- `foresta-obs`
- `hover-nav-foresta`
- `mh-plant`
- `dp-bipedal-part`
- `dp-bipedal-shot`
- `dp-bipedal`
- `neo-spawner`
- `for-turret`
- `for-turret-shot`
- `neo-wasp`
- `neo-wasp-part`
- `volcanox-scenes`
- `volcanox-mood`
- `volcano-scenes`
- `volcano-mood`
- `volcano-obs`
- `volcano-obs2`
- `chain-physics`
- `rigid-body-plat`
- `volcano-part`
- `flamer-lava`
- `flitter`
- `spiky-frog`
- `flut-wild`
- `target-indax`
- `target-indax-hang`
- `mantis`
- `volcanox-obs`
- `spyder`
- `wcar-faccar`
- `mhcity-obs2`
- `mhcity-part`
- `mhcity-obs`
- `dm-mine-spider`
- `rapid-gunner`
- `stadium-mood`
- `stadium-scenes`
- `stadiuma-mood`
- `stadiuma-part`
- `kanga-lizard`
- `marauder`
- `arena-scenes`
- `wasstada-mood`
- `wasstada-obs`
- `wasstada-part`
- `wasstadb-obs`
- `wasstadc-obs`
- `dm-flyer`
- `maker-part`
- `maker-projectile`
- `skeet-part`
- `wascity-turret`
- `wasgun-h`
- `wasgun-hud`
- `wasgun-manager`
- `nav-graph-h`
- `traffic-engine-h`
- `waswide-init`
- `cty-borrow-manager-h`
- `cty-borrow-manager`
- `desert-part`
- `height-map-h`
- `height-map`
- `traffic-height-map`
- `vehicle-control`
- `hvehicle-h`
- `hvehicle`
- `hvehicle-effects`
- `hvehicle-physics`
- `hvehicle-util`
- `glider-h`
- `glider-hud`
- `glider-manager`
- `glider-ring`
- `glider-ring-part`
- `h-glider`
- `hanga-init`
- `was-pre-game`
- `was-leaper-race`
- `flut-racer`
- `desert-scenes`
- `desert-lizard-h`
- `desert-lizard-task`
- `desert-lizard`
- `throne-scenes`
- `waspal-mood`
- `waspala-obs`
- `waspala-part`
- `deswalk-obs`
- `deswalk-part`
- `terraformer-drone`
- `terraformer-head`
- `terraformer-part`
- `terraformer-setup`
2024-04-22 18:43:51 +02:00
2595 changed files with 1419748 additions and 343073 deletions

No files matched your search

@@ -32,4 +32,4 @@ cp -r $SOURCE/decompiler/config $DEST/data/decompiler/
cp -r $SOURCE/goal_src $DEST/data
cp -r $SOURCE/game/assets $DEST/data/game/
cp -r $SOURCE/game/graphics/opengl_renderer/shaders $DEST/data/game/graphics/opengl_renderer
cp -r $SOURCE/custom_levels $DEST/data
cp -r $SOURCE/custom_assets $DEST/data
@@ -24,4 +24,4 @@ cp -r $SOURCE/decompiler/config $DEST/data/decompiler/
cp -r $SOURCE/goal_src $DEST/data
cp -r $SOURCE/game/assets $DEST/data/game/
cp -r $SOURCE/game/graphics/opengl_renderer/shaders $DEST/data/game/graphics/opengl_renderer
cp -r $SOURCE/custom_levels $DEST/data
cp -r $SOURCE/custom_assets $DEST/data
+1 -1
View File
@@ -33,7 +33,7 @@ jobs:
libxi-dev zip ninja-build libgl1-mesa-dev libssl-dev
- name: Setup sccache
uses: hendrikmuhs/[email protected]2
uses: hendrikmuhs/[email protected]3
with:
variant: sccache
key: linux-ubuntu-20.04-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
+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]2
uses: hendrikmuhs/[email protected]3
with:
variant: sccache
key: linux-ubuntu-20.04-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
run: arch -arm64 brew install cmake ninja
- name: Setup sccache
uses: hendrikmuhs/[email protected]2
uses: hendrikmuhs/[email protected]3
with:
variant: sccache
key: macos-12-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
run: brew install cmake nasm ninja
- name: Setup sccache
uses: hendrikmuhs/[email protected]2
uses: hendrikmuhs/[email protected]3
with:
variant: sccache
key: macos-12-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
}
- name: Setup sccache
uses: hendrikmuhs/[email protected]2
uses: hendrikmuhs/[email protected]3
with:
variant: sccache
key: windows-2022-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
}
- name: Setup sccache
uses: hendrikmuhs/[email protected]2
uses: hendrikmuhs/[email protected]3
with:
variant: sccache
key: windows-2022-${{ inputs.cachePrefix }}-${{ inputs.cmakePreset }}-${{ github.sha }}
+9 -1
View File
@@ -54,7 +54,14 @@ imgui.ini
node_modules/
# texture replacements
texture_replacements/*
custom_assets/jak1/texture_replacements/*
custom_assets/jak2/texture_replacements/*
custom_assets/jak3/texture_replacements/*
# merc replacements
custom_assets/jak1/merc_replacements/*
custom_assets/jak2/merc_replacements/*
custom_assets/jak3/merc_replacements/*
# generated cmake files
svnrev.h
@@ -76,3 +83,4 @@ __pycache__/
/TODO.md
unifont-15.0.03.ttf
*.diff
goalc-report.html
+147 -34
View File
@@ -7,42 +7,58 @@
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - Unit-Tests - Summary",
"args": ["--gtest_brief=1"]
"args": [
"--gtest_brief=1"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - Unit-Tests - Verbose",
"args": ["--gtest_brief=0"]
"args": [
"--gtest_brief=0"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - Draft Tests - Verbose",
"args": ["--gtest_brief=0", "--gtest_filter=\"*Draft*\""]
"args": [
"--gtest_brief=0",
"--gtest_filter=\"*Draft*\""
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - TypeConsistency - Verbose",
"args": ["--gtest_brief=0", "--gtest_filter=\"*TypeConsistency*\""]
"args": [
"--gtest_brief=0",
"--gtest_filter=\"*TypeConsistency*\""
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - TypeConsistency - Jak 2 - Verbose",
"args": ["--gtest_brief=0", "--gtest_filter=\"*Jak2TypeConsistency*\""]
"args": [
"--gtest_brief=0",
"--gtest_filter=\"*Jak2TypeConsistency*\""
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - WithGameTests - Verbose",
"args": ["--gtest_brief=0", "--gtest_filter=\"*WithGameTests*\""]
"args": [
"--gtest_brief=0",
"--gtest_filter=\"*WithGameTests*\""
]
},
{
"type": "default",
@@ -113,56 +129,109 @@
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - Jak 1 - Runtime",
"args": ["-v", "--game", "jak1", "--", "-fakeiso", "-debug"]
"args": [
"-v",
"--game",
"jak1",
"--",
"-fakeiso",
"-debug"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - Jak 1 - Runtime (boot)",
"args": ["-v", "--game", "jak1", "--", "-boot", "-fakeiso", "-debug"]
"args": [
"-v",
"--game",
"jak1",
"--",
"-boot",
"-fakeiso",
"-debug"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - Jak 2 - Runtime (no boot)",
"args": ["-v", "--game", "jak2", "--", "-fakeiso", "-debug"]
"args": [
"-v",
"--game",
"jak2",
"--",
"-fakeiso",
"-debug"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - Jak 2 - Runtime (boot)",
"args": ["-v", "--game", "jak2", "--", "-boot", "-fakeiso", "-debug"]
"args": [
"-v",
"--game",
"jak2",
"--",
"-boot",
"-fakeiso",
"-debug"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - Jak 2 - Runtime (release)",
"args": ["-v", "--game", "jak2", "--", "-boot", "-fakeiso"]
"args": [
"-v",
"--game",
"jak2",
"--",
"-boot",
"-fakeiso"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "gk.exe (bin\\gk.exe)",
"name": "Game - Jak 3 - Runtime (boot)",
"args": ["-v", "--game", "jak3", "--", "-boot", "-fakeiso", "-debug"]
"args": [
"-v",
"--game",
"jak3",
"--",
"-boot",
"-fakeiso",
"-debug"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc.exe (bin\\goalc.exe)",
"name": "REPL - Jak 1",
"args": ["--user-auto", "--game", "jak1"]
"args": [
"--user-auto",
"--game",
"jak1"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc.exe (bin\\goalc.exe)",
"name": "REPL - Jak 2",
"args": ["--user-auto", "--game", "jak2"]
"args": [
"--user-auto",
"--game",
"jak2"
]
},
{
"type": "default",
@@ -243,19 +312,45 @@
"ntsc_v1"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "decompiler.exe (bin\\decompiler.exe)",
"name": "Decompiler - Jak 3 - Extract",
"args": [
"${workspaceRoot}/decompiler/config/jak3/jak3_config.jsonc",
"${workspaceRoot}/iso_data",
"${workspaceRoot}/decompiler_out",
"--version",
"ntsc_v1",
"--config-override \"{\\\"decompile_code\\\": false, \\\"levels_extract\\\": true, \\\"allowed_objects\\\": []}\""
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "memory_dump_tool.exe (bin\\memory_dump_tool.exe)",
"name": "Tools - EE Memory Analyze - Jak 1",
"args": ["\"${workspaceRoot}/eeMemory.bin\"", "--output-path", "\"${workspaceRoot}\"", "--game", "jak1"]
"args": [
"\"${workspaceRoot}/eeMemory.bin\"",
"--output-path",
"\"${workspaceRoot}\"",
"--game",
"jak1"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "memory_dump_tool.exe (bin\\memory_dump_tool.exe)",
"name": "Tools - EE Memory Analyze - Jak 2",
"args": ["\"${workspaceRoot}/eeMemory.bin\"", "--output-path", "\"${workspaceRoot}\"", "--game", "jak2"]
"args": [
"\"${workspaceRoot}/eeMemory.bin\"",
"--output-path",
"\"${workspaceRoot}\"",
"--game",
"jak2"
]
},
{
"type": "default",
@@ -272,35 +367,53 @@
"project": "CMakeLists.txt",
"projectTarget": "extractor.exe (bin\\extractor.exe)",
"name": "Tools - Extractor - Full",
"args": ["\"E:\\ISOs\\Jak\\Jak 1.iso\""]
"args": [
"\"E:\\ISOs\\Jak\\Jak 1.iso\""
]
},
{
"type" : "default",
"project" : "CMakeLists.txt",
"projectTarget" : "lsp.exe (bin\\lsp.exe)",
"name" : "Tools - LSP",
"args" : []
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "lsp.exe (bin\\lsp.exe)",
"name": "Tools - LSP",
"args": []
},
{
"type" : "default",
"project" : "CMakeLists.txt",
"projectTarget" : "type_searcher.exe (bin\\type_searcher.exe)",
"name" : "Tools - Type Searcher",
"args" : ["--game", "jak2", "--output-path", "./search-results.json", "--size", 255, "--fields", "[{\\\"type\\\":\\\"quaternion\\\",\\\"offset\\\":48}]"]
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "type_searcher.exe (bin\\type_searcher.exe)",
"name": "Tools - Type Searcher",
"args": [
"--game",
"jak2",
"--output-path",
"./search-results.json",
"--size",
255,
"--fields",
"[{\\\"type\\\":\\\"quaternion\\\",\\\"offset\\\":48}]"
]
},
{
"type" : "default",
"project" : "CMakeLists.txt",
"projectTarget" : "formatter.exe (bin\\formatter.exe)",
"name" : "Tools - Formatter - Inplace",
"args" : ["--write", "--file", "C:\\Users\\xtvas\\Repos\\opengoal\\jak-project\\decompiler_out\\jak3\\mood-h_disasm.gc"]
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "formatter.exe (bin\\formatter.exe)",
"name": "Tools - Formatter - Inplace",
"args": [
"--write",
"--file",
"C:\\Users\\xtvas\\Repositories\\opengoal\\jak-project\\goal_src\\jak1\\engine\\camera\\cam-states.gc"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "goalc-test.exe (bin\\goalc-test.exe)",
"name": "Tests - Formatter",
"args": ["--gtest_brief=0", "--gtest_filter=\"*FormatterTests*\""]
"args": [
"--gtest_brief=0",
"--gtest_filter=\"*FormatterTests*\""
]
}
]
}
}
+2 -2
View File
@@ -8,10 +8,10 @@
"name": "run python script",
"type": "python",
"request": "launch",
"program": "${workspaceFolder}/scripts/gsrc/copy-common-naming.py",
"program": "${workspaceFolder}/scripts/gsrc/compare-compilation-outputs.py",
"console": "integratedTerminal",
"cwd": "${workspaceFolder}",
"args": ["--update-names-from-refs", "--decompiler", "./out/build/Release/bin/decompiler"]
"args": []
},
]
}
+6 -1
View File
@@ -101,7 +101,6 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
message(STATUS "AppleClang detected - Setting Defaults")
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} \
-march=native \
-Wall \
-Winit-self \
-ggdb \
@@ -117,6 +116,12 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
-Wsign-promo \
-fdiagnostics-color=always"
)
# pin to AVX for macOS, hopefully all macOS runners have atleast this architecture
# technically speaking, SSE4 is the cutoff for Apple Silicon so...only a matter of time!
if(NOT CMAKE_CXX_COMPILER_TARGET STREQUAL "arm64-apple-darwin")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx")
endif()
# additional c++ flags for release mode for our projects
if(CMAKE_BUILD_TYPE MATCHES "Release")
+5 -3
View File
@@ -51,7 +51,7 @@ add_library(common
repl/config.cpp
repl/nrepl/ReplClient.cpp
repl/nrepl/ReplServer.cpp
repl/util.cpp
repl/repl_wrapper.cpp
serialization/subtitles/subtitles_v1.cpp
serialization/subtitles/subtitles_v2.cpp
serialization/subtitles/subtitles.cpp
@@ -87,9 +87,11 @@ add_library(common
util/term_util.cpp
util/Timer.cpp
util/unicode_util.cpp
versions/versions.cpp)
util/gltf_util.cpp
versions/versions.cpp
)
target_link_libraries(common fmt lzokay replxx libzstd_static tree-sitter sqlite3 libtinyfiledialogs)
target_link_libraries(common fmt lzokay replxx libzstd_static tree-sitter sqlite3 libtinyfiledialogs tiny_gltf)
if(WIN32)
target_link_libraries(common wsock32 ws2_32 windowsapp)
+2 -2
View File
@@ -5,6 +5,8 @@
#include "common/cross_sockets/XSocket.h"
#include "common/log/log.h"
#include "fmt/core.h"
// clang-format off
#ifdef _WIN32
#define NOMINMAX
@@ -13,9 +15,7 @@
#include <WinSock2.h>
#include <WS2tcpip.h>
#endif
#include "common/repl/nrepl/ReplServer.h"
#include "fmt/core.h"
// clang-format on
XSocketClient::XSocketClient(int _tcp_port) {
+12 -4
View File
@@ -35,7 +35,7 @@ void XSocketServer::shutdown_server() {
close_server_socket();
}
bool XSocketServer::init_server() {
bool XSocketServer::init_server(bool failure_may_occur) {
listening_socket = open_socket(AF_INET, SOCK_STREAM, 0);
if (listening_socket < 0) {
listening_socket = -1;
@@ -76,19 +76,27 @@ bool XSocketServer::init_server() {
addr.sin_port = htons(tcp_port);
if (bind(listening_socket, (sockaddr*)&addr, sizeof(addr)) < 0) {
lg::error("[XSocketServer:{}] failed to bind", tcp_port);
if (failure_may_occur) {
lg::debug("[XSocketServer:{}] failed to bind", tcp_port);
} else {
lg::error("[XSocketServer:{}] failed to bind", tcp_port);
}
close_server_socket();
return false;
}
if (listen(listening_socket, 0) < 0) {
lg::error("[XSocketServer:{}] failed to listen", tcp_port);
if (failure_may_occur) {
lg::debug("[XSocketServer:{}] failed to listen", tcp_port);
} else {
lg::error("[XSocketServer:{}] failed to listen", tcp_port);
}
close_server_socket();
return false;
}
server_initialized = true;
lg::info("[XSocketServer:{}] initialized", tcp_port);
lg::debug("[XSocketServer:{}] initialized", tcp_port);
post_init();
return true;
}
+1 -1
View File
@@ -20,7 +20,7 @@ class XSocketServer {
XSocketServer(const XSocketServer&) = delete;
XSocketServer& operator=(const XSocketServer&) = delete;
bool init_server();
bool init_server(bool failure_may_occur = false);
void shutdown_server();
void close_server_socket();
+54 -10
View File
@@ -9,10 +9,16 @@
#include "third-party/sse2neon/sse2neon.h"
#endif
#include "common/log/log.h"
#include "common/util/Assert.h"
namespace tfrag3 {
void PackedTimeOfDay::serialize(Serializer& ser) {
ser.from_pod_vector(&data);
ser.from_ptr(&color_count);
}
void PackedTieVertices::serialize(Serializer& ser) {
ser.from_pod_vector(&color_indices);
ser.from_pod_vector(&matrices);
@@ -71,10 +77,9 @@ void TfragTree::serialize(Serializer& ser) {
draw.serialize(ser);
}
// ser.from_pod_vector(&vertices);
ser.from_pod_vector(&packed_vertices.vertices);
ser.from_pod_vector(&packed_vertices.cluster_origins);
ser.from_pod_vector(&colors);
colors.serialize(ser);
bvh.serialize(ser);
ser.from_ptr(&use_strips);
}
@@ -398,7 +403,7 @@ void TieTree::serialize(Serializer& ser) {
}
packed_vertices.serialize(ser);
ser.from_pod_vector(&colors);
colors.serialize(ser);
bvh.serialize(ser);
ser.from_ptr(&has_per_proto_visibility_toggle);
@@ -406,7 +411,7 @@ void TieTree::serialize(Serializer& ser) {
}
void ShrubTree::serialize(Serializer& ser) {
ser.from_pod_vector(&time_of_day_colors);
time_of_day_colors.serialize(ser);
ser.from_pod_vector(&indices);
packed_vertices.serialize(ser);
if (ser.is_saving()) {
@@ -422,6 +427,30 @@ void ShrubTree::serialize(Serializer& ser) {
ser.from_string_vector(&proto_names);
}
void HfragmentBucket::serialize(Serializer& ser) {
ser.from_pod_vector(&corners);
ser.from_ptr(&montage_table);
}
void Hfragment::serialize(Serializer& ser) {
ser.from_pod_vector(&vertices);
ser.from_pod_vector(&indices);
ser.from_pod_vector(&corners);
if (ser.is_saving()) {
ser.save<size_t>(buckets.size());
} else {
buckets.resize(ser.load<size_t>());
}
for (auto& x : buckets) {
x.serialize(ser);
}
time_of_day_colors.serialize(ser);
ser.from_ptr(&wang_tree_tex_id);
ser.from_ptr(&draw_mode);
ser.from_ptr(&occlusion_offset);
}
void BVH::serialize(Serializer& ser) {
ser.from_ptr(&first_leaf_node);
ser.from_ptr(&last_leaf_node);
@@ -463,6 +492,7 @@ void MercDraw::serialize(Serializer& ser) {
ser.from_ptr(&first_index);
ser.from_ptr(&index_count);
ser.from_ptr(&num_triangles);
ser.from_ptr(&no_strip);
}
void Blerc::serialize(Serializer& ser) {
@@ -604,6 +634,8 @@ void Level::serialize(Serializer& ser) {
tree.serialize(ser);
}
hfrag.serialize(ser);
collision.serialize(ser);
merc_data.serialize(ser);
@@ -654,8 +686,7 @@ void PackedShrubVertices::memory_usage(MemoryUsageTracker* tracker) const {
}
void ShrubTree::memory_usage(MemoryUsageTracker* tracker) const {
tracker->add(MemoryUsageCategory::SHRUB_TIME_OF_DAY,
sizeof(TimeOfDayColor) * time_of_day_colors.size());
tracker->add(MemoryUsageCategory::SHRUB_TIME_OF_DAY, sizeof(u8) * time_of_day_colors.data.size());
packed_vertices.memory_usage(tracker);
tracker->add(MemoryUsageCategory::SHRUB_DRAW, sizeof(ShrubDraw) * static_draws.size());
tracker->add(MemoryUsageCategory::SHRUB_IND, sizeof(u32) * indices.size());
@@ -683,7 +714,7 @@ void TieTree::memory_usage(MemoryUsageTracker* tracker) const {
draw.vis_groups.size() * sizeof(StripDraw::VisGroup));
}
packed_vertices.memory_usage(tracker);
tracker->add(MemoryUsageCategory::TIE_TIME_OF_DAY, sizeof(TimeOfDayColor) * colors.size());
tracker->add(MemoryUsageCategory::TIE_TIME_OF_DAY, sizeof(u8) * colors.data.size());
for (auto& draw : instanced_wind_draws) {
draw.memory_usage(tracker);
@@ -707,7 +738,7 @@ void TfragTree::memory_usage(MemoryUsageTracker* tracker) const {
draw.vis_groups.size() * sizeof(StripDraw::VisGroup));
}
packed_vertices.memory_usage(tracker);
tracker->add(MemoryUsageCategory::TFRAG_TIME_OF_DAY, sizeof(TimeOfDayColor) * colors.size());
tracker->add(MemoryUsageCategory::TFRAG_TIME_OF_DAY, sizeof(u8) * colors.data.size());
tracker->add(MemoryUsageCategory::TFRAG_BVH, sizeof(VisNode) * bvh.vis_nodes.size());
}
@@ -720,6 +751,13 @@ void IndexTexture::memory_usage(MemoryUsageTracker* tracker) const {
tracker->add(MemoryUsageCategory::SPECIAL_TEXTURE, 256 * 4); // clut
}
void Hfragment::memory_usage(tfrag3::MemoryUsageTracker* tracker) const {
tracker->add(MemoryUsageCategory::HFRAG_VERTS, vertices.size() * sizeof(HfragmentVertex));
tracker->add(MemoryUsageCategory::HFRAG_INDEX, indices.size() * sizeof(u32));
tracker->add(MemoryUsageCategory::HFRAG_TIME_OF_DAY, time_of_day_colors.data.size() * sizeof(u8));
tracker->add(MemoryUsageCategory::HFRAG_CORNERS, corners.size() * sizeof(HfragmentCorner));
}
void Level::memory_usage(MemoryUsageTracker* tracker) const {
for (const auto& texture : textures) {
texture.memory_usage(tracker);
@@ -740,6 +778,7 @@ void Level::memory_usage(MemoryUsageTracker* tracker) const {
for (const auto& tree : shrub_trees) {
tree.memory_usage(tracker);
}
hfrag.memory_usage(tracker);
collision.memory_usage(tracker);
merc_data.memory_usage(tracker);
}
@@ -783,6 +822,11 @@ void print_memory_usage(const tfrag3::Level& lev, int uncompressed_data_size) {
{"merc-mod-draw-1", mem_use.data[tfrag3::MemoryUsageCategory::MERC_MOD_DRAW_1]},
{"merc-mod-draw-2", mem_use.data[tfrag3::MemoryUsageCategory::MERC_MOD_DRAW_2]},
{"blerc", mem_use.data[tfrag3::MemoryUsageCategory::BLERC]},
{"hfrag-verts", mem_use.data[tfrag3::MemoryUsageCategory::HFRAG_VERTS]},
{"hfrag-index", mem_use.data[tfrag3::MemoryUsageCategory::HFRAG_INDEX]},
{"hfrag-time-of-day", mem_use.data[tfrag3::MemoryUsageCategory::HFRAG_TIME_OF_DAY]},
{"hfrag-corners", mem_use.data[tfrag3::MemoryUsageCategory::HFRAG_CORNERS]}
};
for (auto& known : known_categories) {
total_accounted += known.second;
@@ -795,8 +839,8 @@ void print_memory_usage(const tfrag3::Level& lev, int uncompressed_data_size) {
for (const auto& x : known_categories) {
if (x.second) {
fmt::print("{:30s} : {:6d} kB {:3.1f}%\n", x.first, x.second / 1024,
100.f * (float)x.second / uncompressed_data_size);
lg::print("{:30s} : {:6d} kB {:3.1f}%\n", x.first, x.second / 1024,
100.f * (float)x.second / uncompressed_data_size);
}
}
}
+66 -16
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 = 39;
constexpr int TFRAG3_VERSION = 41;
enum MemoryUsageCategory {
TEXTURE,
@@ -61,6 +61,11 @@ enum MemoryUsageCategory {
MERC_MOD_TABLE,
BLERC,
HFRAG_VERTS,
HFRAG_INDEX,
HFRAG_TIME_OF_DAY,
HFRAG_CORNERS,
COLLISION,
NUM_CATEGORIES
@@ -269,18 +274,23 @@ struct BVH {
void serialize(Serializer& ser);
};
// A time-of-day color. Each stores 8 colors. At a given "time of day", they are interpolated
// to find a single color which goes into a color palette.
struct TimeOfDayColor {
math::Vector<u8, 4> rgba[8];
// This is split into groups of 4 colors.
// The data in these groups is stored first by palette, then color, then channel.
struct PackedTimeOfDay {
std::vector<u8> data;
u32 color_count = 0;
void serialize(Serializer& ser);
bool operator==(const TimeOfDayColor& other) const {
for (size_t i = 0; i < 8; i++) {
if (rgba[i] != other.rgba[i]) {
return false;
}
}
return true;
u8 read(int color, int palette, int channel) const {
const int color_quad = color / 4;
const int color_in_quad = color % 4;
return data[color_quad * 4 * 4 * 8 + palette * 4 * 4 + color_in_quad * 4 + channel];
}
u8& read(int color, int palette, int channel) {
const int color_quad = color / 4;
const int color_in_quad = color % 4;
return data[color_quad * 4 * 4 * 8 + palette * 4 * 4 + color_in_quad * 4 + channel];
}
};
@@ -319,8 +329,8 @@ struct TfragTree {
TFragmentTreeKind kind; // our tfrag kind
std::vector<StripDraw> draws; // the actual topology and settings
PackedTfragVertices packed_vertices;
std::vector<TimeOfDayColor> colors; // vertex colors (pre-interpolation)
BVH bvh; // the bvh for frustum culling
PackedTimeOfDay colors; // vertex colors (pre-interpolation)
BVH bvh; // the bvh for frustum culling
bool use_strips = true;
struct {
@@ -401,7 +411,7 @@ struct TieTree {
std::array<u32, kNumTieCategories + 1> category_draw_indices;
PackedTieVertices packed_vertices;
std::vector<TimeOfDayColor> colors; // vertex colors (pre-interpolation)
PackedTimeOfDay colors; // vertex colors (pre-interpolation)
std::vector<InstancedStripDraw> instanced_wind_draws;
std::vector<TieWindInstance> wind_instance_info;
@@ -422,7 +432,7 @@ struct TieTree {
struct ShrubTree {
// todo some visibility structure
std::vector<TimeOfDayColor> time_of_day_colors; // multiplier colors
PackedTimeOfDay time_of_day_colors; // multiplier colors
PackedShrubVertices packed_vertices;
std::vector<ShrubDraw> static_draws; // the actual topology and settings
@@ -441,6 +451,43 @@ struct ShrubTree {
void unpack();
};
struct HfragmentVertex {
float height = 0;
u32 vi = 0;
u16 color_index = 0;
u8 u = 0, v = 0;
u32 pad = 0;
};
struct HfragmentCorner {
math::Vector<float, 4> bsphere;
u32 vis_id = 0;
u32 index_start = 0;
u32 index_length = 0;
u32 num_tris = 0;
};
struct HfragmentBucket {
std::vector<u32> corners;
std::array<u16, 16> montage_table;
void serialize(Serializer& ser);
};
struct Hfragment {
std::vector<HfragmentVertex> vertices;
std::vector<u32> indices;
std::vector<HfragmentCorner> corners;
std::vector<HfragmentBucket> buckets;
PackedTimeOfDay time_of_day_colors;
std::array<s32, 4> wang_tree_tex_id;
DrawMode draw_mode;
u32 occlusion_offset;
void serialize(Serializer& ser);
void memory_usage(MemoryUsageTracker* tracker) const;
};
struct CollisionMesh {
struct Vertex {
float x, y, z;
@@ -483,6 +530,8 @@ struct MercDraw {
u32 first_index;
u32 index_count;
u32 num_triangles;
// no strip hack for custom models
bool no_strip = false;
void serialize(Serializer& ser);
};
@@ -566,6 +615,7 @@ struct Level {
std::array<std::vector<TfragTree>, TFRAG_GEOS> tfrag_trees;
std::array<std::vector<TieTree>, TIE_GEOS> tie_trees;
std::vector<ShrubTree> shrub_trees;
Hfragment hfrag;
CollisionMesh collision;
MercModelGroup merc_data;
u16 version2 = TFRAG3_VERSION;
+2 -2
View File
@@ -4,7 +4,7 @@
#include "fmt/core.h"
std::string DmaTag::print() {
std::string DmaTag::print() const {
std::string result;
const char* mode_names[8] = {"refe", "cnt", "next", "ref", "refs", "call", "ret", "end"};
result += fmt::format("TAG: 0x{:08x} {:4s} qwc 0x{:04x}", addr, mode_names[(int)kind], qwc);
@@ -15,7 +15,7 @@ std::string DmaTag::print() {
return result;
}
std::string VifCode::print() {
std::string VifCode::print() const {
std::string result;
switch (kind) {
+2 -2
View File
@@ -52,7 +52,7 @@ struct DmaTag {
bool operator!=(const DmaTag& other) const { return !((*this) == other); }
std::string print();
std::string print() const;
};
inline void emulate_dma(const void* source_base, void* dest_base, u32 tadr, u32 dadr) {
@@ -148,7 +148,7 @@ struct VifCode {
u16 num;
u16 immediate;
std::string print();
std::string print() const;
};
struct VifCodeStcycl {
-1
View File
@@ -12,7 +12,6 @@ Also in general I found it _really_ hard to find modern and easy to understand a
Atleast for me, it helps to understand the path code takes as it flows through the formatting process. Originally I tried to do as much at once for sake of efficiency but this just makes things incredibly hard to reason about and fix bugs. So like any problem that is complex, break it down, the formatter goes through many distinct phases chipping away at the problem:
```mermaid
%%{init: {'theme': 'dark', "flowchart" : { "curve" : "basis" } } }%%
flowchart TB
subgraph top1 [Build a Formatting Tree]
direction TB
+90 -26
View File
@@ -33,14 +33,16 @@ int hang_indentation_width(const FormatterTreeNode& curr_node) {
return 1 + hang_indentation_width(first_elt);
}
// TODO - this doesn't account for paren's width contribution!
int get_total_form_inlined_width(const FormatterTreeNode& curr_node) {
if (curr_node.token) {
return curr_node.token->length();
}
int width = 1;
for (const auto& ref : curr_node.refs) {
width += get_total_form_inlined_width(ref);
for (int i = 0; i < curr_node.refs.size(); i++) {
width += get_total_form_inlined_width(curr_node.refs.at(i));
if (i != curr_node.refs.size() - 1) {
width += 1; // add the space between elements
}
}
return width + 1;
}
@@ -49,7 +51,9 @@ int get_total_form_inlined_width(const FormatterTreeNode& curr_node) {
void apply_formatting_config(
FormatterTreeNode& curr_node,
std::optional<std::shared_ptr<formatter_rules::config::FormFormattingConfig>>
config_from_parent = {}) {
config_from_parent = {},
std::optional<std::shared_ptr<formatter_rules::config::FormFormattingConfig>>
config_merge_from_parent = {}) {
using namespace formatter_rules;
// node is empty, base-case
if (curr_node.token || curr_node.refs.empty()) {
@@ -65,6 +69,13 @@ void apply_formatting_config(
predefined_config = config::opengoal_form_config.at(form_head.value());
curr_node.formatting_config = predefined_config.value();
}
if (config_merge_from_parent) {
const auto& merge_config = *config_merge_from_parent.value();
curr_node.formatting_config.parent_mutable_extra_indent +=
merge_config.parent_mutable_extra_indent;
curr_node.formatting_config.prevent_inlining = merge_config.prevent_inlining;
}
} else if (config_from_parent) {
// TODO - doesn't merge just replaces, a bit inflexible
predefined_config = *config_from_parent.value();
@@ -104,7 +115,7 @@ void apply_formatting_config(
if (curr_node.formatting_config.has_constant_pairs) {
for (int i = 0; i < (int)curr_node.refs.size(); i++) {
auto& child_ref = curr_node.refs.at(i);
const auto type = child_ref.metadata.node_type;
const auto& type = child_ref.metadata.node_type;
if (constant_types.find(type) == constant_types.end() &&
constant_pairs::is_element_second_in_constant_pair(curr_node, child_ref, i)) {
child_ref.formatting_config.parent_mutable_extra_indent = 2;
@@ -129,13 +140,16 @@ void apply_formatting_config(
auto& ref = curr_node.refs.at(i);
if (!ref.token) {
// If the child has a pre-defined configuration at that index, we pass it along
if (predefined_config &&
predefined_config->index_configs.find(i) != predefined_config->index_configs.end()) {
apply_formatting_config(ref, predefined_config->index_configs.at(i));
if (predefined_config && predefined_config->index_config_override.find(i) !=
predefined_config->index_config_override.end()) {
apply_formatting_config(ref, {}, predefined_config->index_config_override.at(i));
} else if (predefined_config && predefined_config->index_configs.find(i) !=
predefined_config->index_configs.end()) {
apply_formatting_config(ref, predefined_config->index_configs.at(i), {});
} else if (predefined_config && predefined_config->default_index_config) {
apply_formatting_config(ref, predefined_config->default_index_config);
apply_formatting_config(ref, predefined_config->default_index_config, {});
} else {
apply_formatting_config(ref);
apply_formatting_config(ref, {}, {});
}
}
}
@@ -151,10 +165,27 @@ void apply_formatting_config(
max_columns = field.refs.size();
}
}
// if only one field has a value in the max col position, it looks weird for it to be indented
bool ignore_final_column_width = true;
int fields_with_atleast_max_col = 0;
for (const auto& field : curr_node.refs) {
if ((int)field.refs.size() == max_columns) {
fields_with_atleast_max_col++;
if (fields_with_atleast_max_col > 1) {
ignore_final_column_width = false;
break;
}
}
}
// Now find the column max widths
std::vector<int> column_max_widths = {};
for (int col = 0; col < max_columns; col++) {
column_max_widths.push_back(0);
// -2 because its the indentation before the final column that we want to skip
if (col >= curr_node.formatting_config.num_columns_to_compute_widths ||
(ignore_final_column_width && col == max_columns - 2)) {
continue;
}
for (const auto& field : curr_node.refs) {
if ((int)field.refs.size() > col) {
const auto width = get_total_form_inlined_width(field.refs.at(col));
@@ -202,6 +233,10 @@ bool form_contains_node_that_prevents_inlining(const FormatterTreeNode& curr_nod
bool can_node_be_inlined(const FormatterTreeNode& curr_node, int cursor_pos) {
using namespace formatter_rules;
if (curr_node.formatting_config.force_inline) {
// Ensure there are no comments, this still trumps this
if (form_contains_comment(curr_node)) {
return false;
}
return true;
}
// First off, we cannot inline the top level
@@ -264,13 +299,15 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
// Add new line entry
if (ref.token) {
// Cleanup block-comments
std::string val = ref.token_str();
if (ref.metadata.node_type == "block_comment") {
// TODO - change this sanitization to return a list of lines instead of a single new-lined
// line
val = comments::format_block_comment(ref.token_str());
const auto comment_lines = comments::format_block_comment(ref.token_str());
for (const auto& line : comment_lines) {
form_lines.push_back(line);
}
} else {
form_lines.push_back(ref.token_str());
}
form_lines.push_back(val);
if (!curr_node.metadata.is_top_level && i == (int)curr_node.refs.size() - 1 &&
(ref.metadata.is_comment)) {
// if there's an inline comment at the end of a form, we have to force the paren to the next
@@ -292,26 +329,41 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
if (i == (int)curr_node.refs.size() - 1 && form_lines.size() > 1 &&
(curr_node.formatting_config.hang_forms ||
curr_node.formatting_config.combine_first_two_lines)) {
form_lines.at(0) += fmt::format(" {}", form_lines.at(1));
form_lines.at(0) += fmt::format(" {}", str_util::ltrim(form_lines.at(1)));
form_lines.erase(form_lines.begin() + 1);
} else if ((i + 1) < (int)curr_node.refs.size()) {
const auto& next_ref = curr_node.refs.at(i + 1);
// combine the next inline comment or constant pair
if ((next_ref.metadata.node_type == "comment" && next_ref.metadata.is_inline) ||
(curr_node.formatting_config.has_constant_pairs &&
constant_pairs::is_element_second_in_constant_pair(curr_node, next_ref, i + 1))) {
constant_pairs::is_element_second_in_constant_pair(curr_node, next_ref, i + 1)) ||
constant_pairs::is_element_second_in_constant_pair_new(curr_node.refs.at(i), next_ref)) {
// TODO
// has issues with not consolidating first lines, this should probably just be moved to
// outside this loop for simplicity, do it later
if (next_ref.token) {
form_lines.at(form_lines.size() - 1) += fmt::format(" {}", next_ref.token.value());
form_lines.at(form_lines.size() - 1) += fmt::format(" {}", next_ref.token_str());
i++;
// We have to handle hang-consolidation here or else it will never be reached above!
if (i == (int)curr_node.refs.size() - 1 && form_lines.size() > 1 &&
(curr_node.formatting_config.hang_forms ||
curr_node.formatting_config.combine_first_two_lines)) {
form_lines.at(0) += fmt::format(" {}", form_lines.at(1));
form_lines.erase(form_lines.begin() + 1);
}
} else if (can_node_be_inlined(next_ref, cursor_pos)) {
const auto& lines = apply_formatting(next_ref, {}, cursor_pos); // TODO - cursor pos
for (const auto& line : lines) {
form_lines.at(form_lines.size() - 1) += fmt::format(" {}", line);
}
i++;
// We have to handle hang-consolidation here or else it will never be reached above!
if (i == (int)curr_node.refs.size() - 1 && form_lines.size() > 1 &&
(curr_node.formatting_config.hang_forms ||
curr_node.formatting_config.combine_first_two_lines)) {
form_lines.at(0) += fmt::format(" {}", form_lines.at(1));
form_lines.erase(form_lines.begin() + 1);
}
}
if (!curr_node.metadata.is_top_level && next_ref.metadata.node_type == "comment" &&
(i + 1) == (int)curr_node.refs.size()) {
@@ -328,7 +380,9 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
// Consolidate any lines if the configuration requires it
// TODO there is a hack here so that multi-line forms that are consolidated still line up properly
// i have to make consolidate a more first-class feature of the config
if (curr_node.formatting_config.inline_until_index(form_lines)) {
// TODO - hacky, but prevents a bad situation, clean up
if (curr_node.formatting_config.inline_until_index(form_lines) &&
!str_util::contains(form_lines.at(0), ";")) {
std::vector<std::string> new_form_lines = {};
const auto original_form_head_width = str_util::split(form_lines.at(0), '\n').at(0).length();
bool consolidating_lines = true;
@@ -374,22 +428,32 @@ std::vector<std::string> apply_formatting(const FormatterTreeNode& curr_node,
form_lines[form_lines.size() - 1] =
fmt::format("{}{}", form_lines[form_lines.size() - 1], form_surround_end);
}
std::string curr_form = "";
if (curr_node.formatting_config.parent_mutable_extra_indent > 0) {
curr_form += str_util::repeat(curr_node.formatting_config.parent_mutable_extra_indent, " ");
}
if (inline_form) {
form_lines = {fmt::format("{}", fmt::join(form_lines, " "))};
// NOTE - not sure about this, if we are inlining a form, it always makes sense to eliminate
// trailing whitespace the only issue i can foresee is related to strings that span multiple
// lines.
std::vector<std::string> new_form_lines = {};
for (const auto& form_line : form_lines) {
new_form_lines.push_back(str_util::ltrim(form_line));
}
form_lines = {fmt::format("{}", fmt::join(new_form_lines, " "))};
} else {
bool currently_in_block_comment = false;
for (int i = 0; i < (int)form_lines.size(); i++) {
if (i > 0) {
auto& line = form_lines.at(i);
auto& line = form_lines.at(i);
if (str_util::contains(line, "|#")) {
currently_in_block_comment = false;
}
if (i > 0 && !currently_in_block_comment) {
line = fmt::format("{}{}",
str_util::repeat(curr_node.formatting_config.indentation_width_for_index(
curr_node.formatting_config, i),
" "),
line);
}
if (str_util::contains(line, "#|") && !str_util::contains(line, "|#")) {
currently_in_block_comment = true;
}
}
}
return form_lines;
+41 -11
View File
@@ -79,18 +79,18 @@ FormatterTree::FormatterTree(const std::string& source, const TSNode& root_node)
}
const std::unordered_map<std::string, std::vector<std::string>> node_type_ignorable_contents = {
{"list_lit", {"(", ")"}},
{"quoting_lit", {"'"}},
{"unquoting_lit", {","}},
{"quasi_quoting_lit", {"`"}}};
{"list_lit", {"(", ")"}}};
// TODO make an imperative version eventually
// TODO - cleanup duplication
void FormatterTree::construct_formatter_tree_recursive(const std::string& source,
TSNode curr_node,
FormatterTreeNode& tree_node,
std::optional<std::string> node_prefix) {
if (ts_node_child_count(curr_node) == 0) {
tree_node.refs.push_back(FormatterTreeNode(source, curr_node));
auto new_node = FormatterTreeNode(source, curr_node);
new_node.node_prefix = node_prefix;
tree_node.refs.push_back(new_node);
return;
}
const std::string curr_node_type = ts_node_type(curr_node);
@@ -105,11 +105,37 @@ void FormatterTree::construct_formatter_tree_recursive(const std::string& source
tree_node.refs.push_back(FormatterTreeNode(source, curr_node));
return;
} else if (curr_node_type == "quoting_lit") {
next_node_prefix = "'";
if (node_prefix) {
node_prefix.value() += "'";
} else {
node_prefix = "'";
}
construct_formatter_tree_recursive(source, ts_node_child(curr_node, 1), tree_node, node_prefix);
return;
} else if (curr_node_type == "unquoting_lit") {
next_node_prefix = ",";
if (node_prefix) {
node_prefix.value() += ",";
} else {
node_prefix = ",";
}
construct_formatter_tree_recursive(source, ts_node_child(curr_node, 1), tree_node, node_prefix);
return;
} else if (curr_node_type == "quasi_quoting_lit") {
next_node_prefix = "`";
if (node_prefix) {
node_prefix.value() += "`";
} else {
node_prefix = "`";
}
construct_formatter_tree_recursive(source, ts_node_child(curr_node, 1), tree_node, node_prefix);
return;
} else if (curr_node_type == "unquote_splicing_lit") {
if (node_prefix) {
node_prefix.value() += ",@";
} else {
node_prefix = ",@";
}
construct_formatter_tree_recursive(source, ts_node_child(curr_node, 1), tree_node, node_prefix);
return;
}
std::vector<std::string> skippable_nodes = {};
if (node_type_ignorable_contents.find(curr_node_type) != node_type_ignorable_contents.end()) {
@@ -117,6 +143,7 @@ void FormatterTree::construct_formatter_tree_recursive(const std::string& source
}
for (size_t i = 0; i < ts_node_child_count(curr_node); i++) {
const auto child_node = ts_node_child(curr_node, i);
auto debug_child = ts_node_string(child_node);
const auto contents = get_source_code(source, child_node);
bool skip_node = false;
for (const auto& skippable_content : skippable_nodes) {
@@ -129,19 +156,22 @@ void FormatterTree::construct_formatter_tree_recursive(const std::string& source
continue;
}
if (curr_node_type == "list_lit") {
construct_formatter_tree_recursive(source, child_node, list_node, next_node_prefix);
construct_formatter_tree_recursive(source, child_node, list_node, {});
if (node_prefix) {
list_node.node_prefix = node_prefix;
}
} else {
construct_formatter_tree_recursive(source, child_node, tree_node, next_node_prefix);
// TODO - im not sure if this is correct
construct_formatter_tree_recursive(source, child_node, tree_node, node_prefix);
if (node_prefix && !tree_node.refs.empty()) {
tree_node.refs.at(tree_node.refs.size() - 1).node_prefix = node_prefix;
}
}
}
if (curr_node_type == "list_lit") {
// special case for empty lists
if (node_prefix && !list_node.node_prefix) {
list_node.node_prefix = node_prefix;
}
tree_node.refs.push_back(list_node);
}
}
+69 -8
View File
@@ -12,12 +12,16 @@ namespace formatter_rules {
// differentiate between a quoted symbol and a quoted form
const std::set<std::string> constant_types = {"kwd_lit", "num_lit", "str_lit",
"char_lit", "null_lit", "bool_lit"};
const std::set<std::string> constant_type_forms = {"meters", "seconds", "degrees"};
namespace constant_list {
bool is_constant_list(const FormatterTreeNode& node) {
if (!node.is_list() || node.refs.empty()) {
return false;
}
if (!node.refs.at(0).token) {
return true;
}
const auto& type = node.refs.at(0).metadata.node_type;
return constant_types.find(type) != constant_types.end();
}
@@ -36,21 +40,28 @@ bool should_insert_blank_line(const FormatterTreeNode& containing_node,
if (node.metadata.is_comment && node.metadata.num_blank_lines_following == 0) {
return false;
}
// If the next form is a comment and is inline, don't insert a comment
// If the next form is a comment and is inline, don't insert a new line
if ((index + 1) < (int)containing_node.refs.size() &&
containing_node.refs.at(index + 1).metadata.is_comment &&
containing_node.refs.at(index + 1).metadata.is_inline) {
return false;
}
// TODO - only if the form doesn't fit on a single line
if (node.formatting_config.elide_top_level_newline) {
if ((index + 1) < (int)containing_node.refs.size() &&
containing_node.refs.at(index + 1).metadata.is_comment) {
return true;
}
return false;
}
return true;
}
} // namespace blank_lines
namespace comments {
std::string format_block_comment(const std::string& comment) {
std::vector<std::string> format_block_comment(const std::string& comment) {
// Normalize block comments, remove any trailing or leading whitespace
// Only allow annotations on the first line, like #|@file
// Don't mess with internal indentation as the user might intend it to be a certain way.
@@ -71,12 +82,22 @@ std::string format_block_comment(const std::string& comment) {
// Remove trailing whitespace
comment_contents = str_util::rtrim(comment_contents);
// remove |#
// TODO - check suffix
comment_contents.pop_back();
comment_contents.pop_back();
if (str_util::ends_with(comment_contents, "|#")) {
comment_contents.pop_back();
comment_contents.pop_back();
}
comment_contents = str_util::rtrim(comment_contents);
new_comment += fmt::format("\n{}\n|#", comment_contents);
return new_comment;
std::vector<std::string> lines = {new_comment};
const auto contents_as_lines = str_util::split_string(comment_contents, "\n");
if (contents_as_lines.size() > 1) {
for (const auto& line : contents_as_lines) {
lines.push_back(line);
}
lines.push_back("|#");
} else {
lines.at(0) = fmt::format("{} {} |#", new_comment, str_util::trim(contents_as_lines.at(0)));
}
return lines;
}
} // namespace comments
@@ -101,6 +122,46 @@ bool is_element_second_in_constant_pair(const FormatterTreeNode& containing_node
return true;
}
// TODO - potentially remove the above
bool is_element_second_in_constant_pair_new(const FormatterTreeNode& prev_node,
const FormatterTreeNode& curr_node) {
if (prev_node.metadata.node_type == "kwd_lit") {
// Handle standard constant types
// TODO - pair up sym_names as well
if (constant_types.find(curr_node.metadata.node_type) != constant_types.end()) {
if (curr_node.metadata.node_type != "kwd_lit") {
// NOTE - there is ambiugity here which cannot be totally solved (i think?)
// if the element itself is also a keyword, assume this is two adjacent keywords and they
// should not be paired
return true;
}
}
// Quoted symbols
if (curr_node.metadata.node_type == "sym_name" && curr_node.node_prefix &&
(curr_node.node_prefix.value() == "'" || curr_node.node_prefix.value() == ",")) {
return true;
}
if (!curr_node.refs.empty()) {
// Constant forms special cases (ie. meters)
if (constant_type_forms.find(curr_node.refs.at(0).token_str()) != constant_type_forms.end()) {
return true;
}
// If they are just a list of symbol names (enum or simple method call)
bool all_symbols = true;
for (const auto& ref : curr_node.refs) {
if (ref.metadata.node_type != "sym_name") {
all_symbols = false;
break;
}
}
if (all_symbols) {
return true;
}
}
}
return false;
}
bool form_should_be_constant_paired(const FormatterTreeNode& node) {
// Criteria for a list to be constant paired:
// - needs to start with a non-symbol
+3 -1
View File
@@ -36,7 +36,7 @@ bool should_insert_blank_line(const FormatterTreeNode& containing_node,
//
// Reference - https://github.com/kkinnear/zprint/blob/main/doc/options/comments.md
namespace comments {
std::string format_block_comment(const std::string& comment);
std::vector<std::string> format_block_comment(const std::string& comment);
}
// Paired elements in a list will be kept in-line rather than the default new-line indentation
@@ -72,6 +72,8 @@ const static int min_pair_amount = 4;
bool is_element_second_in_constant_pair(const FormatterTreeNode& containing_node,
const FormatterTreeNode& node,
const int index);
bool is_element_second_in_constant_pair_new(const FormatterTreeNode& prev_node,
const FormatterTreeNode& curr_node);
bool form_should_be_constant_paired(const FormatterTreeNode& node);
} // namespace constant_pairs
+202 -8
View File
@@ -1,24 +1,146 @@
#include "rule_config.h"
#include "common/util/string_util.h"
namespace formatter_rules {
namespace config {
static FormFormattingConfig new_inlinable_simple_flow_rule() {
return {.config_set = true, .hang_forms = false};
}
static FormFormattingConfig new_permissive_flow_rule() {
return {.config_set = true, .hang_forms = false, .combine_first_two_lines = true};
}
static FormFormattingConfig new_flow_rule(int start_index) {
static FormFormattingConfig new_flow_rule(int start_index, bool has_constant_pairs = false) {
return {.config_set = true,
.hang_forms = false,
.inline_until_index = [start_index](const std::vector<std::string>& /*curr_lines*/) {
return start_index;
}};
.inline_until_index =
[start_index](const std::vector<std::string>& /*curr_lines*/) { return start_index; },
.has_constant_pairs = has_constant_pairs};
}
static FormFormattingConfig new_function_rule(int start_index, bool has_constant_pairs = false) {
FormFormattingConfig cfg = {
.config_set = true,
.hang_forms = false,
.inline_until_index =
[start_index](const std::vector<std::string>& /*curr_lines*/) { return start_index; },
.has_constant_pairs = has_constant_pairs};
auto arg_list_config = std::make_shared<FormFormattingConfig>();
arg_list_config->force_inline = true;
arg_list_config->hang_forms = false;
cfg.index_configs.emplace(2, arg_list_config);
return cfg;
}
static FormFormattingConfig new_inlineable_flow_rule(int start_index,
bool has_constant_pairs = false) {
return {.config_set = true,
.hang_forms = false,
.inline_until_index =
[start_index](const std::vector<std::string>& curr_lines) {
int total_width = 0;
for (const auto& line : curr_lines) {
// Check for comments
// TODO - this shows how this isn't really the best strategy but it holds up
if (str_util::contains(line, ";")) {
// Can't inline, there's a comment!
return start_index;
}
total_width += line.length();
// an empty line implies a new-line was forced, this is bleeding implementation
// details, but fine for now
if (line.empty()) {
return start_index;
}
}
if (total_width <= 120) {
return (int)curr_lines.size();
}
return start_index;
},
.has_constant_pairs = has_constant_pairs};
}
static FormFormattingConfig new_defstate_rule(int start_index, bool has_constant_pairs = false) {
FormFormattingConfig cfg = {
.config_set = true,
.hang_forms = false,
.inline_until_index =
[start_index](const std::vector<std::string>& /*curr_lines*/) { return start_index; },
.has_constant_pairs = has_constant_pairs};
std::vector<int> state_handler_indexes = {4, 6, 8, 10,
12, 14}; // NOTE - not all of these have to be defined
for (const auto& index : state_handler_indexes) {
auto temp_config = std::make_shared<FormFormattingConfig>();
temp_config->prevent_inlining = true;
temp_config->parent_mutable_extra_indent = 2;
cfg.index_config_override.emplace(index, temp_config);
}
return cfg;
}
static FormFormattingConfig new_defmethod_rule(int start_index, bool has_constant_pairs = false) {
// TODO - might be nice to have a function that returns a config based on a given index, instead
// of hardcoding them!
// Right now this only works for non-`new` methods (else we may bleed into the body of a normal
// method)
auto arg_list_config = std::make_shared<FormFormattingConfig>();
arg_list_config->force_inline = true;
arg_list_config->hang_forms = false;
FormFormattingConfig cfg = {.config_set = true,
.hang_forms = false,
.inline_until_index =
[start_index](const std::vector<std::string>& curr_lines) {
if (curr_lines.size() >= 2 && curr_lines.at(1) == "new") {
// defmethod was changed to omit the type name for everything
// except the `new` method, so special case.
return start_index + 1;
}
return start_index;
},
.has_constant_pairs = has_constant_pairs};
cfg.index_configs.emplace(2, arg_list_config);
return cfg;
}
static FormFormattingConfig new_lambda_rule(int start_index, bool has_constant_pairs = false) {
FormFormattingConfig cfg = {.config_set = true,
.hang_forms = false,
.inline_until_index =
[start_index](const std::vector<std::string>& curr_lines) {
if (curr_lines.size() >= 2 && curr_lines.at(1) == ":behavior") {
// defmethod was changed to omit the type name for everything
// except the `new` method, so special case.
return start_index + 2;
}
return start_index;
},
.has_constant_pairs = has_constant_pairs};
return cfg;
}
static FormFormattingConfig new_defenum_rule() {
auto temp_list_config = std::make_shared<FormFormattingConfig>();
temp_list_config->force_inline = true;
temp_list_config->hang_forms = false;
return {
.config_set = true,
.hang_forms = false,
.inline_until_index = [](const std::vector<std::string>& /*curr_lines*/) { return 2; },
.has_constant_pairs = true,
.default_index_config = temp_list_config,
};
}
static FormFormattingConfig new_deftype_rule(
int start_index,
int num_columns_to_compute_widths,
const std::vector<int>& inlining_preventation_indices) {
FormFormattingConfig cfg;
cfg.has_constant_pairs = true;
cfg.config_set = true;
cfg.hang_forms = false;
cfg.inline_until_index = [start_index](std::vector<std::string> curr_lines) {
@@ -39,6 +161,7 @@ static FormFormattingConfig new_deftype_rule(
temp_config->default_index_config = temp_list_config;
if (index == 3) {
temp_config->determine_column_widths_for_list_elements = true;
temp_config->num_columns_to_compute_widths = num_columns_to_compute_widths;
}
cfg.index_configs.emplace(index, temp_config);
}
@@ -74,6 +197,29 @@ static FormFormattingConfig new_binding_rule(int form_head_width) {
return cfg;
}
static FormFormattingConfig new_inline_binding_rule(int form_head_width) {
FormFormattingConfig cfg;
cfg.config_set = true;
cfg.hang_forms = false;
cfg.combine_first_two_lines = true;
auto binding_list_config = std::make_shared<FormFormattingConfig>();
binding_list_config->config_set = true;
binding_list_config->hang_forms = false;
binding_list_config->indentation_width = 1;
binding_list_config->indentation_width_for_index = [form_head_width](FormFormattingConfig /*cfg*/,
int index) {
if (index == 0) {
return 0;
}
return form_head_width;
};
binding_list_config->should_prevent_inlining = [](FormFormattingConfig /*config*/, int num_refs) {
return false;
};
cfg.index_configs.emplace(1, binding_list_config);
return cfg;
}
static FormFormattingConfig new_pair_rule(bool combine_first_two_expr) {
FormFormattingConfig cfg;
cfg.config_set = true;
@@ -88,23 +234,71 @@ static FormFormattingConfig new_pair_rule(bool combine_first_two_expr) {
return cfg;
}
static FormFormattingConfig new_top_level_inline_form(bool elide_new_line) {
return {.force_inline = true, .elide_top_level_newline = elide_new_line};
}
const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config = {
{"case", new_pair_rule(true)},
{"case-str", new_pair_rule(true)},
{"cond", new_pair_rule(false)},
{"defmethod", new_flow_rule(3)},
{"deftype", new_deftype_rule(3, {3, 4, 5, 6})},
{"#cond", new_pair_rule(false)},
{"in-package", new_top_level_inline_form(true)},
{"bundles", new_top_level_inline_form(true)},
{"require", new_top_level_inline_form(true)},
{"def-art-elt", new_top_level_inline_form(true)},
{"def-joint-node", new_top_level_inline_form(true)},
{"declare-file", new_top_level_inline_form(false)},
{"defenum", new_defenum_rule()},
{"defmethod", new_defmethod_rule(3)},
{"lambda", new_lambda_rule(2)},
{"deftype", new_deftype_rule(3, 1, {3, 4, 5, 6})},
{"defun", new_flow_rule(3)},
{"defun-recursive", new_flow_rule(4)},
{"defun-debug-recursive", new_flow_rule(4)},
{"defun-debug", new_flow_rule(3)},
{"defbehavior", new_flow_rule(4)},
{"if", new_permissive_flow_rule()},
{"if", new_inlineable_flow_rule(2)},
{"#if", new_inlineable_flow_rule(2)},
{"define", new_permissive_flow_rule()},
{"def-mips2c", new_permissive_flow_rule()},
{"defconstant", new_permissive_flow_rule()},
{"defglobalconstant", new_permissive_flow_rule()},
{"defmethod-mips2c", new_permissive_flow_rule()},
{"define-extern", new_permissive_flow_rule()},
{"defmacro", new_flow_rule(3)},
{"declare-type", new_permissive_flow_rule()},
{"defmacro", new_function_rule(3)},
{"desfun", new_function_rule(3)},
{"defskelgroup", new_flow_rule(2, true)},
{"defpartgroup", new_flow_rule(2, true)},
{"defpart", new_flow_rule(2, true)},
{"defstate", new_defstate_rule(3, true)},
{"behavior", new_flow_rule(2)},
{"dotimes", new_flow_rule(2)},
{"dolist", new_flow_rule(2)},
{"process-spawn-function", new_flow_rule(2)},
{"let", new_binding_rule(4)},
{"protect", new_binding_rule(4)},
{"let*", new_binding_rule(5)},
{"rlet", new_binding_rule(5)},
{"when", new_flow_rule(2)},
{"unless", new_flow_rule(2)},
{"with-profiler", new_flow_rule(2)},
{"with-pc", new_flow_rule(0)},
{"#unless", new_flow_rule(2)},
{"#when", new_flow_rule(2)},
{"countdown", new_flow_rule(2)},
{"until", new_flow_rule(2)},
{"loop", new_flow_rule(0)},
{"while", new_flow_rule(2)},
{"begin", new_flow_rule(0)},
{"seval", new_flow_rule(0)},
{"with-pp", new_flow_rule(0)},
{"with-gensyms", new_flow_rule(2)},
{"with-vf0", new_flow_rule(0)},
{"with-vf", new_inline_binding_rule(8)},
{"with-cnt-vif-block", new_inline_binding_rule(19)},
{"local-vars", new_inlinable_simple_flow_rule()},
{"with-dma-buffer-add-bucket", new_flow_rule(2)}};
} // namespace config
} // namespace formatter_rules
+5 -1
View File
@@ -7,7 +7,6 @@
#include <unordered_map>
#include <vector>
// TODO - some way to apply a config to all list elements (index configs with -1?)
namespace formatter_rules {
namespace config {
struct FormFormattingConfig {
@@ -33,9 +32,14 @@ struct FormFormattingConfig {
int parent_mutable_extra_indent = 0;
std::optional<std::shared_ptr<FormFormattingConfig>> default_index_config;
std::unordered_map<int, std::shared_ptr<FormFormattingConfig>> index_configs = {};
// TODO / NOTe - not fully implemented, only doing `parent_mutable_extra_indent` right now
std::unordered_map<int, std::shared_ptr<FormFormattingConfig>> index_config_override = {};
bool determine_column_widths_for_list_elements = false;
int num_columns_to_compute_widths = 0;
std::vector<int> list_element_column_widths = {};
bool elide_top_level_newline = false;
};
extern const std::unordered_map<std::string, FormFormattingConfig> opengoal_form_config;
+28 -7
View File
@@ -26,6 +26,8 @@ u64 get_current_tid() {
}
#endif
#include "common/log/log.h"
#include "common/util/compress.h"
#include "common/util/string_util.h"
// clang-format on
u64 get_current_ts() {
@@ -34,12 +36,12 @@ u64 get_current_ts() {
GlobalProfiler::GlobalProfiler() {
m_t0 = get_current_ts();
set_max_events(65536);
m_nodes.resize(m_max_events);
}
void GlobalProfiler::set_max_events(size_t event_count) {
ASSERT(!m_enabled);
m_nodes.resize(event_count);
void GlobalProfiler::update_event_buffer_size(size_t new_size) {
m_max_events = new_size;
m_nodes.resize(m_max_events);
}
void GlobalProfiler::set_waiting_for_event(const std::string& event_name) {
@@ -72,6 +74,10 @@ void GlobalProfiler::root_event() {
instant_event("ROOT");
}
size_t GlobalProfiler::get_next_idx() {
return (m_next_idx % m_nodes.size());
}
void GlobalProfiler::begin_event(const char* name) {
event(name, ProfNode::BEGIN);
}
@@ -96,8 +102,10 @@ void GlobalProfiler::set_enable(bool en) {
m_enabled = en;
}
void GlobalProfiler::dump_to_json(const std::string& path) {
ASSERT(!m_enabled);
void GlobalProfiler::dump_to_json() {
if (m_enabled) {
set_enable(false);
}
nlohmann::json json;
auto& trace_events = json["traceEvents"];
@@ -185,7 +193,20 @@ void GlobalProfiler::dump_to_json(const std::string& path) {
t.second.highest_at_target);
}
file_util::write_text_file(path, json.dump());
if (m_enable_compression) {
const auto json_str = json.dump();
const auto compressed_data =
compression::compress_zstd_no_header(json_str.data(), json_str.size());
auto file_path = file_util::get_jak_project_dir() / "profile_data" /
fmt::format("prof-{}.json.zst", str_util::current_local_timestamp_no_colons());
file_util::create_dir_if_needed_for_file(file_path);
file_util::write_binary_file(file_path, compressed_data.data(), compressed_data.size());
} else {
auto file_path = file_util::get_jak_project_dir() / "profile_data" /
fmt::format("prof-{}.json", str_util::current_local_timestamp_no_colons());
file_util::create_dir_if_needed_for_file(file_path);
file_util::write_text_file(file_path, json.dump());
}
}
GlobalProfiler gprof;
+8 -2
View File
@@ -17,7 +17,8 @@ struct ProfNode {
class GlobalProfiler {
public:
GlobalProfiler();
void set_max_events(size_t event_count);
size_t get_max_events() { return m_max_events; }
void update_event_buffer_size(size_t new_size);
void set_waiting_for_event(const std::string& event_name);
void instant_event(const char* name);
void begin_event(const char* name);
@@ -25,11 +26,16 @@ class GlobalProfiler {
void end_event();
void clear();
void set_enable(bool en);
void dump_to_json(const std::string& path);
void dump_to_json();
void root_event();
bool is_enabled() { return m_enabled; }
size_t get_next_idx();
bool m_enable_compression = false;
private:
std::atomic_bool m_enabled = false;
size_t m_max_events = 65536;
u64 m_t0 = 0;
std::atomic_size_t m_next_idx = 0;
std::vector<ProfNode> m_nodes;
-1
View File
@@ -12,7 +12,6 @@
#include "Reader.h"
#include "common/log/log.h"
#include "common/repl/util.h"
#include "common/util/FileUtil.h"
#include "common/util/FontUtils.h"
+1 -1
View File
@@ -18,7 +18,7 @@
#include "common/goos/Object.h"
#include "common/goos/TextDB.h"
#include "common/repl/util.h"
#include "common/repl/repl_wrapper.h"
#include "common/util/Assert.h"
namespace goos {
+4 -4
View File
@@ -140,7 +140,7 @@ void printstd(const char* format, va_list arg_list) {
internal::log_vprintf(format, arg_list);
}
// how many extra log files for a single program should be kept?
// how many extra log files for a single program should be kept
constexpr int LOG_ROTATE_MAX = 10;
void set_file(const std::string& filename,
@@ -163,7 +163,7 @@ void set_file(const std::string& filename,
file_util::find_files_in_dir(fs::path(complete_filename).parent_path(),
std::regex(fmt::format("{}\\.(\\d\\.)?log", filename)));
for (const auto& file : old_log_files) {
lg::info("removing {}", file.string());
lg::debug("removing {}", file.string());
fs::remove(file);
}
// remove the oldest log file if there are more than LOG_ROTATE_MAX
@@ -172,9 +172,9 @@ void set_file(const std::string& filename,
// sort the names and remove them
existing_log_files = file_util::sort_filepaths(existing_log_files, true);
if (existing_log_files.size() > (LOG_ROTATE_MAX - 1)) {
lg::info("removing {} log files", existing_log_files.size() - (LOG_ROTATE_MAX - 1));
lg::debug("removing {} log files", existing_log_files.size() - (LOG_ROTATE_MAX - 1));
for (int i = 0; i < (int)existing_log_files.size() - (LOG_ROTATE_MAX - 1); i++) {
lg::info("removing {}", existing_log_files.at(i).string());
lg::debug("removing {}", existing_log_files.at(i).string());
fs::remove(existing_log_files.at(i));
}
}
+9
View File
@@ -7,15 +7,21 @@
namespace REPL {
void to_json(json& j, const Config& obj) {
j = json{
{"nreplPort", obj.nrepl_port},
{"gameVersionFolder", obj.game_version_folder},
{"numConnectToTargetAttempts", obj.target_connect_attempts},
{"asmFileSearchDirs", obj.asm_file_search_dirs},
{"keybinds", obj.keybinds},
{"perGameHistory", obj.per_game_history},
{"permissiveRedefinitions", obj.permissive_redefinitions},
};
}
void from_json(const json& j, Config& obj) {
// TODO - make a camelCase variant of json_serialize/deserialize macros
if (j.contains("nreplPort")) {
j.at("nreplPort").get_to(obj.nrepl_port);
}
if (j.contains("gameVersionFolder")) {
j.at("gameVersionFolder").get_to(obj.game_version_folder);
}
@@ -55,6 +61,9 @@ void from_json(const json& j, Config& obj) {
if (j.contains("perGameHistory")) {
j.at("perGameHistory").get_to(obj.per_game_history);
}
if (j.contains("permissiveRedefinitions")) {
j.at("permissiveRedefinitions").get_to(obj.permissive_redefinitions);
}
// if there is game specific configuration, override any values we just set
if (j.contains(version_to_game_name(obj.game_version))) {
from_json(j.at(version_to_game_name(obj.game_version)), obj);
+11
View File
@@ -26,11 +26,14 @@ struct KeyBind {
void to_json(json& j, const KeyBind& obj);
void from_json(const json& j, KeyBind& obj);
// TODO - per-game config
struct Config {
GameVersion game_version;
Config(GameVersion _game_version) : game_version(_game_version){};
// this is the default REPL configuration
int nrepl_port = 8181;
int temp_nrepl_port = -1;
std::string game_version_folder;
int target_connect_attempts = 30;
std::vector<std::string> asm_file_search_dirs = {};
@@ -45,6 +48,14 @@ struct Config {
{KeyBind::Modifier::CTRL, "B", "Displays the most recently caught backtrace", "(:di)"},
{KeyBind::Modifier::CTRL, "N", "Full build of the game", "(mi)"}};
bool per_game_history = true;
bool permissive_redefinitions = false;
int get_nrepl_port() {
if (temp_nrepl_port != -1) {
return temp_nrepl_port;
}
return nrepl_port;
}
};
void to_json(json& j, const Config& obj);
void from_json(const json& j, Config& obj);
+60 -33
View File
@@ -16,10 +16,6 @@
#include "common/log/log.h"
// clang-format on
// TODO - basically REPL to listen and inject commands into a running REPL
// - we will need a C++ side client as well which will let us communicate with the repl via for
// example, ImgUI
//
// TODO - The server also needs to eventually return the result of the evaluation
ReplServer::~ReplServer() {
@@ -31,7 +27,18 @@ ReplServer::~ReplServer() {
void ReplServer::post_init() {
// Add the listening socket to our set of sockets
lg::info("[nREPL:{}:{}] awaiting connections", tcp_port, listening_socket);
lg::debug("[nREPL:{}:{}] awaiting connections", tcp_port, listening_socket);
}
void ReplServer::error_response(int socket, const std::string& error) {
std::string msg = fmt::format("[ERROR]: {}", error);
auto resp = write_to_socket(socket, msg.c_str(), msg.size());
if (resp == -1) {
lg::warn("[nREPL:{}] Client Disconnected: {}", tcp_port, address_to_string(addr),
ntohs(addr.sin_port), socket);
close_socket(socket);
client_sockets.erase(socket);
}
}
void ReplServer::ping_response(int socket) {
@@ -52,7 +59,6 @@ std::optional<std::string> ReplServer::get_msg() {
// Add the server's main listening socket (where we accept clients from)
FD_SET(listening_socket, &read_sockets);
int max_sd = listening_socket;
for (const int& sock : client_sockets) {
if (sock > max_sd) {
@@ -64,12 +70,11 @@ std::optional<std::string> ReplServer::get_msg() {
}
// Wait for activity on _something_, with a timeout so we don't get stuck here on exit.
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 100000;
struct timeval timeout = {0, 100000};
auto activity = select(max_sd + 1, &read_sockets, NULL, NULL, &timeout);
if (activity < 0) { // TODO - || error!
if (activity < 0 && errno != EINTR) {
lg::error("[nREPL:{}] select error, returned: {}, errno: {}", tcp_port, activity,
strerror(errno));
return std::nullopt;
}
@@ -78,44 +83,46 @@ std::optional<std::string> ReplServer::get_msg() {
socklen_t addr_len = sizeof(addr);
auto new_socket = accept_socket(listening_socket, (sockaddr*)&addr, &addr_len);
if (new_socket < 0) {
// TODO - handle error
if (new_socket != -1) {
lg::error("[nREPL:{}] accept error, returned: {}, errono: {}", tcp_port, new_socket,
strerror(errno));
}
} else {
lg::info("[nREPL:{}]: New socket connection: {}:{}:{}", tcp_port, address_to_string(addr),
ntohs(addr.sin_port), new_socket);
// Say hello
ping_response(new_socket);
// Track the new socket
if ((int)client_sockets.size() < max_clients) {
client_sockets.insert(new_socket);
} else {
// TODO - Respond with NO
// Respond with NO and close the socket
lg::warn("[nREPL:{}]: Maximum clients reached. Rejecting connection.", tcp_port);
error_response(new_socket, "Maximum clients reached. Rejecting connection.");
close_socket(new_socket);
}
}
}
// otherwise (and no matter what) check all the clients to see if they have sent us anything
// else its some IO operation on some other socket
//
// RACE - the first client wins
// TODO - there are ways to do this with iterators but, couldn't figure it out!
std::vector<int> sockets_to_scan(client_sockets.begin(), client_sockets.end());
for (const int& sock : sockets_to_scan) {
// Check all clients for activity
for (auto it = client_sockets.begin(); it != client_sockets.end();) {
int sock = *it;
if (FD_ISSET(sock, &read_sockets)) {
// Attempt to read a header
// TODO - should this be in a loop?
auto req_bytes = read_from_socket(sock, header_buffer.data(), header_buffer.size());
if (req_bytes == 0) {
// Socket disconnected
if (req_bytes <= 0) {
// TODO - add a queue of messages in the REPL::Wrapper so we can print _BEFORE_ the prompt
// is output
lg::warn("[nREPL:{}] Client Disconnected: {}", tcp_port, address_to_string(addr),
ntohs(addr.sin_port), sock);
if (req_bytes == 0) {
lg::warn("[nREPL:{}] Client Disconnected: {}", tcp_port, address_to_string(addr));
} else {
lg::warn("[nREPL:{}] Error reading from socket on {}: {}", tcp_port,
address_to_string(addr), strerror(errno));
}
// Cleanup the socket and remove it from our set
close_socket(sock);
client_sockets.erase(sock);
it = client_sockets.erase(it); // Erase and move to the next element
continue;
} else {
// Otherwise, process the message
auto* header = (ReplServerHeader*)(header_buffer.data());
@@ -123,7 +130,12 @@ std::optional<std::string> ReplServer::get_msg() {
int expected_size = header->length;
int got = 0;
int tries = 0;
bool skip_to_next_socket = false;
while (got < expected_size) {
if (want_exit_callback()) {
lg::warn("[nREPL:{}] Terminating nREPL early", tcp_port);
return std::nullopt;
}
tries++;
if (tries > 100) {
break;
@@ -135,11 +147,25 @@ std::optional<std::string> ReplServer::get_msg() {
tcp_port, got, expected_size, buffer.size());
return std::nullopt;
}
auto x = read_from_socket(sock, buffer.data() + got, expected_size - got);
if (want_exit_callback()) {
return std::nullopt;
auto bytes_read = read_from_socket(sock, buffer.data() + got, expected_size - got);
if (bytes_read <= 0) {
if (bytes_read == 0) {
lg::warn("[nREPL:{}] Client Disconnected: {}", tcp_port, address_to_string(addr));
} else {
lg::warn("[nREPL:{}] Error reading from socket on {}: {}", tcp_port,
address_to_string(addr), strerror(errno));
}
close_socket(sock);
it = client_sockets.erase(it); // Erase and move to the next element
skip_to_next_socket = true;
break;
}
got += x > 0 ? x : 0;
got += bytes_read;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
if (skip_to_next_socket) {
continue;
}
switch (header->type) {
@@ -153,6 +179,7 @@ std::optional<std::string> ReplServer::get_msg() {
}
}
}
++it;
}
return std::nullopt;
}
+1
View File
@@ -27,5 +27,6 @@ class ReplServer : public XSocketServer {
fd_set read_sockets;
std::set<int> client_sockets = {};
void error_response(int socket, const std::string& error);
void ping_response(int socket);
};
@@ -1,4 +1,4 @@
#include "util.h"
#include "repl_wrapper.h"
#include "common/util/FileUtil.h"
#include "common/util/json_util.h"
@@ -8,36 +8,66 @@
#include "fmt/color.h"
#include "fmt/core.h"
#include "third-party/replxx/include/replxx.hxx"
// TODO - expand a list of hints (ie. a hint for defun to show at a glance how to write a function,
// or perhaps, show the docstring for the current function being used?)
namespace REPL {
void Wrapper::clear_screen() {
repl.clear_screen();
}
void Wrapper::print_welcome_message() {
// TODO - dont print on std-out
// Welcome message / brief intro for documentation
std::string ascii;
ascii += " _____ _____ _____ _____ __ \n";
ascii += "| |___ ___ ___| __| | _ | | \n";
ascii += "| | | . | -_| | | | | | | |__ \n";
ascii += "|_____| _|___|_|_|_____|_____|__|__|_____|\n";
ascii += " |_| \n";
fmt::print(fmt::emphasis::bold | fg(fmt::color::orange), ascii);
fmt::print("Welcome to OpenGOAL {}.{}!\n", versions::GOAL_VERSION_MAJOR,
versions::GOAL_VERSION_MINOR);
fmt::print("Run {} or {} for help with common commands and REPL usage.\n",
fmt::styled("(repl-help)", fmt::emphasis::bold | fg(fmt::color::cyan)),
fmt::styled("(repl-keybinds)", fmt::emphasis::bold | fg(fmt::color::cyan)));
fmt::print("Run ");
fmt::print(fmt::emphasis::bold | fg(fmt::color::cyan), "(lt)");
fmt::print(" to connect to the local target.\n");
fmt::print("Run ");
fmt::print(fmt::emphasis::bold | fg(fmt::color::cyan), "(mi)");
fmt::print(" to rebuild the entire game.\n\n");
void Wrapper::print_welcome_message(const std::vector<std::string>& loaded_projects) {
std::string message;
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " ..:::::..\n");
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .:-----------:.\n");
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-----.");
message += fmt::format(fmt::emphasis::bold, " Welcome to OpenGOAL {}.{} [{}]",
versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR,
fmt::format(fg(fmt::color::gray), "{}", build_revision()));
if (!username.empty() && username != "#f" && username != "unknown") {
message += fmt::format(fg(fmt::color::light_green), " {}", username);
}
message += "!\n";
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .---.");
if (repl_config.game_version == GameVersion::Jak1) {
message += fmt::format(" [{}]: ", fmt::format(fg(fmt::color::orange), "jak1"));
} else if (repl_config.game_version == GameVersion::Jak2) {
message += fmt::format(" [{}]: ", fmt::format(fg(fmt::color::purple), "jak2"));
} else if (repl_config.game_version == GameVersion::Jak3) {
message += fmt::format(" [{}]: ", fmt::format(fg(fmt::color::gold), "jak3"));
} else {
message += fmt::format(" [{}]: ", fmt::format(fg(fmt::color::magenta), "jakx"));
}
const auto loaded_projects_str = fmt::format("{}", fmt::join(loaded_projects, ","));
message += fmt::format(fg(fmt::color::gray), "{}\n", loaded_projects_str);
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " . --- .");
message +=
fmt::format(" Project Path: {}\n",
fmt::format(fg(fmt::color::gray), file_util::get_jak_project_dir().string()));
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " - :===: -");
message += " nREPL:";
if (!nrepl_alive) {
message += fmt::format(fg(fmt::color::red), "DISABLED\n");
} else {
message += fmt::format(fg(fmt::color::light_green), " Listening on {}\n",
repl_config.get_nrepl_port());
}
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " --. .--: :--. .--");
message += " Source File Search Dirs: ";
const auto search_dir_string =
fmt::format("{}", fmt::join(repl_config.asm_file_search_dirs, ","));
message += fmt::format("[{}]\n", fmt::format(fg(fmt::color::gray), search_dir_string));
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .=======. =======.");
message += fmt::format(" {} or {} for basic help and usage\n",
fmt::format(fg(fmt::color::cyan), "(repl-help)"),
fmt::format(fg(fmt::color::cyan), "(repl-keybinds)"));
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-=====-. .-=====-");
message +=
fmt::format(" {} to connect to the game\n", fmt::format(fg(fmt::color::cyan), "(lt)"));
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-===========-.");
message += fmt::format(" {} to recompile the active project.\n",
fmt::format(fg(fmt::color::cyan), "(mi)"));
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .-===-.\n");
message += fmt::format(fmt::emphasis::bold | fg(fmt::color::orange), " .\n");
fmt::print("{}", message);
}
void Wrapper::print_to_repl(const std::string& str) {
@@ -242,20 +272,24 @@ StartupFile load_user_startup_file(const std::string& username, const GameVersio
return startup_file;
}
REPL::Config load_repl_config(const std::string& username, const GameVersion game_version) {
REPL::Config load_repl_config(const std::string& username,
const GameVersion game_version,
const int nrepl_port) {
auto repl_config_path =
file_util::get_jak_project_dir() / "goal_src" / "user" / username / "repl-config.json";
REPL::Config loaded_config(game_version);
if (file_util::file_exists(repl_config_path.string())) {
try {
REPL::Config config(game_version);
auto repl_config_data =
parse_commented_json(file_util::read_text_file(repl_config_path), "repl-config.json");
from_json(repl_config_data, config);
return config;
from_json(repl_config_data, loaded_config);
loaded_config.temp_nrepl_port = nrepl_port;
return loaded_config;
} catch (std::exception& e) {
REPL::Config config(game_version);
// do nothing
}
}
return REPL::Config(game_version);
loaded_config.temp_nrepl_port = nrepl_port;
return loaded_config;
}
} // namespace REPL
@@ -17,18 +17,23 @@ struct StartupFile {
};
class Wrapper {
replxx::Replxx repl;
public:
std::string username;
Config repl_config;
StartupFile startup_file;
bool nrepl_alive = false;
std::vector<std::string> examples{};
std::vector<std::pair<std::string, replxx::Replxx::Color>> regex_colors{};
Wrapper(GameVersion version) : repl_config(version) {}
Wrapper(const std::string& _username, const Config& config, const StartupFile& startup)
: username(_username), repl_config(config), startup_file(startup) {}
Wrapper(const std::string& _username,
const Config& config,
const StartupFile& startup,
bool _nrepl_alive)
: username(_username),
repl_config(config),
startup_file(startup),
nrepl_alive(_nrepl_alive) {}
replxx::Replxx& get_repl() { return repl; }
void init_settings();
void reload_startup_file();
@@ -36,7 +41,7 @@ class Wrapper {
// Functionality / Commands
void clear_screen();
void print_to_repl(const std::string& str);
void print_welcome_message();
void print_welcome_message(const std::vector<std::string>& loaded_projects);
void set_history_max_size(size_t len);
const char* readline(const std::string& prompt);
void add_to_history(const std::string& line);
@@ -47,11 +52,14 @@ class Wrapper {
std::pair<std::string, bool> get_current_repl_token(std::string const& context);
private:
replxx::Replxx repl;
replxx::Replxx::key_press_handler_t commit_text_action(std::string text_to_commit);
std::vector<REPL::KeyBind> keybindings = {};
};
std::string find_repl_username();
StartupFile load_user_startup_file(const std::string& username, const GameVersion game_version);
REPL::Config load_repl_config(const std::string& username, const GameVersion game_version);
REPL::Config load_repl_config(const std::string& username,
const GameVersion game_version,
const int nrepl_port);
} // namespace REPL
@@ -89,7 +89,9 @@ const std::unordered_map<std::string, u16> jak2_speaker_name_to_enum_val = {
{"citizen-male", 31},
{"citizen-female", 32},
{"oracle", 33},
{"precursor", 34}};
{"precursor", 34},
{"metalkor-before-consite", 35},
{"metalkor-intro", 36}};
GameSubtitlePackage read_json_files_v2(const GameSubtitleDefinitionFile& file_info) {
GameSubtitlePackage package;
+147 -1
View File
@@ -42,7 +42,153 @@ std::vector<std::string> jak2_slots = {
"cas-toxic-slime-scroll-dest",
};
std::vector<std::string> jak3_slots = {};
std::vector<std::string> jak3_slots = {
"skull-gem-dest",
"jakc-arm",
"jakc-eyebrow",
"jakc-face",
"jakc-finger",
"jakc-hair",
"jakchires-arm",
"jakchires-eye",
"jakchires-eyebrow",
"jakchires-eyelid",
"jakchires-facelft",
"jakchires-facert",
"jakchires-hair",
// default-water
"bomb-gradient",
"blue-beam-dest",
"lightjak-wings",
"mushroom-dest",
// default-warp
"shield-env-rim-dest",
// templea-water
"templea-waterfall-dest",
// templea-warp
"holograph-env-rim-dest",
// hanga-sprite
"glider-ring-dest2",
"glider-ring-dest",
// foresta-water
"fora-water-dest",
"fora-waterfall-01-dest",
"fora-water-wave-01-dest",
// forestb-water
"forb-water-dest",
"forb-waterfall-01-dest",
"forb-water-wave-01-dest",
// lforplnt-pris
"mh-gem-dest",
// lmhcitya-tfrag
"mhcitya-base-goo-01-dest",
// lmhcityb-tfrag
"mhcityb-base-goo-01-dest",
// mhcitya-pris
// "mhcity-de-door-skin-01-dest",
// templec-water
"tplc-water-dest",
// sewc-water
"sewer-water-01-c-dest",
"sewer-waterfall-01-c-dest",
"sewer-waterfall-02-c-dest",
"sewer-water-wave-01-c-dest",
"sewer-water-highlight-01-c-dest",
// sewd-water
"sewer-water-01-d-dest",
"sewer-waterfall-02-d-dest",
"sewer-water-highlight-01-d-dest",
"sewer-water-wave-01-d-dest",
"sewer-water-wave-02-d-dest",
"sewer-water-still-01-d-dest",
// sewe-water
"sewer-water-01-e-dest",
"sewer-waterfall-01-e-dest",
"sewer-waterfall-02-e-dest",
"sewer-water-highlight-01-e-dest",
// sewg-water
"sewer-water-01-g-dest",
"sewer-waterfall-02-g-dest",
"sewer-water-wave-01-g-dest",
// sewh-water
"sewer-water-01-h-dest",
"sewer-waterfall-02-h-dest",
"sewer-water-wave-02-h-dest",
"sewer-watefall-froth-01-h-dest",
// sewi-water
"sewer-water-still-01-i-dest",
"sewer-waterfall-02-i-dest",
"sewer-water-wave-01-i-dest",
// sewj-water
"sewer-waterfall-02-j-dest",
"sewer-watefall-froth-01-j-dest",
// sewl-water
"sewer-waterfall-02-l-dest",
"sewer-watefall-froth-01-l-dest",
// sewm-water
"sewer-water-01-m-dest",
"sewer-waterfall-01-m-dest",
"sewer-waterfall-02-m-dest",
"sewer-water-highlight-01-m-dest",
"sewer-water-wave-01-m-dest",
"sewer-water-still-01-m-dest",
"sewer-watefall-froth-01-m-dest",
// sewn-water
"sewer-waterfall-01-n-dest",
"sewer-waterfall-02-n-dest",
// "sewer-water-highlight-01-n-dest",
"sewer-water-wave-01-n-dest",
"sewer-water-still-01-n-dest",
// hanga-water
// "des-thermal-01-dest",
// desresc-warp
"sat-shield-dest",
// security
"security-env-dest",
"security-dot-dest",
// lgunnorm-water
"kg-target-c-forcefield-01-dest",
// templex-water
"temple-waterfall-dest",
// desertd-water
"des-waterfall-dest",
// towerb-water
"tow-energy-bridge-dest",
// factoryb-water
"hemi-gradient-dest",
"hemi-gradient-flames-dest",
// factoryc-alpha
"facc-convey-dest",
"facc-convey-02-dest",
// waspal-water
"waspala-water-dest",
"waspala-waterfall-dest",
// rubblea-water
"rub-water-dest",
// rubblea2-water
"rub-water-desta2",
// rubbleb-water
"rub-water-destb",
// rubblec-water
"rub-water-destc",
// nstb-quicksand
"nstb-quicksand-dest",
// ctyslumb-water
"ctyslumb-water-dest",
"ctyslumb-fountain-fall-dest",
// ctyslumc-water
"ctyslumc-water-dest",
"ctyslumc-fountain-fall-dest",
// mined-tfrag
"mined-pillar-side-dest",
"mined-pillar-top2side-dest",
"mined-pillar-top-dest",
// volcanoa-alpha
"vola-lava-01-dest",
"vola-lava-fall-dest",
// wasstada-alpha
"wstd-lava-base-dest",
};
} // namespace
+4
View File
@@ -28,8 +28,12 @@ struct MethodInfo {
std::string name;
TypeSpec type;
std::string defined_in_type;
// TODO - this might be redundant, but preventing an unknown breaking change, clean it up later
std::string type_name;
bool no_virtual = false;
// TODO - this is no longer used anymore...but was not removed from th4e struct?
bool overrides_parent = false;
// TODO - this is no longer used anymore...but was not removed from th4e struct?
bool only_overrides_docstring = false;
std::optional<std::string> docstring;
std::optional<std::string> overlay_name;
+2
View File
@@ -124,10 +124,12 @@ class TypeSpec {
ASSERT(m_arguments);
return m_arguments->at(idx);
}
TypeSpec& get_arg(int idx) {
ASSERT(m_arguments);
return m_arguments->at(idx);
}
const TypeSpec& last_arg() const {
ASSERT(m_arguments);
ASSERT(!m_arguments->empty());
+9 -4
View File
@@ -548,6 +548,7 @@ MethodInfo TypeSystem::override_method(Type* type,
existing_info.name,
existing_info.type,
type->get_name(),
type->get_name(),
existing_info.no_virtual,
false,
true,
@@ -607,6 +608,7 @@ MethodInfo TypeSystem::declare_method(Type* type,
method_name,
ts,
type->get_name(),
type->get_name(),
no_virtual,
true,
false,
@@ -645,6 +647,7 @@ MethodInfo TypeSystem::declare_method(Type* type,
method_name,
ts,
type->get_name(),
type->get_name(),
no_virtual,
false,
false,
@@ -678,8 +681,8 @@ MethodInfo TypeSystem::overlay_method(Type* type,
}
// use the existing ID.
return type->add_method({existing_info.id, method_name, ts, type->get_name(), false, true, false,
docstring, std::make_optional(method_overlay_name)});
return type->add_method({existing_info.id, method_name, ts, type->get_name(), type->get_name(),
false, true, false, docstring, std::make_optional(method_overlay_name)});
}
MethodInfo TypeSystem::define_method(const std::string& type_name,
@@ -709,8 +712,10 @@ MethodInfo TypeSystem::define_method(Type* type,
// look up the method
MethodInfo existing_info;
bool got_existing = try_lookup_method(type, method_name, &existing_info);
if (got_existing) {
// The lookup will return a parents method, but the type should be equal
// to the type in question (it's a child)
existing_info.type_name = type->get_name();
// Update the docstring
existing_info.docstring = docstring;
int bad_arg_idx = -99;
@@ -758,7 +763,7 @@ MethodInfo TypeSystem::add_new_method(Type* type,
return existing;
} else {
return type->add_new_method(
{0, "new", ts, type->get_name(), false, false, false, docstring, {}});
{0, "new", ts, type->get_name(), type->get_name(), false, false, false, docstring, {}});
}
}
+4 -2
View File
@@ -58,10 +58,11 @@ EnumType* parse_defenum(const goos::Object& defenum,
auto& enum_name_obj = car(iter);
iter = cdr(iter);
// check for docstring
std::optional<std::string> maybe_docstring;
if (iter->is_pair() && car(iter).is_string()) {
// TODO - docstring - store and use docstring if coming from the compiler
if (symbol_metadata) {
symbol_metadata->docstring = str_util::trim_newline_indents(car(iter).as_string()->data);
maybe_docstring = str_util::trim_newline_indents(car(iter).as_string()->data);
symbol_metadata->docstring = maybe_docstring.value();
}
iter = cdr(iter);
}
@@ -157,6 +158,7 @@ EnumType* parse_defenum(const goos::Object& defenum,
if (is_type("integer", base_type, ts)) {
auto parent = ts->get_type_of_type<ValueType>(base_type.base_type());
auto new_type = std::make_unique<EnumType>(parent, name, is_bitfield, entries);
new_type->m_metadata.docstring = maybe_docstring;
new_type->set_runtime_type(parent->get_runtime_name());
return dynamic_cast<EnumType*>(ts->add_type(name, std::move(new_type)));
} else {
+3
View File
@@ -36,6 +36,9 @@
#define ASSERT_NOT_REACHED_MSG(STR) \
(void)((private_assert_failed("not reached", __FILE__, __LINE__, __PRETTY_FUNCTION__, STR), 0))
#define ASSERT_EQ_IMM(EXPR, EXPECTED) \
ASSERT_MSG((EXPR) == (EXPECTED), fmt::format("result was {}, expected {}", (EXPR), (EXPECTED)))
#else
#define ASSERT(EX) ((void)0)
+93 -25
View File
@@ -57,6 +57,14 @@ fs::path get_user_home_dir() {
#endif
}
struct {
bool initialized = false;
fs::path path_to_data_folder;
fs::path user_config_dir_override = "";
// by default - if the config dir is overridden, we don't use the default save location
bool use_overridden_config_dir_for_saves = true;
} g_file_path_info;
fs::path get_user_config_dir() {
fs::path config_base_path;
#ifdef _WIN32
@@ -80,35 +88,53 @@ fs::path get_user_config_dir() {
fs::path get_user_settings_dir(GameVersion game_version) {
auto game_version_name = game_version_names[game_version];
return get_user_config_dir() / game_version_name / "settings";
auto config_dir = get_user_config_dir();
if (!g_file_path_info.user_config_dir_override.empty()) {
config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL";
}
return config_dir / game_version_name / "settings";
}
fs::path get_user_memcard_dir(GameVersion game_version) {
auto game_version_name = game_version_names[game_version];
return get_user_config_dir() / game_version_name / "saves";
auto config_dir = get_user_config_dir();
if (!g_file_path_info.user_config_dir_override.empty() &&
g_file_path_info.use_overridden_config_dir_for_saves) {
config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL";
}
return config_dir / game_version_name / "saves";
}
fs::path get_user_screenshots_dir(GameVersion game_version) {
auto game_version_name = game_version_names[game_version];
return get_user_config_dir() / game_version_name / "screenshots";
auto config_dir = get_user_config_dir();
if (!g_file_path_info.user_config_dir_override.empty()) {
config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL";
}
return config_dir / game_version_name / "screenshots";
}
fs::path get_user_misc_dir(GameVersion game_version) {
auto game_version_name = game_version_names[game_version];
return get_user_config_dir() / game_version_name / "misc";
auto config_dir = get_user_config_dir();
if (!g_file_path_info.user_config_dir_override.empty()) {
config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL";
}
return config_dir / game_version_name / "misc";
}
fs::path get_user_features_dir(GameVersion game_version) {
auto game_version_name = game_version_names[game_version];
auto path = get_user_config_dir() / game_version_name / "features";
auto config_dir = get_user_config_dir();
if (!g_file_path_info.user_config_dir_override.empty()) {
config_dir = g_file_path_info.user_config_dir_override / "OpenGOAL";
}
auto path = config_dir / game_version_name / "features";
file_util::create_dir_if_needed(path);
return path;
}
struct {
bool initialized = false;
fs::path path_to_data;
} gFilePathInfo;
fs::path g_iso_data_directory = "";
/*!
* Get the path to the current executable.
@@ -159,9 +185,11 @@ std::optional<std::string> try_get_jak_project_path() {
return try_get_project_path_from_path(get_current_executable_path());
}
std::optional<fs::path> try_get_data_dir() {
std::optional<fs::path> try_get_data_dir(bool skip_logs) {
fs::path my_path = get_current_executable_path();
lg::info("Current executable directory - {}", my_path.string());
if (!skip_logs) {
lg::debug("Current executable directory - {}", my_path.string());
}
auto data_dir = my_path.parent_path() / "data";
if (fs::exists(data_dir) && fs::is_directory(data_dir)) {
return std::make_optional(data_dir);
@@ -170,31 +198,38 @@ std::optional<fs::path> try_get_data_dir() {
}
}
bool setup_project_path(std::optional<fs::path> project_path_override) {
if (gFilePathInfo.initialized) {
bool setup_project_path(std::optional<fs::path> project_path_override, bool skip_logs) {
if (g_file_path_info.initialized) {
return true;
}
if (project_path_override) {
gFilePathInfo.path_to_data = fs::absolute(project_path_override.value());
gFilePathInfo.initialized = true;
lg::info("Using explicitly set project path: {}", gFilePathInfo.path_to_data.string());
g_file_path_info.path_to_data_folder = fs::absolute(project_path_override.value());
g_file_path_info.initialized = true;
if (!skip_logs) {
lg::debug("Using explicitly set project path: {}",
g_file_path_info.path_to_data_folder.string());
}
return true;
}
auto data_path = try_get_data_dir();
auto data_path = try_get_data_dir(skip_logs);
if (data_path) {
gFilePathInfo.path_to_data = *data_path;
gFilePathInfo.initialized = true;
lg::info("Using data path: {}", data_path->string());
g_file_path_info.path_to_data_folder = *data_path;
g_file_path_info.initialized = true;
if (!skip_logs) {
lg::debug("Using data path: {}", data_path->string());
}
return true;
}
auto development_repo_path = try_get_jak_project_path();
if (development_repo_path) {
gFilePathInfo.path_to_data = *development_repo_path;
gFilePathInfo.initialized = true;
lg::info("Using development repo path: {}", *development_repo_path);
g_file_path_info.path_to_data_folder = *development_repo_path;
g_file_path_info.initialized = true;
if (!skip_logs) {
lg::debug("Using development repo path: {}", *development_repo_path);
}
return true;
}
@@ -202,9 +237,37 @@ bool setup_project_path(std::optional<fs::path> project_path_override) {
return false;
}
void override_user_config_dir(fs::path user_config_dir_override,
bool use_overridden_config_dir_for_saves) {
g_file_path_info.user_config_dir_override = user_config_dir_override;
g_file_path_info.use_overridden_config_dir_for_saves = use_overridden_config_dir_for_saves;
}
fs::path get_jak_project_dir() {
ASSERT(gFilePathInfo.initialized);
return gFilePathInfo.path_to_data;
ASSERT(g_file_path_info.initialized);
return g_file_path_info.path_to_data_folder;
}
fs::path get_iso_dir_for_game(GameVersion game_version) {
if (!g_iso_data_directory.empty()) {
return g_iso_data_directory;
}
// Find the location based on the game version
std::string expected_subdir = "jak1";
if (game_version == GameVersion::Jak2) {
expected_subdir = "jak2";
} else if (game_version == GameVersion::Jak3) {
expected_subdir = "jak3";
}
const auto temp_dir = get_jak_project_dir() / "iso_data" / expected_subdir;
if (fs::exists(temp_dir)) {
g_iso_data_directory = temp_dir;
}
return g_iso_data_directory;
}
void set_iso_data_dir(const fs::path& directory) {
g_iso_data_directory = directory;
}
std::string get_file_path(const std::vector<std::string>& input) {
@@ -757,4 +820,9 @@ std::pair<int, std::string> get_majority_file_line_endings_and_count(
return {lf_count + crlf_count, "\n"};
}
bool is_dir_in_dir(const fs::path& parent, const fs::path& child) {
// Check if the parent path is a prefix of the child path
return child.has_parent_path() && child.parent_path().lexically_relative(parent) == fs::path(".");
}
} // namespace file_util
+7 -1
View File
@@ -35,12 +35,17 @@ fs::path get_user_screenshots_dir(GameVersion game_version);
fs::path get_user_misc_dir(GameVersion game_version);
fs::path get_user_features_dir(GameVersion game_version);
fs::path get_jak_project_dir();
fs::path get_iso_dir_for_game(GameVersion game_version);
void set_iso_data_dir(const fs::path& directory);
bool create_dir_if_needed(const fs::path& path);
bool create_dir_if_needed_for_file(const std::string& path);
bool create_dir_if_needed_for_file(const fs::path& path);
std::string get_current_executable_path();
std::optional<std::string> try_get_project_path_from_path(const std::string& path);
bool setup_project_path(std::optional<fs::path> project_path_override);
bool setup_project_path(std::optional<fs::path> project_path_override, bool skip_logs = false);
void override_user_config_dir(fs::path user_config_dir_override,
bool use_overridden_config_dir_for_saves);
std::string get_file_path(const std::vector<std::string>& path);
void write_binary_file(const std::string& name, const void* data, size_t size);
void write_binary_file(const fs::path& name, const void* data, size_t size);
@@ -74,4 +79,5 @@ std::string make_screenshot_filepath(const GameVersion game_version, const std::
std::string get_majority_file_line_endings(const std::string& file_contents);
std::pair<int, std::string> get_majority_file_line_endings_and_count(
const std::string& file_contents);
bool is_dir_in_dir(const fs::path& parent, const fs::path& child);
} // namespace file_util
+3
View File
@@ -985,6 +985,8 @@ static std::vector<ReplaceInfo> s_replace_info_jak2 = {
{"o~Y~-26H~-4V'~Z", "ó"},
{"U~Y~-24H~-3V'~Z", "Ú"},
{"u~Y~-24H~-3V'~Z", "ú"},
{"Z~Y~-24H~-3V'~Z", "Ź"},
{"z~Y~-24H~-3V'~Z", "ź"},
// circumflex
{"A~Y~-20H~-4V^~Z", "Â"},
@@ -1015,6 +1017,7 @@ static std::vector<ReplaceInfo> s_replace_info_jak2 = {
{"a~Y~-25H~-5V¨~Z", "ä"},
{"E~Y~-20H~-5V¨~Z", "Ë"},
{"I~Y~-19H~-5V¨~Z", "Ï"},
{"i~Y~-26H~-4V¨~Z", "ï"},
{"O~Y~-26H~-8V¨~Z", "Ö"},
{"o~Y~-26H~-4V¨~Z", "ö"},
{"U~Y~-25H~-8V¨~Z", "Ü"},
+13
View File
@@ -46,4 +46,17 @@ std::vector<u8> decompress_zstd(const void* data, size_t size) {
ASSERT(decomp_size == decompressed_size);
return result;
}
std::vector<u8> compress_zstd_no_header(const void* data, size_t size) {
size_t max_compressed = ZSTD_compressBound(size);
std::vector<u8> result(max_compressed);
size_t compressed_size = ZSTD_compress(result.data(), max_compressed, data, size, 1);
if (ZSTD_isError(compressed_size)) {
ASSERT_MSG(false, fmt::format("ZSTD error: {}", ZSTD_getErrorName(compressed_size)));
}
result.resize(compressed_size);
return result;
}
} // namespace compression
+2 -1
View File
@@ -8,4 +8,5 @@ namespace compression {
// compress and decompress data with zstd
std::vector<u8> compress_zstd(const void* data, size_t size);
std::vector<u8> decompress_zstd(const void* data, size_t size);
} // namespace compression
std::vector<u8> compress_zstd_no_header(const void* data, size_t size);
} // namespace compression
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include <string>
#include "common/common_types.h"
inline u64 fnv64(const void* data, u64 len) {
u64 ret = 0xcbf29ce484222325;
const auto* ptr = (const u8*)data;
for (u64 i = 0; i < len; i++) {
ret = 1099511628211 * (((u64)*ptr) ^ ret);
ptr++;
}
return ret;
}
inline u64 fnv64(const std::string& str) {
return fnv64(str.data(), str.length());
}
+467
View File
@@ -0,0 +1,467 @@
#include "gltf_util.h"
#include "common/log/log.h"
namespace gltf_util {
/*!
* Convert a GLTF position buffer or similar to std::vector<Vec3f>
*/
std::vector<math::Vector3f> extract_vec3f(const u8* data, u32 count, u32 stride) {
std::vector<math::Vector3f> result;
result.reserve(count);
for (u32 i = 0; i < count; i++) {
memcpy(&result.emplace_back(), data, sizeof(math::Vector3f));
data += stride;
}
return result;
}
std::vector<math::Vector2f> extract_vec2f(const u8* data, u32 count, u32 stride) {
std::vector<math::Vector2f> result;
result.reserve(count);
for (u32 i = 0; i < count; i++) {
memcpy(&result.emplace_back(), data, sizeof(math::Vector2f));
data += stride;
}
return result;
}
/*!
* Convert a GLTF color buffer (float format) to u8 colors.
*/
std::vector<math::Vector<u8, 4>> extract_color_from_vec4_float(const u8* data,
u32 count,
u32 stride) {
std::vector<math::Vector<u8, 4>> result;
result.reserve(count);
for (u32 i = 0; i < count; i++) {
math::Vector<float, 4> temp;
memcpy(&temp, data, sizeof(math::Vector<float, 4>));
data += stride;
result.emplace_back(temp.x() * 255, temp.y() * 255, temp.z() * 255, temp.w() * 255);
}
return result;
}
/*!
* Convert a GLTF color buffer (u16 format) to u8 colors.
*/
std::vector<math::Vector<u8, 4>> extract_color_from_vec4_u16(const u8* data,
u32 count,
u32 stride) {
std::vector<math::Vector<u8, 4>> result;
result.reserve(count);
for (u32 i = 0; i < count; i++) {
math::Vector<u16, 4> temp;
memcpy(&temp, data, sizeof(math::Vector<u16, 4>));
data += stride;
result.emplace_back(temp.x() >> 8, temp.y() >> 8, temp.z() >> 8, temp.w() >> 8);
}
return result;
}
/*!
* Convert a GLTF index buffer
*/
std::vector<u32> gltf_index_buffer(const tinygltf::Model& model,
int indices_idx,
u32 index_offset) {
const auto& indices_accessor = model.accessors[indices_idx];
const auto& buffer_view = model.bufferViews[indices_accessor.bufferView];
const auto& buffer = model.buffers[buffer_view.buffer];
const auto data_ptr = buffer.data.data() + buffer_view.byteOffset + indices_accessor.byteOffset;
const auto stride = indices_accessor.ByteStride(buffer_view);
const auto count = indices_accessor.count;
switch (indices_accessor.componentType) {
case TINYGLTF_COMPONENT_TYPE_BYTE:
return index_list_to_u32<s8>(data_ptr, count, index_offset, stride);
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
return index_list_to_u32<u8>(data_ptr, count, index_offset, stride);
case TINYGLTF_COMPONENT_TYPE_SHORT:
return index_list_to_u32<s16>(data_ptr, count, index_offset, stride);
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
return index_list_to_u32<u16>(data_ptr, count, index_offset, stride);
case TINYGLTF_COMPONENT_TYPE_INT:
return index_list_to_u32<s32>(data_ptr, count, index_offset, stride);
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
return index_list_to_u32<u32>(data_ptr, count, index_offset, stride);
default:
ASSERT_MSG(false, "unsupported component type");
}
}
/*!
* Extract positions, colors, and normals from a mesh.
*/
ExtractedVertices gltf_vertices(const tinygltf::Model& model,
const std::map<std::string, int>& attributes,
const math::Matrix4f& w_T_local,
bool get_colors,
bool get_normals,
const std::string& debug_name) {
std::vector<tfrag3::PreloadedVertex> result;
std::vector<math::Vector<u8, 4>> vtx_colors;
{
const auto& position_attrib = attributes.find("POSITION");
ASSERT_MSG(position_attrib != attributes.end(), "Did not find position attribute.");
const auto attrib_accessor = model.accessors[position_attrib->second];
const auto& buffer_view = model.bufferViews[attrib_accessor.bufferView];
const auto& buffer = model.buffers[buffer_view.buffer];
const auto data_ptr = buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset;
const auto byte_stride = attrib_accessor.ByteStride(buffer_view);
const auto count = attrib_accessor.count;
ASSERT_MSG(attrib_accessor.type == TINYGLTF_TYPE_VEC3, "POSITION wasn't vec3");
ASSERT_MSG(attrib_accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT,
"POSITION wasn't float");
// for (auto& attrib : attributes) {
// lg::print("attrib: {}\n", attrib.first);
//}
auto mesh_verts = extract_vec3f(data_ptr, count, byte_stride);
result.reserve(mesh_verts.size());
for (auto& vert : mesh_verts) {
auto& new_vert = result.emplace_back();
math::Vector4f v_in(vert.x(), vert.y(), vert.z(), 1);
math::Vector4f v_w = w_T_local * v_in;
new_vert.x = v_w.x() * 4096;
new_vert.y = v_w.y() * 4096;
new_vert.z = v_w.z() * 4096;
}
}
if (get_colors) {
const auto& color_attrib = attributes.find("COLOR_0");
if (color_attrib == attributes.end()) {
lg::error("Mesh {} didn't have any colors, using white", debug_name);
for (size_t i = 0; i < result.size(); i++) {
vtx_colors.emplace_back(0x80, 0x80, 0x80, 0xff);
}
} else {
const auto attrib_accessor = model.accessors[color_attrib->second];
const auto& buffer_view = model.bufferViews[attrib_accessor.bufferView];
const auto& buffer = model.buffers[buffer_view.buffer];
const auto data_ptr =
buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset;
const auto byte_stride = attrib_accessor.ByteStride(buffer_view);
const auto count = attrib_accessor.count;
ASSERT_MSG(attrib_accessor.type == TINYGLTF_TYPE_VEC4, "COLOR_0 wasn't vec4");
std::vector<math::Vector<u8, 4>> colors;
switch (attrib_accessor.componentType) {
case TINYGLTF_COMPONENT_TYPE_FLOAT:
colors = extract_color_from_vec4_float(data_ptr, count, byte_stride);
break;
case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
colors = extract_color_from_vec4_u16(data_ptr, count, byte_stride);
break;
default:
lg::die("Unknown component type for COLOR_0: {}", attrib_accessor.componentType);
}
vtx_colors.insert(vtx_colors.end(), colors.begin(), colors.end());
}
}
bool got_texture = false;
{
const auto& texcoord_attrib = attributes.find("TEXCOORD_0");
if (texcoord_attrib != attributes.end()) {
const auto attrib_accessor = model.accessors[texcoord_attrib->second];
const auto& buffer_view = model.bufferViews[attrib_accessor.bufferView];
const auto& buffer = model.buffers[buffer_view.buffer];
const auto data_ptr =
buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset;
const auto byte_stride = attrib_accessor.ByteStride(buffer_view);
const auto count = attrib_accessor.count;
ASSERT_MSG(attrib_accessor.type == TINYGLTF_TYPE_VEC2, "TEXCOORD wasn't vec2");
ASSERT_MSG(attrib_accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT,
"TEXCOORD wasn't float");
auto mesh_verts = extract_vec2f(data_ptr, count, byte_stride);
ASSERT(mesh_verts.size() == result.size());
got_texture = true;
for (size_t i = 0; i < mesh_verts.size(); i++) {
result[i].s = mesh_verts[i].x();
result[i].t = mesh_verts[i].y();
}
} else {
if (!get_normals) {
// don't warn if we're just getting collision
lg::warn("No texcoord attribute for mesh: {}", debug_name);
}
}
}
std::vector<math::Vector3f> normals;
if (get_normals) {
const auto& normal_attrib = attributes.find("NORMAL");
if (normal_attrib != attributes.end()) {
const auto attrib_accessor = model.accessors[normal_attrib->second];
const auto& buffer_view = model.bufferViews[attrib_accessor.bufferView];
const auto& buffer = model.buffers[buffer_view.buffer];
const auto data_ptr =
buffer.data.data() + buffer_view.byteOffset + attrib_accessor.byteOffset;
const auto byte_stride = attrib_accessor.ByteStride(buffer_view);
const auto count = attrib_accessor.count;
ASSERT_MSG(attrib_accessor.type == TINYGLTF_TYPE_VEC3, "NORMAL wasn't vec3");
ASSERT_MSG(attrib_accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT,
"NORMAL wasn't float");
normals = extract_vec3f(data_ptr, count, byte_stride);
for (auto& nrm : normals) {
math::Vector4f nrm4(nrm.x(), nrm.y(), nrm.z(), 0.f);
nrm = (w_T_local * nrm4).xyz();
}
ASSERT(normals.size() == result.size());
} else {
lg::error("No NORMAL attribute for mesh: {}", debug_name);
}
}
for (auto& v : result) {
v.color_index = 0;
if (!got_texture) {
v.s = 0;
v.t = 0;
}
}
// TODO: other properties
return {result, vtx_colors, normals};
}
DrawMode make_default_draw_mode() {
DrawMode mode;
mode.set_depth_write_enable(true);
mode.set_depth_test(GsTest::ZTest::GEQUAL);
mode.set_alpha_blend(DrawMode::AlphaBlend::DISABLED);
mode.set_aref(0);
mode.set_alpha_fail(GsTest::AlphaFail::KEEP);
mode.set_clamp_s_enable(false);
mode.set_clamp_t_enable(false);
mode.disable_filt(); // for checkerboard...
mode.enable_tcc(); // ?
mode.disable_at();
mode.enable_zt();
mode.disable_ab();
mode.disable_decal();
mode.enable_fog();
return mode;
}
int texture_pool_debug_checker(TexturePool* pool) {
const auto& existing = pool->textures_by_name.find("DEBUG_CHECKERBOARD");
if (existing == pool->textures_by_name.end()) {
size_t idx = pool->textures_by_idx.size();
pool->textures_by_name["DEBUG_CHECKERBOARD"] = idx;
auto& tex = pool->textures_by_idx.emplace_back();
tex.w = 16;
tex.h = 16;
tex.debug_name = "DEBUG_CHECKERBOARD";
tex.debug_tpage_name = "DEBUG";
tex.load_to_pool = false;
tex.combo_id = 0; // doesn't matter, not a pool tex
tex.data.resize(16 * 16);
u32 c0 = 0xa0303030;
u32 c1 = 0xa0e0e0e0;
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
tex.data[i * 16 + j] = (((i / 4) & 1) ^ ((j / 4) & 1)) ? c1 : c0;
}
}
return idx;
} else {
return existing->second;
}
}
int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex) {
const auto& existing = pool->textures_by_name.find(tex.name);
if (existing != pool->textures_by_name.end()) {
lg::info("Reusing image: {}", tex.name);
return existing->second;
} else {
lg::info("adding new texture: {}, size {} kB", tex.name, tex.width * tex.height * 4 / 1024);
}
ASSERT(tex.bits == 8);
ASSERT(tex.component == 4);
ASSERT(tex.pixel_type == TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE);
size_t idx = pool->textures_by_idx.size();
pool->textures_by_name[tex.name] = idx;
auto& tt = pool->textures_by_idx.emplace_back();
tt.w = tex.width;
tt.h = tex.height;
tt.debug_name = tex.name;
tt.debug_tpage_name = "custom-level";
tt.load_to_pool = false;
tt.combo_id = 0; // doesn't matter, not a pool tex
tt.data.resize(tt.w * tt.h);
ASSERT(tex.image.size() >= tt.data.size());
memcpy(tt.data.data(), tex.image.data(), tt.data.size() * 4);
return idx;
}
math::Matrix4f affine_translation(const math::Vector3f& translation) {
math::Matrix4f result = math::Matrix4f::identity();
result(0, 3) = translation[0];
result(1, 3) = translation[1];
result(2, 3) = translation[2];
result(3, 3) = 1;
return result;
}
math::Matrix4f affine_scale(const math::Vector3f& scale) {
math::Matrix4f result = math::Matrix4f::zero();
result(0, 0) = scale[0];
result(1, 1) = scale[1];
result(2, 2) = scale[2];
result(3, 3) = 1;
return result;
}
math::Matrix4f affine_rot_qxyzw(const math::Vector4f& quat) {
math::Matrix4f result = math::Matrix4f::zero();
result(3, 3) = 1;
result(0, 0) = 1.0 - 2.0 * (quat.y() * quat.y() + quat.z() * quat.z());
result(0, 1) = 2.0 * (quat.x() * quat.y() - quat.z() * quat.w());
result(0, 2) = 2.0 * (quat.x() * quat.z() + quat.y() * quat.w());
result(1, 0) = 2.0 * (quat.x() * quat.y() + quat.z() * quat.w());
result(1, 1) = 1.0 - 2.0 * (quat.x() * quat.x() + quat.z() * quat.z());
result(1, 2) = 2.0 * (quat.y() * quat.z() - quat.x() * quat.w());
result(2, 0) = 2.0 * (quat.x() * quat.z() - quat.y() * quat.w());
result(2, 1) = 2.0 * (quat.y() * quat.z() + quat.x() * quat.w());
result(2, 2) = 1.0 - 2.0 * (quat.x() * quat.x() + quat.y() * quat.y());
return result;
}
math::Vector3f vector3f_from_gltf(const std::vector<double>& in) {
ASSERT(in.size() == 3);
return math::Vector3f{in[0], in[1], in[2]};
}
math::Vector4f vector4f_from_gltf(const std::vector<double>& in) {
ASSERT(in.size() == 4);
return math::Vector4f{in[0], in[1], in[2], in[3]};
}
math::Matrix4f matrix_from_node(const tinygltf::Node& node) {
if (!node.matrix.empty()) {
math::Matrix4f result;
for (int i = 0; i < 16; i++) {
result.data()[i] = node.matrix[i];
}
return result;
} else {
// from trs
math::Matrix4f t, r, s;
if (!node.translation.empty()) {
t = affine_translation(vector3f_from_gltf(node.translation));
} else {
t = math::Matrix4f::identity();
}
if (!node.rotation.empty()) {
r = affine_rot_qxyzw(vector4f_from_gltf(node.rotation));
} else {
r = math::Matrix4f::identity();
}
if (!node.scale.empty()) {
s = affine_scale(vector3f_from_gltf(node.scale));
} else {
s = math::Matrix4f::identity();
}
return t * r * s;
}
}
/*!
* Recursively walk the tree of nodes, flatten, and compute w_T_node for each.
*/
void node_find_helper(const tinygltf::Model& model,
const math::Matrix4f& w_T_parent,
int node_idx,
std::vector<NodeWithTransform>* out) {
const auto& node = model.nodes.at(node_idx);
math::Matrix4f w_T_node = w_T_parent * matrix_from_node(node);
out->push_back({node_idx, w_T_node});
for (auto& child : node.children) {
node_find_helper(model, w_T_node, child, out);
}
}
std::vector<NodeWithTransform> flatten_nodes_from_all_scenes(const tinygltf::Model& model) {
std::vector<NodeWithTransform> out;
for (auto& scene : model.scenes) {
for (auto& nidx : scene.nodes) {
math::Matrix4f identity = math::Matrix4f::identity();
node_find_helper(model, identity, nidx, &out);
}
}
return out;
}
void dedup_vertices(const std::vector<tfrag3::PreloadedVertex>& vertices_in,
std::vector<tfrag3::PreloadedVertex>& vertices_out,
std::vector<u32>& old_to_new_out) {
ASSERT(vertices_out.empty());
ASSERT(old_to_new_out.empty());
old_to_new_out.resize(vertices_in.size(), -1);
std::unordered_map<tfrag3::PreloadedVertex, u32, tfrag3::PreloadedVertex::hash> vtx_to_new;
for (size_t in_idx = 0; in_idx < vertices_in.size(); in_idx++) {
auto& vtx = vertices_in[in_idx];
const auto& lookup = vtx_to_new.find(vtx);
if (lookup == vtx_to_new.end()) {
// first time seeing this one
size_t new_idx = vertices_out.size();
vertices_out.push_back(vtx);
old_to_new_out[in_idx] = new_idx;
vtx_to_new[vtx] = new_idx;
} else {
old_to_new_out[in_idx] = lookup->second;
}
}
}
DrawMode draw_mode_from_sampler(const tinygltf::Sampler& sampler) {
DrawMode mode = make_default_draw_mode();
if (sampler.magFilter == TINYGLTF_TEXTURE_FILTER_NEAREST) {
ASSERT(sampler.minFilter == TINYGLTF_TEXTURE_FILTER_NEAREST);
mode.set_filt_enable(false);
} else {
ASSERT(sampler.minFilter != TINYGLTF_TEXTURE_FILTER_NEAREST);
mode.set_filt_enable(true);
}
switch (sampler.wrapS) {
case TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE:
mode.set_clamp_s_enable(true);
break;
case TINYGLTF_TEXTURE_WRAP_REPEAT:
mode.set_clamp_s_enable(false);
break;
default:
ASSERT(false);
}
switch (sampler.wrapT) {
case TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE:
mode.set_clamp_t_enable(true);
break;
case TINYGLTF_TEXTURE_WRAP_REPEAT:
mode.set_clamp_t_enable(false);
break;
default:
ASSERT(false);
}
return mode;
}
} // namespace gltf_util
+71
View File
@@ -0,0 +1,71 @@
#pragma once
#include <string>
#include <unordered_map>
#include <vector>
#include "common/common_types.h"
#include "common/custom_data/Tfrag3Data.h"
#include "common/math/Vector.h"
#include "third-party/tiny_gltf/tiny_gltf.h"
namespace gltf_util {
/*!
* Convert a GLTF index buffer to std::vector<u32>
*/
template <typename T>
std::vector<u32> index_list_to_u32(const u8* data, u32 num_verts, u32 offset, u32 stride) {
std::vector<u32> result;
result.reserve(num_verts);
for (u32 i = 0; i < num_verts; i++) {
T val;
memcpy(&val, data, sizeof(T));
result.push_back(offset + val);
data += stride;
}
return result;
}
std::vector<math::Vector3f> extract_vec3f(const u8* data, u32 count, u32 stride);
std::vector<math::Vector2f> extract_vec2f(const u8* data, u32 count, u32 stride);
std::vector<math::Vector<u8, 4>> extract_color_from_vec4_u16(const u8* data, u32 count, u32 stride);
std::vector<u32> gltf_index_buffer(const tinygltf::Model& model, int indices_idx, u32 index_offset);
struct ExtractedVertices {
std::vector<tfrag3::PreloadedVertex> vtx;
std::vector<math::Vector<u8, 4>> vtx_colors;
std::vector<math::Vector3f> normals;
};
ExtractedVertices gltf_vertices(const tinygltf::Model& model,
const std::map<std::string, int>& attributes,
const math::Matrix4f& w_T_local,
bool get_colors,
bool get_normals,
const std::string& debug_name);
DrawMode make_default_draw_mode();
struct TexturePool {
std::unordered_map<std::string, int> textures_by_name;
std::vector<tfrag3::Texture> textures_by_idx;
};
int texture_pool_add_texture(TexturePool* pool, const tinygltf::Image& tex);
int texture_pool_debug_checker(TexturePool* pool);
struct NodeWithTransform {
int node_idx;
math::Matrix4f w_T_node;
};
void dedup_vertices(const std::vector<tfrag3::PreloadedVertex>& vertices_in,
std::vector<tfrag3::PreloadedVertex>& vertices_out,
std::vector<u32>& old_to_new_out);
std::vector<NodeWithTransform> flatten_nodes_from_all_scenes(const tinygltf::Model& model);
DrawMode draw_mode_from_sampler(const tinygltf::Sampler& sampler);
} // namespace gltf_util
+3 -3
View File
@@ -27,11 +27,11 @@ Range<int> parse_json_optional_integer_range(const nlohmann::json& json);
}
template <typename T>
void json_get_optional(const nlohmann::json& json,
void json_get_optional(const nlohmann::json& j,
const std::string& key,
std::optional<T>& optionalValue) {
if (json.contains(key) && !json[key].is_null()) {
optionalValue = json[key].get<T>();
if (j.contains(key) && !j[key].is_null()) {
optionalValue = j[key].get<T>();
}
}
+17 -8
View File
@@ -3,20 +3,29 @@
#include "common/common_types.h"
#include "common/log/log.h"
#ifdef __linux__
#ifdef _WIN32
// clang-format off
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <psapi.h>
// clang-format on
size_t get_peak_rss() {
HANDLE hProcess = GetCurrentProcess();
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) {
return pmc.PeakWorkingSetSize;
} else {
return 0;
}
}
#else
#include <sys/resource.h>
size_t get_peak_rss() {
rusage x;
getrusage(RUSAGE_SELF, &x);
return x.ru_maxrss * 1024;
}
#else
size_t get_peak_rss() {
return 0;
}
#endif
#ifdef _WIN32
-1
View File
@@ -3,7 +3,6 @@
#include <cstddef>
#include <string>
// Note: these are not implemented on windows and will return zero.
size_t get_peak_rss();
void setup_cpu_info();
-3
View File
@@ -7,9 +7,6 @@
// A normal Trie does not allow for duplicate keys, however this one does
// It allows for insertion and removal
//
// Note, keys assume only basic ASCII, which is _fine_ as OpenGOAL itself has this
// limitation as well.
template <typename T>
class TrieWithDuplicates {
private:
@@ -5,13 +5,13 @@ Disclaimer: custom levels are still in development and are missing most features
The first three steps are already done for "test zone", so this can be used as a starting point.
# 1: File Setup
To create a custom level, copy the layout of `custom_levels/test-zone`. See `test-zone.jsonc` for information on how to name things. The `.gd` file also contains the level name.
To create a custom level, copy the layout of `custom_assets/jak1/levels/test-zone`. See `test-zone.jsonc` for information on how to name things. The `.gd` file also contains the level name.
# 2: Modify the engine
Modify `goal_src/engine/level/level-info.gc` to add level info for each custom level. There is level info for `test-zone` at the bottom that can be used as an example.
Modify `goal_src/jak1/engine/level/level-info.gc` to add level info for each custom level. There is level info for `test-zone` at the bottom that can be used as an example.
# 3: Modify the build system
Modify `goal_src/game.gp` and add a custom level target:
Modify `goal_src/jak1/game.gp` and add a custom level target:
```lisp
(build-custom-level "test-zone")
;; the DGO file
@@ -21,7 +21,7 @@ Modify `goal_src/game.gp` and add a custom level target:
# 4: Export the GLTF file from blender.
For now, all meshes are displayed and treated as ground collision. This causes buggy collision because walls shouldn't use "floor" mode.
Blender will create a `.glb` file, which must have the name specified in the `.jsonc` file and should be located in `custom_level/your_level`
Blender will create a `.glb` file, which must have the name specified in the `.jsonc` file and should be located in `custom_assets/jak1/levels/your_level`
# 5: Rebuild the game
Any time the `.glb` file is changed, you must rebuild the game. Launch the compiler (`goalc`) and run `(mi)` to rebuild everything. It's recommended to leave the compiler open - it will remember files that haven't changed and skip rebuilding them.
File renamed without changes.
@@ -10,7 +10,7 @@
// Must have vertex colors. Use the blender cycles renderer, bake, diffuse, uncheck color,
// and bake to vertex colors. For now, only the first vertex color group is used, so make sure you
// only have 1.
"gltf_file": "custom_levels/jak1/test-zone/test-zone2.glb",
"gltf_file": "custom_assets/jak1/levels/test-zone/test-zone2.glb",
// automatically set wall vs. ground based on angle. Useful if you don't want to assign this yourself
"automatic_wall_detection": true,
@@ -55,20 +55,22 @@
// adds a 'symbol' tag (using the 'type' and 'string' lump types works the same way):
// "symbol-list": ["symbol", "sym-1", "sym-2"]
// The base actor id for your custom level. If you have multiple levels this should be unique!
"base_id": 100,
// The base actor id for your custom level. If you have multiple levels, this should be unique!
"base_id": 100,
// All art groups you want to use in your custom level. Will add their models and corresponding textures to the FR3 file.
// Note: You will still have to add them to your level's .gd file.
// Removed so that the release builds don't have to double-decompile the game
// "art_groups": ["plat-ag"],
"art_groups": [],
// Any textures you want to include in your custom level. This is mainly useful for things such as the zoomer HUD,
// which is not in the common level files and has no art group associated with it.
// To get a list of all the textures, you can extract all of the game's textures
// by setting "save_texture_pngs" to true in the decompiler config.
"textures": [
// If you have any custom models in the "custom_assets/jak1/models/custom_levels" folder that you want to use in your level, add them to this list.
// Note: Like with art groups, these should also be added to your level's .gd file.
"custom_models": ["test-actor"],
// Any textures you want to include in your custom level. This is mainly useful for things such as the zoomer HUD,
// which is not in the common level files and has no art group associated with it.
// To get a list of all the textures, you can extract all of the game's textures
// by setting "save_texture_pngs" to true in the decompiler config.
"textures": [
// all textures required for the zoomer HUD
// "zoomerhud",
// "zoomerhud-dial",
@@ -130,6 +132,16 @@
"lump": {
"name": "test-eco"
}
},
{
"trans": [-5.41, 3.5, 28.42], // translation
"etype": "test-actor", // actor type
"game_task": 0, // associated game task (for powercells, etc)
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-7.41, 3.5, 28.42, 10], // bounding sphere
"lump": {
"name": "test-actor"
}
}
// {
// "trans": [-7.41, 3.5, 28.42], // translation
@@ -4,6 +4,8 @@
;; the actual file name still needs to be 8.3
("TSZ.DGO"
("static-screen.o"
"test-zone.go"
"test-zone-obs.o"
"plat-ag.go"
"test-actor-ag.go"
"test-zone.go"
))
@@ -10,7 +10,7 @@
// Must have vertex colors. Use the blender cycles renderer, bake, diffuse, uncheck color,
// and bake to vertex colors. For now, only the first vertex color group is used, so make sure you
// only have 1.
"gltf_file": "custom_levels/jak2/test-zone/test-zone2.glb",
"gltf_file": "custom_assets/jak2/levels/test-zone/test-zone2.glb",
// automatically set wall vs. ground based on angle. Useful if you don't want to assign this yourself
"automatic_wall_detection": true,
@@ -0,0 +1,90 @@
{
// The "in-game" name of the level. Should be lower case, with dashes (GOAL symbol name)
// the name of this file, and the folder this file is in must have the same name.
"long_name": "test-zone",
// The file name, should be upper case and 8 characters or less.
"iso_name": "TESTZONE",
// The nickname, should be exactly 3 characters
"nickname": "tsz", // 3 char name, all lowercase
// Background mesh file.
// Must have vertex colors. Use the blender cycles renderer, bake, diffuse, uncheck color,
// and bake to vertex colors. For now, only the first vertex color group is used, so make sure you
// only have 1.
"gltf_file": "custom_assets/jak3/levels/test-zone/test-zone2.glb",
// automatically set wall vs. ground based on angle. Useful if you don't want to assign this yourself
"automatic_wall_detection": true,
"automatic_wall_angle": 45.0,
// if your mesh has triangles with incorrect orientation, set this to make all collision mesh triangles double sided
// this makes collision 2x slower and bigger, so only use if really needed
"double_sided_collide": false,
// available res-lump tag types:
// integer types: int32, uint32, enum-int32, enum-uint32
// float types: float, meters (1 meter = 4096.0 units), degrees (65536.0 = 360°)
// vector types: vector (normal floats), vector4m (meters), vector3m (meters with w set to 1.0), vector-vol (normal floats with w in meters), movie-pos (meters with w in degrees)
// special types: symbol, type, string, eco-info, cell-info, buzzer-info, water-height
//
// examples:
//
// adds a float tag 'spring-height' with value of 200 meters (1 meter = 4096.0 units):
// "spring-height": ["meters", 200.0]
//
// adds a degrees tag 'rotoffset':
// "rotoffset": ["degrees", -45.0]
//
// adds a movie-pos tag:
// "movie-pos": ["movie-pos", [100.22, -25.3, 99.5, 180.0]]
//
// adds an enum tag 'options':
// "options": ["enum-int32", "(fact-options large)"]
//
// adds a water-height tag:
// "water-height": ["water-height", 25.0, 0.5, 2.0, "(water-flags can-swim can-wade)"]
//
// adds an eco-info tag:
// "eco-info": ["eco-info", "(pickup-type health)", 2]
//
// adds a 'type' tag (using the "symbol" and "string" lump types works the same way):
// "spawn-types": ["type", "spyder", "juicer"]
// The base actor id for your custom level. If you have multiple levels, this should be unique!
"base_id": 100,
// All art groups you want to use in your custom level. Will add their models and corresponding textures to the FR3 file.
// "art_groups": [],
// Any textures you want to include in your custom level.
// This is mainly useful for textures which are not in the common level files and have no art group associated with them.
// To get a list of all the textures, you can extract all of the game's textures
// by setting "save_texture_pngs" to true in the decompiler config.
// "textures": [],
"actors" : [
{
"trans": [-15.2818, 15.2461, 17.1360], // translation
"etype": "crate", // actor type
"game_task": "(game-task none)", // associated game task (for powercells, etc)
"kill_mask": 0,
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-15.2818, 15.2461, 17.1360, 10], // bounding sphere
"lump": {
"name": "test-crate",
"eco-info": ["eco-info", "(pickup-type gem)", 1]
}
},
{
"trans": [-5.4630, 17.4553, 1.6169], // translation
"etype": "eco-yellow", // actor type
"game_task": "(game-task none)", // associated game task (for powercells, etc)
"kill_mask": 0,
"quat": [0, 0, 0, 1], // quaternion
"bsphere": [-5.4630, 17.4553, 1.6169, 10], // bounding sphere
"lump": {
"name": "test-eco"
}
}
]
}
Binary file not shown.
@@ -0,0 +1,8 @@
;; DGO definition file for Awful Village level
;; We use the convention of having a longer DGO name for levels without precomputed visibility.
;; the actual file name still needs to be 8.3
("TSZ.DGO"
("test-zone.go"
)
)
+4 -1
View File
@@ -58,6 +58,7 @@ add_library(
level_extractor/extract_actors.cpp
level_extractor/extract_collide_frags.cpp
level_extractor/extract_common.cpp
level_extractor/extract_hfrag.cpp
level_extractor/extract_joint_group.cpp
level_extractor/extract_level.cpp
level_extractor/extract_merc.cpp
@@ -67,6 +68,7 @@ add_library(
level_extractor/fr3_to_gltf.cpp
level_extractor/MercData.cpp
level_extractor/tfrag_tie_fixup.cpp
level_extractor/merc_replacement.cpp
ObjectFile/LinkedObjectFile.cpp
ObjectFile/LinkedObjectFileCreation.cpp
@@ -88,7 +90,8 @@ add_library(
VuDisasm/VuDisassembler.cpp
VuDisasm/VuInstruction.cpp
config.cpp)
config.cpp
decompilation_process.cpp)
target_link_libraries(decomp
lzokay
@@ -6586,6 +6586,10 @@ bool try_vector_reset_inline(const Env& env,
RegisterAccess orig;
store = repop_passthrough_arg(store, stack, env, &orig, &got_orig);
if (!store) {
return false;
}
// create the actual form
Form* new_thing = pool.form<GenericElement>(
GenericOperator::make_function(pool.form<ConstantTokenElement>("vector-reset!")),
+4
View File
@@ -760,6 +760,10 @@ bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out, const Env* cons
break;
}
if (entries_matched == m_entry_matchers.size()) {
break;
}
if (m_entry_matchers.at(entries_matched)
.do_match(let_body->entries().at(0), maps_out, env)) {
entries_matched++;
+1 -1
View File
@@ -25,7 +25,7 @@ namespace decompiler {
*/
class LinkedObjectFile {
public:
LinkedObjectFile(GameVersion version) : version(version){};
LinkedObjectFile(GameVersion _version) : version(_version) {}
void set_segment_count(int n_segs);
void push_back_word_to_segment(uint32_t word, int segment);
int get_label_id_for(int seg, int offset);
+2 -2
View File
@@ -332,7 +332,7 @@ class ObjectFileDB {
void for_each_function_def_order(Func f) {
for_each_obj([&](ObjectFileData& data) {
for (int i = 0; i < int(data.linked_data.segments); i++) {
int fn = 0;
[[maybe_unused]] int fn = 0;
for (size_t j = data.linked_data.functions_by_seg.at(i).size(); j-- > 0;) {
f(data.linked_data.functions_by_seg.at(i).at(j), i, data);
fn++;
@@ -355,7 +355,7 @@ class ObjectFileDB {
template <typename Func>
void for_each_function_in_seg(int seg, Func f) {
for_each_obj([&](ObjectFileData& data) {
int fn = 0;
[[maybe_unused]] int fn = 0;
if (data.linked_data.segments == 3) {
for (size_t j = data.linked_data.functions_by_seg.at(seg).size(); j-- > 0;) {
f(data.linked_data.functions_by_seg.at(seg).at(j), data);
+16 -2
View File
@@ -5,6 +5,7 @@
#include "ObjectFileDB.h"
#include "common/formatter/formatter.h"
#include "common/goos/PrettyPrinter.h"
#include "common/link_types.h"
#include "common/log/log.h"
@@ -872,9 +873,22 @@ void ObjectFileDB::ir2_write_results(const fs::path& output_dir,
auto file_name = output_dir / (obj.to_unique_name() + "_ir2.asm");
file_util::write_text_file(file_name, file_text);
auto final = ir2_final_out(obj, imports, {});
auto unformatted_code = ir2_final_out(obj, imports, {});
auto final_name = output_dir / (obj.to_unique_name() + "_disasm.gc");
file_util::write_text_file(final_name, final);
if (config.format_code) {
const auto formatted_code = formatter::format_code(unformatted_code);
if (!formatted_code) {
lg::error(
"Was unable to format the decompiled result of {}, make a github issue. Writing "
"unformatted code",
obj.to_unique_name());
file_util::write_text_file(final_name, unformatted_code);
} else {
file_util::write_text_file(final_name, formatted_code.value());
}
} else {
file_util::write_text_file(final_name, unformatted_code);
}
}
}
+2 -6
View File
@@ -54,12 +54,8 @@ void append_body_to_function_definition(goos::Object* top_form,
body_elements.insert(body_elements.end(), inline_body.begin(), inline_body.end());
// If the first element in the body is a docstring, add it first
if (body_elements.size() > 0 && body_elements.at(0).is_string()) {
if (version > GameVersion::Jak2) {
initial_top_level_forms.push_back(
goos::StringObject::make_new(fix_docstring_indent(inline_body.at(0).as_string()->data)));
} else {
initial_top_level_forms.push_back(inline_body.at(0));
}
initial_top_level_forms.push_back(
goos::StringObject::make_new(fix_docstring_indent(inline_body.at(0).as_string()->data)));
body_elements.erase(body_elements.begin());
}
+6 -1
View File
@@ -64,7 +64,6 @@ Config make_config_via_json(nlohmann::json& json) {
inputs_json.at("str_art_file_names").get<std::vector<std::string>>();
}
config.audio_dir_file_name = inputs_json.at("audio_dir_file_name").get<std::string>();
config.streamed_audio_file_names =
inputs_json.at("streamed_audio_file_names").get<std::vector<std::string>>();
@@ -96,6 +95,9 @@ Config make_config_via_json(nlohmann::json& json) {
}
config.disassemble_code = json.at("disassemble_code").get<bool>();
config.decompile_code = json.at("decompile_code").get<bool>();
if (json.contains("format_code")) {
config.format_code = json.at("format_code").get<bool>();
}
config.write_hex_near_instructions = json.at("write_hex_near_instructions").get<bool>();
config.write_scripts = json.at("write_scripts").get<bool>();
config.disassemble_data = json.at("disassemble_data").get<bool>();
@@ -318,6 +320,9 @@ Config make_config_via_json(nlohmann::json& json) {
if (json.contains("save_texture_pngs")) {
config.save_texture_pngs = json.at("save_texture_pngs").get<bool>();
}
if (json.contains("rip_streamed_audio")) {
config.rip_streamed_audio = json.at("rip_streamed_audio").get<bool>();
}
if (inputs_json.contains("animated_textures")) {
config.animated_textures =
+2 -2
View File
@@ -102,8 +102,6 @@ struct Config {
std::vector<std::string> str_file_names;
std::vector<std::string> str_texture_file_names;
std::vector<std::string> str_art_file_names;
std::string audio_dir_file_name;
std::vector<std::string> streamed_audio_file_names;
std::string obj_file_name_map_file;
@@ -111,6 +109,7 @@ struct Config {
bool disassemble_code = false;
bool decompile_code = false;
bool format_code = false;
bool write_scripts = false;
bool disassemble_data = false;
bool process_tpages = false;
@@ -174,6 +173,7 @@ struct Config {
std::vector<std::string> levels_to_extract;
bool levels_extract;
bool save_texture_pngs = false;
bool rip_streamed_audio = false;
DecompileHacks hacks;
+11 -11
View File
@@ -21102,7 +21102,7 @@
:size-assert #x94
:flag-assert #xf00300094
(:methods
(dumb-15 (_type_) none))
(spawn-particles! (_type_) none))
(:states
hud-normal
hud-coming-in
@@ -22303,20 +22303,20 @@
;; - Functions
(define-extern calculate-rotation-and-color-for-slice (function int float int int int hud-particle none))
(define-extern part-hud-health-01-func (function basic basic hud-particle none)) ;; TODO - i figured this out on another branch...all these particle functions get called by the particle system with the same beginning types iirc
(define-extern part-hud-health-02-func (function basic basic hud-particle none))
(define-extern part-hud-health-03-func (function basic basic hud-particle none))
(define-extern calculate-rotation-and-color-for-slice (function int float int int int matrix none))
(define-extern part-hud-health-01-func (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern part-hud-health-02-func (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern part-hud-health-03-func (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern fuel-cell-hud-orbit-callback (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern fuel-cell-hud-starburst-3-callback (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern fuel-cell-hud-starburst-4-callback (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern fuel-cell-hud-center-callback (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern part-hud-buzzer-func (function basic basic hud-particle none))
(define-extern part-hud-eco-timer-01-func (function basic basic hud-particle none))
(define-extern part-hud-eco-timer-02-func (function basic basic hud-particle none))
(define-extern part-hud-eco-timer-03-func (function basic basic hud-particle none))
(define-extern part-hud-eco-timer-backing-func (function basic basic hud-particle none))
(define-extern part-hud-eco-timer-func (function basic basic hud-particle none))
(define-extern part-hud-buzzer-func (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern part-hud-eco-timer-01-func (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern part-hud-eco-timer-02-func (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern part-hud-eco-timer-03-func (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern part-hud-eco-timer-backing-func (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern part-hud-eco-timer-func (function sparticle-system sparticle-cpuinfo matrix none))
(define-extern show-hud (function none))
;; - Unknowns
+7
View File
@@ -23,6 +23,10 @@
// run the first pass of the decompiler
"find_functions": true,
// will attempt to run the decompiled output through the OpenGOAL formatter
// this will be skipped in offline tests
"format_code": true,
////////////////////////////
// DATA ANALYSIS OPTIONS
////////////////////////////
@@ -118,6 +122,9 @@
// save game textures as .png files to decompiler_out/<game>/textures
"save_texture_pngs": false,
// whether or not to dump out streamed audio files to decompiler_out/<game>/audio
"rip_streamed_audio": false,
////////////////////////////
// PATCHING OPTIONS
////////////////////////////
+1 -1
View File
@@ -634,7 +634,7 @@
// there are some missing textures. I don't know what the game actually does here.
// the format for entries is [level, tpage, index]
"missing_textures": [["finalboss-vis", 1419, 3]],
"missing_textures": [["finalboss", 1419, 3]],
// some object files have garbage pad data at the end which makes the decompiler
// assume they must be different files, such as the art group for orb-cache-top.
@@ -258,10 +258,6 @@
"TEXT/6COMMON.TXT"
],
// uncomment the next line to extract audio to wave files.
//"audio_dir_file_name": "jak1/VAG",
"audio_dir_file_name": "",
"streamed_audio_file_names": [
"VAGWAD.ENG",
"VAGWAD.FRE",
@@ -228,9 +228,5 @@
"TEXT/6COMMON.TXT"
],
// uncomment the next line to extract audio to wave files.
//"audio_dir_file_name": "jak1/VAG",
"audio_dir_file_name": "",
"streamed_audio_file_names": ["VAGWAD.ENG", "VAGWAD.JAP"]
}
+14
View File
@@ -2515,6 +2515,7 @@
(iop-mem 48)
(cancel-dgo 49)
(set-stereo-mode 50) ;; sound-rpc-set-stereo-mode
(set-mirror 201)
)
(defenum sound-group
@@ -2829,6 +2830,17 @@
:flag-assert #x900000004
)
; added
(defenum sound-mirror-mode
:type uint8
(normal)
(mirrored)
)
; added for mirror mode
(deftype sound-rpc-set-mirror-mode (sound-rpc-cmd)
((mirror sound-mirror-mode)))
(deftype sound-rpc-union (structure)
((data uint32 20 :offset-assert 0)
(load-bank sound-rpc-load-bank :offset 0)
@@ -2852,6 +2864,7 @@
(shutdown sound-rpc-shutdown :offset 0)
(list-sounds sound-rpc-list-sounds :offset 0)
(unload-music sound-rpc-unload-music :offset 0)
(mirror-mode sound-rpc-set-mirror-mode :overlay-at (-> data 0))
)
:method-count-assert 9
:size-assert #x50
@@ -8774,6 +8787,7 @@ Unlike [[engine]], users can use [[engine-pers]] as a parent class."
(progress-graphics-ps2-lod-dist #x1337)
(progress-graphics-msaa-off #x1338)
(progress-graphics-display #x1339)
(language-name-finnish #x133a)
)
;; ---text-id-h:text-id
+3
View File
@@ -127,6 +127,9 @@
"rip_collision": false,
// save game textures as .png files to decompiler_out/<game>/textures
"save_texture_pngs": false,
// whether or not to dump out streamed audio files to decompiler_out/<game>/audio
"rip_streamed_audio": false,
////////////////////////////
// PATCHING OPTIONS
+1 -1
View File
@@ -769,7 +769,7 @@
// there are some missing textures. I don't know what the game actually does here.
// the format for entries is [level, tpage, index]
"missing_textures": [
["vinroom-vis", 0, 0],
["vinroom", 0, 0],
["ctyfence", 0, 0]
],
@@ -441,10 +441,6 @@
"TEXT/7COMMON.TXT"
],
// uncomment the next line to extract audio to wave files.
// "audio_dir_file_name": "jak2/VAG",
"audio_dir_file_name": "",
"streamed_audio_file_names": [
"VAGWAD.ENG",
"VAGWAD.FRE",
File diff suppressed because it is too large. Load diff
+3
View File
@@ -127,6 +127,9 @@
// save game textures as .png files to decompiler_out/<game>/textures
"save_texture_pngs": false,
// whether or not to dump out streamed audio files to decompiler_out/<game>/audio
"rip_streamed_audio": false,
////////////////////////////
// PATCHING OPTIONS
////////////////////////////
@@ -138,7 +138,7 @@
[7, "(function none)"],
[3, "(function symbol :behavior process)"]
],
"scene": [[4, "(function none :behavior scene-player)"]],
"scene": [[4, "(function symbol :behavior scene-player)"]],
"pov-camera": [
[
7,
@@ -615,5 +615,390 @@
"wvehicle": [[6, "(function collide-shape-prim none)"]],
"pilot-states": [
[15, "(function surface surface surface int object :behavior target)"]
],
"was-squad-control": [[16, "(function object object)"]],
"des-cactus": [[13, "(function collide-shape-prim none)"]],
"desertg-obs": [
[4, "(function collide-shape-prim none)"],
[7, "(function collide-shape-prim none)"]
],
"desertf-obs": [[7, "(function none)"]],
"temple-obs2": [
[43, "(function symbol)"],
[46, "(function object :behavior tpl-watcher)"]
],
"temple-scenes": [
[0, "(function none)"],
[1, "(function none)"],
[2, "(function none)"],
[3, "(function none :behavior scene-player)"],
[4, "(function none :behavior scene-player)"]
],
"des-beast-2": [
[1, "(function cspace transformq none)"],
[2, "(function cspace transformq none)"],
[23, "(function projectile none)"]
],
"scorpion-gun": [
[33, "(function cspace transformq none)"],
[34, "(function cspace transformq none)"]
],
"hover-formation": [
[10, "(function form-search-info float)"],
[11, "(function int int form-search-info uint)"],
[14, "(function vector object)"],
[15, "(function int int (pointer object) int)"]
],
"robo-hover": [
[14, "(function robo-hover cspace float float vector vector int object)"]
],
"tower-scenes": [
[0, "(function none :behavior scene-player)"],
[1, "(function none :behavior scene-player)"]
],
"forest-kill-plants": [
[5, "(function engine-pers connection-pers object object symbol)"],
[7, "(function engine-pers connection-pers object object symbol)"]
],
"forest-tasks": [
[0, "(function none :behavior scene-player)"],
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"],
[3, "(function none :behavior scene-player)"],
[4, "(function none :behavior scene-player)"],
[5, "(function none :behavior scene-player)"],
[6, "(function none :behavior scene-player)"],
[7, "(function none :behavior scene-player)"],
[8, "(function none :behavior scene-player)"],
[9, "(function none :behavior scene-player)"],
[10, "(function none :behavior scene-player)"],
[11, "(function none :behavior scene-player)"],
[12, "(function none :behavior scene-player)"],
[13, "(function none :behavior scene-player)"],
[14, "(function none :behavior scene-player)"],
[15, "(function none :behavior scene-player)"],
[16, "(function none :behavior scene-player)"],
[17, "(function none :behavior scene-player)"],
[18, "(function none :behavior scene-player)"],
[19, "(function none :behavior scene-player)"],
[20, "(function none :behavior scene-player)"],
[21, "(function none :behavior scene-player)"]
],
"neo-wasp": [[15, "(function neo-wasp cspace transformq float float none)"]],
"for-turret": [
[1, "(function cspace transformq none)"],
[2, "(function cspace transformq none)"],
[3, "(function cspace transformq none)"],
[4, "(function cspace transformq none)"]
],
"volcano-obs": [[38, "(function cspace transformq none)"]],
"spiky-frog": [[9, "(function cspace transformq none)"]],
"volcano-scenes": [
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"]
],
"mantis": [
[8, "(function mantis vector float int vector vector)"],
[15, "(function mantis collide-shape-moving vector symbol)"]
],
"wcar-faccar": [[9, "(function handle object :behavior process)"]],
"wasstadb-obs": [[5, "(function object)"]],
"arena-scenes": [
[0, "(function none :behavior scene-player)"],
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"],
[3, "(function none :behavior scene-player)"],
[4, "(function none :behavior scene-player)"],
[5, "(function none :behavior scene-player)"],
[6, "(function none :behavior scene-player)"],
[7, "(function none :behavior scene-player)"],
[8, "(function none :behavior scene-player)"],
[9, "(function none :behavior scene-player)"]
],
"traffic-engine": [
[24, "(function traffic-find-segment-struct nav-segment none)"]
],
"desert-scenes": [
[5, "(function none :behavior scene-player)"],
[6, "(function none :behavior scene-player)"],
[7, "(function none :behavior scene-player)"],
[8, "(function none :behavior scene-player)"],
[9, "(function none :behavior scene-player)"],
[10, "(function none :behavior scene-player)"],
[11, "(function none :behavior scene-player)"],
[12, "(function none :behavior scene-player)"],
[13, "(function none :behavior scene-player)"],
[14, "(function none :behavior scene-player)"],
[15, "(function none :behavior scene-player)"],
[16, "(function none :behavior scene-player)"],
[17, "(function none :behavior scene-player)"],
[18, "(function none :behavior scene-player)"],
[19, "(function none :behavior scene-player)"],
[20, "(function none :behavior scene-player)"],
[21, "(function none :behavior scene-player)"],
[22, "(function none :behavior scene-player)"],
[23, "(function none :behavior scene-player)"],
[24, "(function none :behavior scene-player)"],
[25, "(function none :behavior scene-player)"],
[26, "(function none :behavior scene-player)"],
[27, "(function none :behavior scene-player)"],
[28, "(function none :behavior scene-player)"],
[29, "(function none :behavior scene-player)"],
[30, "(function none :behavior scene-player)"],
[31, "(function none :behavior scene-player)"],
[32, "(function none :behavior scene-player)"],
[33, "(function none :behavior scene-player)"],
[34, "(function none :behavior scene-player)"],
[35, "(function none :behavior scene-player)"],
[36, "(function symbol :behavior scene-player)"]
],
"throne-scenes": [[0, "(function none :behavior scene-player)"]],
"terraformer-setup": [[38, "(function object :behavior manipy)"]],
"mined-scenes": [
[6, "(function none :behavior scene-player)"],
[7, "(function process-drawable vector none :behavior scene-player)"],
[8, "(function process-drawable vector none :behavior scene-player)"]
],
"wasteland-scenes": [
[0, "(function none :behavior scene-player)"],
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"],
[3, "(function none :behavior scene-player)"],
[4, "(function none :behavior scene-player)"],
[5, "(function none :behavior scene-player)"],
[6, "(function none :behavior scene-player)"],
[7, "(function none :behavior scene-player)"],
[8, "(function none :behavior scene-player)"],
[9, "(function none :behavior scene-player)"],
[10, "(function none :behavior scene-player)"]
],
"wasdoors-scenes": [[2, "(function none :behavior scene-player)"]],
"wasdef-manager": [
[7, "(function process-tree object)"],
[8, "(function process-tree object)"],
[9, "(function process-tree object)"]
],
"des-burning-bush": [[37, "(function symbol)"]],
"mh-wasp": [
[9, "(function mh-wasp cspace float float vector vector int none)"]
],
"mh-bat": [
[1, "(function cspace transformq none)"],
[21, "(function object :behavior mh-bat)"],
[26, "(function object :behavior mh-bat)"],
[30, "(function object :behavior mh-bat)"],
[34, "(function object :behavior mh-bat)"],
[39, "(function object :behavior mh-bat)"]
],
"factoryc-obs2": [
[67, "(function (pointer joint-exploder) :behavior fac-break-floor)"]
],
"factory-scenes": [
[0, "(function none :behavior scene-player)"],
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"],
[3, "(function none :behavior scene-player)"],
[4, "(function none :behavior scene-player)"],
[5, "(function none :behavior scene-player)"],
[6, "(function none :behavior scene-player)"],
[7, "(function none :behavior scene-player)"],
[8, "(function none :behavior scene-player)"],
[9, "(function none :behavior scene-player)"],
[10, "(function process-drawable none :behavior scene-player)"],
[11, "(function none :behavior scene-player)"],
[12, "(function none :behavior scene-player)"],
[13, "(function none :behavior scene-player)"],
[14, "(function none :behavior scene-player)"],
[15, "(function none :behavior scene-player)"]
],
"factory-boss-setup": [[37, "(function object :behavior manipy)"]],
"factory-boss-scenes": [
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"]
],
"bot": [[25, "(function gui-connection symbol :behavior bot)"]],
"oasis-defense": [
[4, "(function collide-shape-prim none)"],
[11, "(function collide-shape-prim none)"]
],
"ash-oasis-course": [
[0, "(function ashelin-oasis object)"],
[1, "(function ashelin-oasis object)"],
[2, "(function asht-wait-spot ashelin-oasis object)"],
[3, "(function ashelin-oasis symbol)"]
],
"comb-obs": [
[16, "(function collide-shape-prim none)"],
[33, "(function collide-shape-prim none)"],
[49, "(function collide-shape-prim none)"]
],
"comb-sentry": [[19, "(function collide-shape-prim none)"]],
"comb-field": [[5, "(function symbol)"]],
"comb-scenes": [
[0, "(function none :behavior scene-player)"],
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"],
[3, "(function none :behavior scene-player)"],
[4, "(function none :behavior scene-player)"],
[5, "(function none :behavior scene-player)"],
[6, "(function none :behavior scene-player)"],
[7, "(function none :behavior scene-player)"],
[8, "(function none :behavior scene-player)"]
],
"railx-scenes": [
[0, "(function none :behavior scene-player)"],
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"],
[3, "(function none :behavior scene-player)"],
[4, "(function none :behavior scene-player)"],
[5, "(function none :behavior scene-player)"],
[6, "(function none :behavior scene-player)"],
[7, "(function none :behavior scene-player)"],
[8, "(function none :behavior scene-player)"],
[9, "(function none :behavior scene-player)"],
[10, "(function none :behavior scene-player)"],
[11, "(function none :behavior scene-player)"]
],
"title-obs": [
[20, "(function external-art-buffer int)"],
[22, "(function game-task object)"],
[26, "(function vector :behavior manipy)"],
[30, "(function object :behavior manipy)"]
],
"ff-squad-control": [
[6, "(function process-focusable traffic-object-type-info none)"],
[7, "(function process-focusable traffic-object-type-info none)"],
[8, "(function process-focusable traffic-object-type-info none)"],
[9, "(function crimson-guard traffic-object-type-info none)"]
],
"guard": [
[31, "(function crimson-guard collide-shape vector symbol)"],
[49, "(function process city-attacker-info int)"]
],
"guard-tazer": [
[7, "(function collide-shape-prim none)"],
[13, "(function collide-shape-prim none)"]
],
"roboguard-city": [
[13, "(function cspace transformq none)"],
[78, "(function roboguard-city symbol quaternion :behavior process)"]
],
"ctywide-obs": [[93, "(function symbol)"]],
"ctywide-scenes": [
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"],
[3, "(function none :behavior scene-player)"]
],
"ctyport-obs": [[5, "(function collide-shape-prim none)"]],
"ctyport-scenes": [
[3, "(function none :behavior scene-player)"],
[4, "(function none :behavior scene-player)"],
[5, "(function none :behavior scene-player)"],
[6, "(function none :behavior scene-player)"]
],
"ctyport-attack": [[45, "(function object :behavior process)"]],
"intro-scenes": [
[0, "(function none :behavior scene-player)"],
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"],
[3, "(function none :behavior scene-player)"],
[4, "(function none :behavior scene-player)"],
[5, "(function none :behavior scene-player)"],
[6, "(function none :behavior scene-player)"],
[7, "(function none :behavior scene-player)"],
[8, "(function none :behavior scene-player)"],
[9, "(function none :behavior scene-player)"],
[10, "(function none :behavior scene-player)"],
[11, "(function none :behavior scene-player)"],
[12, "(function none :behavior scene-player)"],
[13, "(function none :behavior scene-player)"],
[14, "(function none :behavior scene-player)"],
[15, "(function none :behavior scene-player)"],
[16, "(function none :behavior scene-player)"],
[17, "(function none :behavior scene-player)"],
[18, "(function none :behavior scene-player)"],
[19, "(function none :behavior scene-player)"],
[20, "(function none :behavior scene-player)"],
[21, "(function none :behavior scene-player)"],
[22, "(function none :behavior scene-player)"],
[23, "(function none :behavior scene-player)"],
[24, "(function none :behavior scene-player)"],
[25, "(function none :behavior scene-player)"],
[26, "(function none :behavior scene-player)"],
[27, "(function none :behavior scene-player)"],
[28, "(function none :behavior scene-player)"],
[29, "(function none :behavior scene-player)"],
[30, "(function none :behavior scene-player)"],
[31, "(function none :behavior scene-player)"],
[32, "(function none :behavior scene-player)"],
[33, "(function none :behavior scene-player)"],
[34, "(function none :behavior scene-player)"],
[35, "(function none :behavior scene-player)"],
[36, "(function none :behavior scene-player)"],
[37, "(function none :behavior scene-player)"],
[38, "(function none :behavior scene-player)"],
[39, "(function none :behavior scene-player)"]
],
"freehq-scenes": [[0, "(function none :behavior scene-player)"]],
"hiphog-scenes": [
[0, "(function none :behavior scene-player)"],
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"],
[3, "(function none :behavior scene-player)"]
],
"rubble-attack": [[7, "(function int)"]],
"rublcst-scenes": [
[0, "(function none :behavior scene-player)"],
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"],
[3, "(function none :behavior scene-player)"],
[4, "(function none :behavior scene-player)"],
[5, "(function none :behavior scene-player)"],
[6, "(function none :behavior scene-player)"],
[7, "(function none :behavior scene-player)"],
[8, "(function none :behavior scene-player)"],
[9, "(function none :behavior scene-player)"],
[10, "(function none :behavior scene-player)"],
[11, "(function none :behavior scene-player)"],
[12, "(function none :behavior scene-player)"],
[13, "(function none :behavior scene-player)"]
],
"vinroom-scenes": [
[0, "(function none :behavior scene-player)"],
[1, "(function none :behavior scene-player)"]
],
"gungame-manager": [[6, "(function process symbol)"]],
"blow-tower-obs2": [
[16, "(function bt-mh-flyer cspace float float vector vector int none)"],
[117, "(function bt-roboguard symbol quaternion)"],
[124, "(function cspace transformq none)"]
],
"cty-blow-tower": [
[39, "(function collide-shape-prim none)"],
[27, "(function process symbol)"],
[46, "(function collide-shape-prim none)"],
[69, "(function process object)"]
],
"assault-enemies": [
[36, "(function assault-crimson-guard city-attacker-info int)"]
],
"assault-task": [[11, "(function symbol :behavior process)"]],
"precura-obs": [[98, "(function symbol :behavior process)"]],
"precurd-scenes": [
[0, "(function none :behavior scene-player)"],
[1, "(function none :behavior scene-player)"],
[2, "(function none :behavior scene-player)"],
[3, "(function none :behavior scene-player)"],
[4, "(function none :behavior scene-player)"],
[5, "(function none :behavior scene-player)"],
[6, "(function none :behavior scene-player)"],
[7, "(function none :behavior scene-player)"],
[8, "(function none :behavior scene-player)"],
[9, "(function none :behavior scene-player)"],
[10, "(function none :behavior scene-player)"],
[11, "(function none :behavior scene-player)"],
[12, "(function none :behavior scene-player)"],
[13, "(function none :behavior scene-player)"],
[14, "(function none :behavior scene-player)"]
]
}
+25 -1
View File
@@ -15,7 +15,31 @@
"lightjak-shield": "jakb-ag",
"freeze-screen": "collectables-ag",
"red-3-sphere": "gun-ag",
"gun-dark-3-sphere": "gun-ag"
"gun-dark-3-sphere": "gun-ag",
"marauder": "marauder-male-ag",
"glider-ring": "des-glider-ring-ag",
"flut-racer": "flut-wild-ag",
"was-pre-heart": "neo-satellite-heart-ag",
"was-pre-beam": "neo-satellite-game-ring-ag",
"was-pre-bubble": "neo-satellite-ps-symbols-ag",
"maker": "dm-robot-ag",
"mh-wasp": "neo-wasp-ag",
"factory-boss": "errol-lowres-ag",
"fac-robotank-turret": "fac-robotank-ag",
"neo-sat-shield": "neo-satellite-shield-ag",
"neo-sat": "neo-satellite-ag",
"power-game-switcher": "switcher-ag",
"power-game-player": "daxter-pac-man-ag",
"power-game-glyph": "cipher-ag",
"power-game-rings": "pow-rings-ag",
"power-game-chaser": "flitter-ag",
"power-game-zapper": "grunt-head-ag",
"gungame-door": "fort-entry-gate-ag",
"bt-mh-flyer": "bt-wasp-ag",
"gunship-exploder": "kg-robot-transport-break",
"gunship-engine": "kg-robot-transport-bomb",
"protect-gunship": "kg-robot-transport",
"gunship-missile": "cty-homing-missile"
},
// remap names for types in an entire file (higher priority)
+164 -19
View File
@@ -78,10 +78,6 @@
"blerc-execute",
"foreground-check-longest-edge-asm",
"generic-light-proc",
"shadow-add-single-edges",
"shadow-add-facing-single-tris",
"shadow-add-double-tris",
"shadow-add-double-edges",
"(method 17 collide-edge-work)",
"(method 10 collide-cache-prim)",
"(method 17 collide-cache)",
@@ -107,11 +103,6 @@
// jak 3
"(method 10 manipulator)",
"(method 46 ff-squad-control)",
"(anon-function 65 temple-obs)",
"(method 33 task-manager-nest-cocoons)",
"(method 33 rub-tower)",
"(method 261 crimson-guard)",
"(anon-function 25 volcanox-obs)",
"memcpy"
],
@@ -219,7 +210,19 @@
"borrow-city-expansion",
"add-want-level",
"level-find-borrow-slot",
"(method 18 level)"
"(method 18 level)",
"(method 11 tow-tentacle)",
"city-sound-expand-want-list",
"(method 12 cty-borrow-manager)",
"(method 16 cty-borrow-manager)",
"mark-permanent-holds",
"update-sound-info",
"insert-into-sound-list",
// title-obs
"(anon-function 22 title-obs)",
"cty-faction-evaluate-commands",
"traffic-manager-event-handler",
"(method 20 cty-faction-manager)"
],
// If format is used with the wrong number of arguments,
@@ -265,7 +268,8 @@
"~10Hfg-wa: ~8,,0m": 1,
"~140Hfg-sh: ~8,,0m": 1,
"~267Hfg-p2: ~8,,0m~%": 1,
"~30Hp2: ~8D~131Hhf: ~8D~%~1K": 2
"~30Hp2: ~8D~131Hhf: ~8D~%~1K": 2,
"Current time (~d:~d) [mission-percentage ~f~%": 2
},
"blocks_ending_in_asm_branch": {
@@ -414,7 +418,51 @@
"(method 118 vehicle)": [3, 4, 7, 8, 9, 10, 17, 26, 30, 31, 33],
"(method 25 squad-control)": [0, 4, 5, 7],
"target-pilot-post": [0, 29],
"(method 36 was-squad-control)": [0, 8, 11, 12, 14, 16]
"(method 36 was-squad-control)": [0, 8, 14, 16],
"(anon-function 6 nst-tasks)": [4, 9, 10, 16, 23, 30],
"(method 33 task-manager-nest-cocoons)": [3, 7, 13, 28],
"(method 90 wvehicle)": [29, 37, 38, 44],
"(anon-function 2 artifact-race)": [40, 55, 56, 57, 65, 66],
"(anon-function 27 course-race)": [6],
"(anon-function 65 temple-obs)": [5, 6],
"(anon-function 5 target-turret)": [0, 1, 2, 3],
"dp-bipedal-consider-attacks": [15, 19],
"(anon-function 25 volcanox-obs)": [3, 5, 6],
"(method 36 task-manager-arena-fight-base)": [11],
"(method 28 hud-wasgun)": [0, 1, 2, 4],
"(method 15 hud-wasgun)": [8, 28, 29, 30, 54],
"(method 15 vehicle-controller)": [0, 3, 5, 6, 7, 10],
"(method 51 hvehicle)": [5],
"(method 159 hvehicle)": [0, 1, 10, 19, 21, 23, 26],
"(method 18 vehicle-controller)": [0, 1, 74, 75],
"glider-too-low?": [2, 19, 21],
"(method 39 task-manager-desert-glide)": [0, 3, 4, 9],
"(method 36 task-manager-desert-glide)": [20, 50, 60],
"(method 37 task-manager-desert-glide)": [11, 12, 23, 29, 31],
"(method 34 task-manager-desert-glide)": [3],
"(anon-function 20 target-flut)": [0, 38, 39],
"(anon-function 14 flut-racer)": [7, 17, 19],
"(method 28 conveyor)": [22],
"generic-merc-execute-all": [7, 15],
"check-enemy": [0, 1],
"(method 91 h-warf)": [0],
"(method 51 h-warf)": [5],
"(method 44 nav-graph)": [0, 7, 8, 26, 34],
"(method 15 city-level-info)": [0, 1, 2, 6, 7, 9, 11, 13],
"(method 10 traffic-suppressor)": [0, 1, 2, 4],
"(method 18 traffic-tracker)": [5, 6, 7, 8],
"(method 21 traffic-tracker)": [0],
"(method 9 cty-faction-manager)": [8],
"(method 46 traffic-engine)": [0, 1, 2, 4],
"(method 42 traffic-engine)": [6],
"(method 17 traffic-manager)": [7, 19, 27, 28, 29, 30, 41],
"(anon-function 10 guard-rifle)": [9],
"(method 261 crimson-guard)": [52, 64],
"(anon-function 13 metalhead-predator)": [24, 25],
"(anon-function 90 ctywide-obs)": [4],
"(anon-function 10 cty-sniper-turret)": [44],
"(method 33 rub-tower)": [9, 10],
"(method 30 gungame-manager)": [0, 4, 5, 7]
},
// Sometimes the game might use format strings that are fetched dynamically,
@@ -448,7 +496,89 @@
[68, 1],
[101, 1],
[130, 1]
]
],
"(method 32 task-manager-desert-turtle-training)": [[59, 1]],
"(method 24 race-manager)": [[97, 1]],
"(method 25 race-manager)": [
[97, 1],
[126, 1]
],
"(method 15 hud-race-final-stats)": [[131, 0]],
"(method 15 hud-wasbbv-goal-time)": [[74, 0]],
"(method 32 task-manager-lightjak-training)": [[53, 0]],
"(method 18 hover-training-manager)": [[69, 0]],
"(method 37 task-manager-arena-training)": [[67, 1]],
"(method 15 hud-arena-final-stats)": [
[103, 0],
[147, 0]
],
"(method 35 task-manager-arena-fight-base)": [[53, 0]],
"(method 32 task-manager-arena-gun-training)": [[53, 0]],
"(method 26 task-manager-arena-fight-2)": [
[72, 0],
[186, 0]
],
"(method 37 task-manager-wascity-gungame)": [
[48, 0],
[78, 0],
[119, 0],
[157, 0],
[195, 0],
[227, 0],
[268, 0],
[306, 0],
[338, 0],
[379, 0],
[411, 0],
[446, 0]
],
"(method 30 was-pre-game)": [
[184, 0],
[276, 0]
],
"(method 32 task-manager-throne-gun-training)": [[53, 0]],
"(method 17 hud-spider-killed)": [[71, 0]],
"(trans idle des-burning-bush)": [
[226, 1],
[257, 0]
],
"(method 37 des-burning-bush)": [
[278, 0],
[336, 0]
],
"(method 38 des-burning-bush)": [
[109, 0],
[153, 0],
[196, 0]
],
"(method 15 freeze-time-hud)": [[108, 0]],
"(method 17 freeze-time-hud)": [[97, 0]],
"(method 15 hud-wasbbv-score)": [[61, 0]],
"(method 15 hud-wasbbv-goal)": [[64, 0]],
"(method 32 task-manager-dark-punch-training)": [[53, 0]],
"(method 32 task-manager-lightjak-training-shield)": [[53, 0]],
"(trans credits highres-viewer-manager)": [[185, 0]],
"(trans idle hirez-viewer)": [[356, 0]],
"(trans idle burning-bush)": [
[171, 1],
[202, 0]
],
"(method 33 task-manager-bbush-board)": [[86, 0]],
"(method 17 board-score-hud)": [[71, 0]],
"(method 23 gungame-manager)": [
[52, 0],
[90, 0],
[128, 0],
[164, 0],
[194, 0],
[235, 0],
[273, 0],
[305, 0],
[346, 0],
[378, 0],
[413, 0]
],
"(trans carry precur-bomb)": [[60, 0]]
},
"mips2c_functions_by_name": [
@@ -475,13 +605,14 @@
"draw-large-polygon",
"render-sky-quad",
"render-sky-tri",
"(method 16 sky-work)",
"(method 17 sky-work)",
"(method 18 sky-work)",
"(method 32 sky-work)",
"(method 33 sky-work)",
// "(method 28 sky-work)",
"(method 31 sky-work)",
"(method 34 sky-work)",
"(method 29 sky-work)",
"(method 30 sky-work)",
"(method 35 sky-work)",
"(method 11 collide-hash)",
"(method 12 collide-hash)",
"fill-bg-using-box-new",
@@ -577,11 +708,26 @@
"(method 21 cloth-system)",
"debug-line-clip?",
"(method 9 font-work)",
"(method 9 prim-strip)",
"live-func-curve",
"birth-func-curve",
"sparticle-motion-blur-dirt",
"foreground-draw-hud"
"foreground-draw-hud",
"shadow-execute",
"shadow-add-double-edges",
"shadow-add-single-edges",
"shadow-add-facing-single-tris",
"shadow-add-double-tris",
"shadow-xform-verts",
"shadow-calc-dual-verts",
"shadow-scissor-edges",
"shadow-scissor-top",
"shadow-init-vars",
"shadow-find-facing-single-tris",
"shadow-find-single-edges",
"shadow-find-facing-double-tris",
"shadow-find-double-edges",
"shadow-add-verts",
"shadow-add-single-tris"
],
"mips2c_jump_table_functions": {},
@@ -597,7 +743,6 @@
["lfacctyb", 0, 0],
["intpfall", 0, 0],
["lfaccity", 0, 0],
["lfacctyb-vis", 0, 0],
["ltowcity", 0, 0],
["powergd", 0, 0],
["lcitysml", 0, 0]
+584 -259
View File
@@ -28,286 +28,286 @@
"DGO/WCB.DGO",
"DGO/WCASEEM.DGO",
"DGO/WASCAST.DGO",
// // arena
// arena
"DGO/WASSTADA.DGO",
"DGO/WASSTADB.DGO",
"DGO/WASSTADC.DGO",
"DGO/ARENACST.DGO",
// // desert
// "DGO/DESA.DGO",
// desert
"DGO/DESA.DGO",
"DGO/DESB.DGO",
// "DGO/DESBATTL.DGO",
// "DGO/DESBCST.DGO",
// "DGO/DESBOSS1.DGO",
// "DGO/DESBOSS2.DGO",
// "DGO/DESC.DGO",
// "DGO/DESCHASE.DGO",
// "DGO/DESD.DGO",
// "DGO/DESE.DGO",
// "DGO/DESERROL.DGO",
// "DGO/DESF.DGO",
// "DGO/DESG.DGO",
// "DGO/DESH.DGO",
// "DGO/DESHOVER.DGO",
// "DGO/DESHUNT.DGO",
"DGO/DESBATTL.DGO",
"DGO/DESBCST.DGO",
"DGO/DESBOSS1.DGO",
"DGO/DESBOSS2.DGO",
"DGO/DESC.DGO",
"DGO/DESCHASE.DGO",
"DGO/DESD.DGO",
"DGO/DESE.DGO",
"DGO/DESERROL.DGO",
"DGO/DESF.DGO",
"DGO/DESG.DGO",
"DGO/DESH.DGO",
"DGO/DESHOVER.DGO",
"DGO/DESHUNT.DGO",
"DGO/DESINTER.DGO",
// "DGO/DESJUMP.DGO",
// "DGO/DESLIZ.DGO",
// "DGO/DESOASIS.DGO",
// "DGO/DESRACE1.DGO",
// "DGO/DESRACE2.DGO",
// "DGO/DESRALLY.DGO",
// "DGO/DESRESC.DGO",
// "DGO/DESRESCC.DGO",
// "DGO/DESRESCG.DGO",
// "DGO/DESTRACK.DGO",
// "DGO/DESW.DGO",
"DGO/DESJUMP.DGO",
"DGO/DESLIZ.DGO",
"DGO/DESOASIS.DGO",
"DGO/DESRACE1.DGO",
"DGO/DESRACE2.DGO",
"DGO/DESRALLY.DGO",
"DGO/DESRESC.DGO",
"DGO/DESRESCC.DGO",
"DGO/DESRESCG.DGO",
"DGO/DESTRACK.DGO",
"DGO/DESW.DGO",
"DGO/DST.DGO",
// "DGO/OASISCST.DGO",
// "DGO/WARPCAST.DGO", // air train
// // nest
// "DGO/NSA.DGO",
// "DGO/NSB.DGO",
// // temple
// "DGO/TEMA.DGO",
// "DGO/TEMB.DGO",
// "DGO/TEMC.DGO",
// "DGO/TEMD.DGO",
// "DGO/TEMP.DGO",
// "DGO/TEMPLEE.DGO",
// "DGO/TEMX.DGO",
// // hang
// "DGO/HGA.DGO",
// "DGO/HGB.DGO",
// // volcano
// "DGO/VOCA.DGO",
// "DGO/VOCX.DGO",
"DGO/OASISCST.DGO",
"DGO/WARPCAST.DGO", // air train
// nest
"DGO/NSA.DGO",
"DGO/NSB.DGO",
// temple
"DGO/TEMA.DGO",
"DGO/TEMB.DGO",
"DGO/TEMC.DGO",
"DGO/TEMD.DGO",
"DGO/TEMP.DGO",
"DGO/TEMPLEE.DGO",
"DGO/TEMX.DGO",
// hang
"DGO/HGA.DGO",
"DGO/HGB.DGO",
// volcano
"DGO/VOCA.DGO",
"DGO/VOCX.DGO",
// mine
"DGO/MIA.DGO",
"DGO/MIB.DGO",
"DGO/MIC.DGO",
"DGO/MINED.DGO",
"DGO/MINEE.DGO",
// // city
// "DGO/CWI.DGO", // ctywide
// "DGO/CFA.DGO", // ctyfarm
// "DGO/CFB.DGO",
// "DGO/CGB.DGO", // ctygen
// "DGO/CIA.DGO", // ctyind
// "DGO/CIB.DGO",
// "DGO/CPO.DGO", // ctyport
// "DGO/CTA.DGO", // ctyslum
// "DGO/CTB.DGO",
// "DGO/CTC.DGO",
// "DGO/CTYPEPA.DGO", // citizens
// "DGO/CTYPEPB.DGO", // predator
// "DGO/CTYPEPC.DGO", // empty
// "DGO/CTYPESA.DGO", // guards
// "DGO/CTYPESB.DGO", // metal heads
// "DGO/CTYPESC.DGO", // kg
// "DGO/CTYCARA.DGO", // cars
// "DGO/CTYCARB.DGO", // bikes
// "DGO/CTYCARC.DGO", // hellcat
// "DGO/CTYCARKG.DGO", // empty
// "DGO/ONINTENT.DGO",
// "DGO/VIN.DGO",
// "DGO/HHG.DGO", // hiphog
// "DGO/GGA.DGO", // gungame
// "DGO/GUNGAME1.DGO",
// "DGO/GUNGAME2.DGO",
// "DGO/POWERGD.DGO",
// "DGO/FREEHQ.DGO",
// "DGO/FREECAST.DGO",
// "DGO/CITYCAST.DGO",
// "DGO/GRIDCST.DGO", // city-destroy-grid-res
// "DGO/SLUMBSET.DGO", // sewer-met-hum-intro
// city
"DGO/CWI.DGO", // ctywide
"DGO/CFA.DGO", // ctyfarm
"DGO/CFB.DGO",
"DGO/CGB.DGO", // ctygen
"DGO/CIA.DGO", // ctyind
"DGO/CIB.DGO",
"DGO/CPO.DGO", // ctyport
"DGO/CTA.DGO", // ctyslum
"DGO/CTB.DGO",
"DGO/CTC.DGO",
"DGO/CTYPEPA.DGO", // citizens
"DGO/CTYPEPB.DGO", // predator
"DGO/CTYPEPC.DGO", // empty
"DGO/CTYPESA.DGO", // guards
"DGO/CTYPESB.DGO", // metal heads
"DGO/CTYPESC.DGO", // kg
"DGO/CTYCARA.DGO", // cars
"DGO/CTYCARB.DGO", // bikes
"DGO/CTYCARC.DGO", // hellcat
"DGO/CTYCARKG.DGO", // empty
"DGO/ONINTENT.DGO",
"DGO/VIN.DGO",
"DGO/HHG.DGO", // hiphog
"DGO/GGA.DGO", // gungame
"DGO/GUNGAME1.DGO",
"DGO/GUNGAME2.DGO",
"DGO/POWERGD.DGO",
"DGO/FREEHQ.DGO",
"DGO/FREECAST.DGO",
"DGO/CITYCAST.DGO",
"DGO/GRIDCST.DGO", // city-destroy-grid-res
"DGO/SLUMBSET.DGO", // sewer-met-hum-intro
// sewer
"DGO/SEA.DGO",
// "DGO/SEB.DGO",
// "DGO/SEC.DGO",
// "DGO/SED.DGO",
// "DGO/SEE.DGO",
// "DGO/SEF.DGO",
// "DGO/SEG.DGO",
// "DGO/SEH.DGO",
// "DGO/SEI.DGO",
// "DGO/SEJ.DGO",
// "DGO/SEK.DGO",
// "DGO/SEL.DGO",
// "DGO/SEM.DGO",
// "DGO/SEN.DGO",
// "DGO/SEO.DGO",
// // mhcity
// "DGO/MHCA.DGO",
// "DGO/MHCB.DGO",
// "DGO/MHCTYCST.DGO",
// // forest
"DGO/SEB.DGO",
"DGO/SEC.DGO",
"DGO/SED.DGO",
"DGO/SEE.DGO",
"DGO/SEF.DGO",
"DGO/SEG.DGO",
"DGO/SEH.DGO",
"DGO/SEI.DGO",
"DGO/SEJ.DGO",
"DGO/SEK.DGO",
"DGO/SEL.DGO",
"DGO/SEM.DGO",
"DGO/SEN.DGO",
"DGO/SEO.DGO",
// mhcity
"DGO/MHCA.DGO",
"DGO/MHCB.DGO",
"DGO/MHCTYCST.DGO",
// forest
"DGO/FRSTA.DGO",
"DGO/FRSTB.DGO",
"DGO/FRSTX.DGO",
// // factory
// "DGO/FACTORYA.DGO",
// "DGO/FACB.DGO",
// "DGO/FACC.DGO",
// "DGO/FACD.DGO",
// // tower
// "DGO/TOWB.DGO",
// "DGO/TOWERA.DGO",
// "DGO/TOWERC.DGO",
// "DGO/TOWERCST.DGO",
// // stadium
// "DGO/STA.DGO",
// "DGO/STAA.DGO",
// "DGO/STB.DGO",
// // rubble
// "DGO/RUBA.DGO",
// "DGO/RUBA2.DGO",
// "DGO/RUBB.DGO",
// "DGO/RUBC.DGO",
// "DGO/RBCT.DGO",
// // comb
// "DGO/COMBA.DGO",
// "DGO/COMBB.DGO",
// "DGO/COMBC.DGO",
// "DGO/COMBD.DGO",
// "DGO/COMBE.DGO",
// "DGO/COMBN.DGO",
// "DGO/COMBX.DGO",
// "DGO/RAILA.DGO",
// "DGO/RAILB.DGO",
// "DGO/RAILB2.DGO",
// "DGO/RAILC.DGO",
// "DGO/RAILCST.DGO",
// "DGO/RAILD.DGO",
// "DGO/RAILE.DGO",
// "DGO/RAILF.DGO",
// "DGO/RAILX.DGO",
// // precursor
// "DGO/PRECA.DGO",
// "DGO/PRECB.DGO",
// "DGO/PRECC.DGO",
// factory
"DGO/FACTORYA.DGO",
"DGO/FACB.DGO",
"DGO/FACC.DGO",
"DGO/FACD.DGO",
// tower
"DGO/TOWB.DGO",
"DGO/TOWERA.DGO",
"DGO/TOWERC.DGO",
"DGO/TOWERCST.DGO",
// stadium
"DGO/STA.DGO",
"DGO/STAA.DGO",
"DGO/STB.DGO",
// rubble
"DGO/RUBA.DGO",
"DGO/RUBA2.DGO",
"DGO/RUBB.DGO",
"DGO/RUBC.DGO",
"DGO/RBCT.DGO",
// comb
"DGO/COMBA.DGO",
"DGO/COMBB.DGO",
"DGO/COMBC.DGO",
"DGO/COMBD.DGO",
"DGO/COMBE.DGO",
"DGO/COMBN.DGO",
"DGO/COMBX.DGO",
"DGO/RAILA.DGO",
"DGO/RAILB.DGO",
"DGO/RAILB2.DGO",
"DGO/RAILC.DGO",
"DGO/RAILCST.DGO",
"DGO/RAILD.DGO",
"DGO/RAILE.DGO",
"DGO/RAILF.DGO",
"DGO/RAILX.DGO",
// precursor
"DGO/PRECA.DGO",
"DGO/PRECB.DGO",
"DGO/PRECC.DGO",
// "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",
"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
// "DGO/OUTCAST3.DGO",
// "DGO/OUTROCST.DGO",
"DGO/OUTCAST3.DGO",
"DGO/OUTROCST.DGO",
// // museum
// "DGO/MUSEUM.DGO",
// "DGO/MUSEUM2.DGO",
// "DGO/MUSEUM3.DGO",
// "DGO/MUSEUM3B.DGO",
// "DGO/MUSEUM4.DGO",
// "DGO/MUSEUM4B.DGO",
"DGO/MUSEUM.DGO",
"DGO/MUSEUM2.DGO",
"DGO/MUSEUM3.DGO",
"DGO/MUSEUM3B.DGO",
"DGO/MUSEUM4.DGO",
"DGO/MUSEUM4B.DGO",
// test
"DGO/HALFPIPE.DGO",
// // borrow
// "DGO/LASHELIN.DGO",
// "DGO/LBBRING1.DGO",
// "DGO/LBBRING2.DGO",
// "DGO/LBBRING3.DGO",
// "DGO/LBBRING4.DGO",
// "DGO/LBBRING5.DGO",
// "DGO/LBBRING6.DGO",
// "DGO/LBBSDRP1.DGO",
// "DGO/LBBSDRP2.DGO",
// "DGO/LBBSDRP3.DGO",
// "DGO/LBBSPID.DGO",
// "DGO/LBBSPIRT.DGO",
// "DGO/LBBSPRT2.DGO",
// "DGO/LBBSPRT3.DGO",
// "DGO/LBBTCHA1.DGO",
// "DGO/LBBTCHA2.DGO",
// "DGO/LBBTCHA3.DGO",
// "DGO/LBIPED.DGO",
// "DGO/LBLOWCST.DGO",
// "DGO/LBLOWTKG.DGO",
// "DGO/LBLOWTMH.DGO",
// "DGO/LBOMBBOT.DGO",
// "DGO/LCITYSML.DGO",
// "DGO/LCTYASS.DGO",
// "DGO/LCTYBLOW.DGO",
// "DGO/LCTYDEST.DGO",
// "DGO/LCTYHIJK.DGO",
// "DGO/LCTYPALT.DGO",
// "DGO/LCTYPATK.DGO",
// "DGO/LCTYPROT.DGO",
// "DGO/LCTYSNPR.DGO",
// "DGO/LDAMKLEV.DGO",
// "DGO/LDAMPECK.DGO",
// "DGO/LDAMPKSM.DGO",
// "DGO/LDAMSIG.DGO",
// "DGO/LDAX.DGO",
// "DGO/LDESGCST.DGO",
// "DGO/LDMPCKGN.DGO",
// "DGO/LERROL.DGO",
// "DGO/LFACB.DGO",
// "DGO/LFACCAR.DGO",
// "DGO/LFACCITY.DGO",
// "DGO/LFACO.DGO",
// "DGO/LFACRM1.DGO",
// "DGO/LFACRM2.DGO",
// "DGO/LFACTORY.DGO",
// "DGO/LFORM.DGO",
// "DGO/LFORP.DGO",
// "DGO/LFORRING.DGO",
// "DGO/LFREEOUT.DGO",
// "DGO/LGUNNORM.DGO",
// "DGO/LGUNRNC.DGO",
// "DGO/LJAK.DGO",
// "DGO/LJAKC.DGO",
// "DGO/LJAKCKLV.DGO",
// "DGO/LJAKKLEV.DGO",
// "DGO/LJAKNDAX.DGO",
// "DGO/LJAKSIG.DGO",
// "DGO/LJINX.DGO",
// "DGO/LJKCDMKL.DGO",
// "DGO/LJKDMPK.DGO",
// "DGO/LJKDXVIN.DGO",
// "DGO/LJKFEET.DGO",
// "DGO/LJNDKLEV.DGO",
// "DGO/LKEIRA.DGO",
// "DGO/LKLEEVER.DGO",
// borrow
"DGO/LASHELIN.DGO",
"DGO/LBBRING1.DGO",
"DGO/LBBRING2.DGO",
"DGO/LBBRING3.DGO",
"DGO/LBBRING4.DGO",
"DGO/LBBRING5.DGO",
"DGO/LBBRING6.DGO",
"DGO/LBBSDRP1.DGO",
"DGO/LBBSDRP2.DGO",
"DGO/LBBSDRP3.DGO",
"DGO/LBBSPID.DGO",
"DGO/LBBSPIRT.DGO",
"DGO/LBBSPRT2.DGO",
"DGO/LBBSPRT3.DGO",
"DGO/LBBTCHA1.DGO",
"DGO/LBBTCHA2.DGO",
"DGO/LBBTCHA3.DGO",
"DGO/LBIPED.DGO",
"DGO/LBLOWCST.DGO",
"DGO/LBLOWTKG.DGO",
"DGO/LBLOWTMH.DGO",
"DGO/LBOMBBOT.DGO",
"DGO/LCITYSML.DGO",
"DGO/LCTYASS.DGO",
"DGO/LCTYBLOW.DGO",
"DGO/LCTYDEST.DGO",
"DGO/LCTYHIJK.DGO",
"DGO/LCTYPALT.DGO",
"DGO/LCTYPATK.DGO",
"DGO/LCTYPROT.DGO",
"DGO/LCTYSNPR.DGO",
"DGO/LDAMKLEV.DGO",
"DGO/LDAMPECK.DGO",
"DGO/LDAMPKSM.DGO",
"DGO/LDAMSIG.DGO",
"DGO/LDAX.DGO",
"DGO/LDESGCST.DGO",
"DGO/LDMPCKGN.DGO",
"DGO/LERROL.DGO",
"DGO/LFACB.DGO",
"DGO/LFACCAR.DGO",
"DGO/LFACCITY.DGO",
"DGO/LFACO.DGO",
"DGO/LFACRM1.DGO",
"DGO/LFACRM2.DGO",
"DGO/LFACTORY.DGO",
"DGO/LFORM.DGO",
"DGO/LFORP.DGO",
"DGO/LFORRING.DGO",
"DGO/LFREEOUT.DGO",
"DGO/LGUNNORM.DGO",
"DGO/LGUNRNC.DGO",
"DGO/LJAK.DGO",
"DGO/LJAKC.DGO",
"DGO/LJAKCKLV.DGO",
"DGO/LJAKKLEV.DGO",
"DGO/LJAKNDAX.DGO",
"DGO/LJAKSIG.DGO",
"DGO/LJINX.DGO",
"DGO/LJKCDMKL.DGO",
"DGO/LJKDMPK.DGO",
"DGO/LJKDXVIN.DGO",
"DGO/LJKFEET.DGO",
"DGO/LJNDKLEV.DGO",
"DGO/LKEIRA.DGO",
"DGO/LKLEEVER.DGO",
"DGO/LMECH.DGO",
// "DGO/LMHCA.DGO",
// "DGO/LMHCB.DGO",
// "DGO/LNSTCST.DGO",
// "DGO/LNSTOA.DGO",
// "DGO/LNSTOBB.DGO",
// "DGO/LNSTOBC.DGO",
// "DGO/LONINSIM.DGO",
// "DGO/LOUTRO.DGO",
// "DGO/LOUTRO2.DGO",
// "DGO/LOUTRO3.DGO",
// "DGO/LPATK.DGO",
// "DGO/LPATKCS.DGO",
// "DGO/LPRECC.DGO",
// "DGO/LPRENME.DGO",
// "DGO/LPTRL.DGO",
// "DGO/LSAMOS.DGO",
// "DGO/LSEEMWCA.DGO",
// "DGO/LSIG.DGO",
// "DGO/LSIGJAKC.DGO",
// "DGO/LSIGKLV.DGO",
// "DGO/LSNKWHLS.DGO",
// "DGO/LTNFXHIP.DGO",
// "DGO/LTNJXHIP.DGO",
// "DGO/LTORN.DGO",
// "DGO/LTORNJNX.DGO",
// "DGO/LTORNSAM.DGO",
// "DGO/LTOWA.DGO",
// "DGO/LTOWB.DGO",
// "DGO/LTOWCITY.DGO",
// "DGO/LTRTWHLS.DGO",
// "DGO/LVINCST.DGO",
// "DGO/LWASBBV.DGO",
// "DGO/LWASSIG.DGO",
// "DGO/LWLANDM.DGO",
"DGO/LMHCA.DGO",
"DGO/LMHCB.DGO",
"DGO/LNSTCST.DGO",
"DGO/LNSTOA.DGO",
"DGO/LNSTOBB.DGO",
"DGO/LNSTOBC.DGO",
"DGO/LONINSIM.DGO",
"DGO/LOUTRO.DGO",
"DGO/LOUTRO2.DGO",
"DGO/LOUTRO3.DGO",
"DGO/LPATK.DGO",
"DGO/LPATKCS.DGO",
"DGO/LPRECC.DGO",
"DGO/LPRENME.DGO",
"DGO/LPTRL.DGO",
"DGO/LSAMOS.DGO",
"DGO/LSEEMWCA.DGO",
"DGO/LSIG.DGO",
"DGO/LSIGJAKC.DGO",
"DGO/LSIGKLV.DGO",
"DGO/LSNKWHLS.DGO",
"DGO/LTNFXHIP.DGO",
"DGO/LTNJXHIP.DGO",
"DGO/LTORN.DGO",
"DGO/LTORNJNX.DGO",
"DGO/LTORNSAM.DGO",
"DGO/LTOWA.DGO",
"DGO/LTOWB.DGO",
"DGO/LTOWCITY.DGO",
"DGO/LTRTWHLS.DGO",
"DGO/LVINCST.DGO",
"DGO/LWASBBV.DGO",
"DGO/LWASSIG.DGO",
"DGO/LWLANDM.DGO",
"DGO/LWSTDPCK.DGO"
],
@@ -333,10 +333,6 @@
"TEXT/11COMMON.TXT"
],
// uncomment the next line to extract audio to wave files.
// "audio_dir_file_name": "jak3/VAG",
"audio_dir_file_name": "",
"streamed_audio_file_names": [
"VAGWAD.ENG",
"VAGWAD.FRE",
@@ -347,6 +343,335 @@
"VAGWAD.INT"
],
"animated_textures": [
// dark jak
"jakc-arm",
"jakc-eyebrow",
"jakc-face",
"jakc-finger",
"jakc-hair",
"jakc-arm-norm",
"jakc-eyebrow-norm",
"jakc-face-norm",
"jakc-finger-norm",
"jakc-hair-norm",
"jakc-arm-dark",
"jakc-eyebrow-dark",
"jakc-face-dark",
"jakc-finger-dark",
"jakc-hair-dark",
// darkjak-highres
"jakchires-arm",
"jakchires-arm-norm",
"jakchires-arm-dark",
"jakchires-eye",
"jakchires-eye-norm",
"jakchires-eye-dark",
"jakchires-eyebrow",
"jakchires-eyebrow-norm",
"jakchires-eyebrow-dark",
"jakchires-eyelid",
"jakchires-eyelid-norm",
"jakchires-eyelid-dark",
"jakchires-facelft",
"jakchires-facelft-norm",
"jakchires-facelft-dark",
"jakchires-facert",
"jakchires-facert-norm",
"jakchires-facert-dark",
"jakchires-hair",
"jakchires-hair-norm",
"jakchires-hair-dark",
// Skull Gem
"skull-gem-dest",
"skull-gem-alpha-00",
"skull-gem-alpha-01",
"skull-gem-alpha-02",
// default-water
"bomb-gradient",
"bomb-gradient-rim",
"bomb-gradient-flames",
"lightjak-wings",
"lighjak-wings-u-src",
"lightjak-wings-v-src",
"mushroom-dest",
"mushroom-src",
// default-warp
"shield-env-rim-dest",
"common-white",
"shield-env-uscroll",
"shield-env-rim-src",
// hanga-sprite
"glider-ring-dest2",
"glider-ring-dest",
"splash-foam",
"racegate",
// templea-water
"templea-waterfall-dest",
"templea-waterfall",
// templea-warp
"holograph-env-rim-dest",
"holograph-env-noise",
"holograph-env-scan",
"holograph-env-rim",
"environment-phong-rim",
// foresta-water
"fora-water-dest",
"fora-water",
"fora-waterfall-01-dest",
"fora-waterfall-01",
"fora-water-wave-01-dest",
"fora-water-wave-01",
// forestb-water
"forb-water-dest",
"forb-water",
"forb-waterfall-01-dest",
"forb-waterfall-01",
"forb-water-wave-01-dest",
"forb-water-wave-01",
// lforplnt-pris
"mh-gem-dest",
"mh-gem",
"mh-gem-alpha-01",
"mh-gem-alpha-02",
// lmhcitya-tfrag
"mhcitya-base-goo-01-dest",
"mhcitya-base-goo-01",
// lmhcityb-tfrag
"mhcityb-base-goo-01-dest",
"mhcityb-base-goo-01",
// mhcitya-pris
// "mhcity-de-door-skin-01-dest",
// "mhcity-de-door-skin-01",
// "mhcity-de-door-skin-02"
// templec-water
"tplc-water-dest",
"tplc-water",
// sewc-water
"sewer-water-01-c-dest",
"sewer-water-01-c",
"sewer-waterfall-01-c-dest",
"sewer-waterfall-01-c",
"sewer-waterfall-02-c-dest",
"sewer-waterfall-02-c",
"sewer-water-wave-01-c-dest",
"sewer-water-wave-01-c",
"sewer-water-highlight-01-c-dest",
"sewer-water-highlight-01-c",
// sewd-water
"sewer-water-01-d-dest",
"sewer-water-01-d",
"sewer-waterfall-02-d-dest",
"sewer-waterfall-02-d",
"sewer-water-highlight-01-d-dest",
"sewer-water-highlight-01-d",
"sewer-water-wave-01-d-dest",
"sewer-water-wave-01-d",
"sewer-water-wave-02-d-dest",
"sewer-water-wave-02-d",
"sewer-water-still-01-d-dest",
"sewer-water-still-01-d",
// sewe-water
"sewer-water-01-e-dest",
"sewer-water-01-e",
"sewer-waterfall-01-e-dest",
"sewer-waterfall-01-e",
"sewer-waterfall-02-e-dest",
"sewer-waterfall-02-e",
"sewer-water-highlight-01-e-dest",
"sewer-water-highlight-01-e",
// sewg-water
"sewer-water-01-g-dest",
"sewer-water-01-g",
"sewer-waterfall-02-g-dest",
"sewer-waterfall-02-g",
"sewer-water-wave-01-g-dest",
"sewer-water-wave-01-g",
// sewh-water
"sewer-water-01-h-dest",
"sewer-water-01-h",
"sewer-waterfall-02-h-dest",
"sewer-waterfall-02-h",
"sewer-water-wave-02-h-dest",
"sewer-water-wave-02-h",
"sewer-watefall-froth-01-h-dest",
"sewer-watefall-froth-01-h",
// sewi-water
"sewer-water-still-01-i-dest",
"sewer-water-still-01-i",
"sewer-waterfall-02-i-dest",
"sewer-waterfall-02-i",
"sewer-water-wave-01-i-dest",
"sewer-water-wave-01-i",
// sewj-water
"sewer-waterfall-02-j-dest",
"sewer-waterfall-02-j",
"sewer-watefall-froth-01-j-dest",
"sewer-watefall-froth-01-j",
// sewl-water
"sewer-waterfall-02-l-dest",
"sewer-waterfall-02-l",
"sewer-watefall-froth-01-l-dest",
"sewer-watefall-froth-01-l",
// sewm-water
"sewer-water-01-m-dest",
"sewer-water-01-m",
"sewer-waterfall-01-m-dest",
"sewer-waterfall-01-m",
"sewer-waterfall-02-m-dest",
"sewer-waterfall-02-m",
"sewer-water-highlight-01-m-dest",
"sewer-water-highlight-01-m",
"sewer-water-wave-01-m-dest",
"sewer-water-wave-01-m",
"sewer-water-still-01-m-dest",
"sewer-water-still-01-m",
"sewer-watefall-froth-01-m-dest",
"sewer-watefall-froth-01-m",
// sewn-water
"sewer-waterfall-01-n-dest",
"sewer-waterfall-01-n",
"sewer-waterfall-02-n-dest",
"sewer-waterfall-02-n",
// "sewer-water-highlight-01-n-dest",
// "sewer-water-highlight-01-n",
"sewer-water-wave-01-n-dest",
"sewer-water-wave-01-n",
"sewer-water-still-01-n-dest",
"sewer-water-still-01-n",
// hanga-water
// "des-thermal-01-dest",
// "des-thermal-01"
// desresc-warp
"sat-shield-dest",
"sat-shield-env-uvscroll",
"sat-shield",
// security
"security-env-dest",
"security-env-uscroll",
"security-dot-dest",
"security-dot-src",
// lgunnorm-water
"kg-target-c-forcefield-01-dest",
"kg-target-c-forcefield-01",
// templex-water
"temple-waterfall-dest",
"temple-waterfall",
// desertd-water
"des-waterfall-dest",
"des-waterfall",
// towerb-water
"tow-energy-bridge-dest",
"tow-energy-bridge",
// factoryb-water
"hemi-gradient-dest",
"hemi-gradient-rim",
"hemi-gradient-flames-dest",
"hemi-gradient-flames",
// factoryc-alpha
"facc-convey-dest",
"facc-convey",
"facc-convey-02-dest",
"facc-convey-02",
// waspal-water
"waspala-water-dest",
"waspala-water",
"waspala-waterfall-dest",
"waspala-waterfall",
// rubblea-water
"rub-water-dest",
"rub-water",
// rubblea2-water
"rub-water-desta2",
"rub-watera2",
// rubbleb-water
"rub-water-destb",
"rub-waterb",
// rubblec-water
"rub-water-destc",
"rub-waterc",
// nstb-quicksand
"nstb-quicksand-dest",
"nstb-quicksand-scroll",
// ctyslumb-water
"ctyslumb-water-dest",
"ctyslumb-water",
"ctyslumb-fountain-fall-dest",
"ctyslumb-fountain-fall",
// ctyslumc-water
"ctyslumc-water-dest",
"ctyslumc-water",
"ctyslumc-fountain-fall-dest",
"ctyslumc-fountain-fall",
// mined-tfrag
"mined-pillar-side-dest",
"mined-pillar-side-cold",
"mined-pillar-side-cooling",
"mined-pillar-side-hot",
"mined-pillar-molten",
"mined-pillar-top2side-dest",
"mined-pillar-top2side-cold",
"mined-pillar-top2side-cooling",
"mined-pillar-top2side-hot",
"mined-pillar-top-dest",
"mined-pillar-top-cold",
"mined-pillar-top-cooling",
"mined-pillar-top-hot",
"mined-pillar-molten-top",
// volcanoa-alpha
"vola-lava-01-dest",
"vola-lava-01",
"vola-lava-fall-dest",
"vola-lava-fall",
// wasstada-alpha
"wstd-lava-base-dest",
"wstd-lava-base"
],
"levels_to_extract": [
// wascity
"WASALL.DGO",
File diff suppressed because it is too large. Load diff
@@ -3,5 +3,9 @@
"(method 29 target)": 2048,
"(method 11 part-spawner)": 64,
"(method 11 elevator)": 1024,
"scene-player-init": 1024
"scene-player-init": 1024,
"task-manager-init-by-other": 2048,
"race-manager-init-by-other": 1024,
"neo-sat-shield-init-by-other": 64,
"bt-gun-manager-init-by-other": 256
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -2011,5 +2011,129 @@
"vars": {
"v0-0": ["v0-0", "saberfish-find-behavior"]
}
},
"(method 23 spider-manager)": {
"vars": {
"s3-0": ["dist", "float"]
}
},
"(method 121 sewer-frog)": {
"vars": {
"v1-10": ["name", "sound-name"]
}
},
"(trans target-board-ride-edge)": {
"vars": {
"a0-44": ["name", "sound-name"]
}
},
"(method 9 menu-create-game-option)": {
"vars": {
"a0-26": ["name", "sound-name"]
}
},
"(code active task-manager-forest-plants)": {
"vars": {
"s5-8": ["hand", "handle"]
}
},
"(method 31 dm-mine-spider-spawner)": {
"vars": {
"s3-0": ["s3-0", "float"]
}
},
"(method 26 task-manager-wascity-gungame)": {
"vars": {
"s4-1": ["sname", "sound-name"]
}
},
"terraformer-head-always": {
"vars": {
"s4-2": ["sname", "sound-name"]
}
},
"launch-mine": {
"vars": {
"v0-1": ["hand", "handle"]
}
},
"(method 42 mh-centipede)": {
"vars": {
"s0-0": ["sname", "sound-name"]
}
},
"check-enemy": {
"args": ["turret", "radius", "pfoc"]
},
"(method 202 bot)": {
"vars": {
"s4-0": ["cspec", "collide-spec"]
}
},
"(enter impact warf-projectile)": {
"vars": {
"s4-0": ["sname", "sound-name"]
}
},
"symbol->city-target-type": {
"vars": {
"v0-0": ["type", "city-target-type"]
}
},
"city-target-type->traffic-object-type": {
"vars": {
"v0-0": ["type", "traffic-type"]
}
},
"city-target-type->cty-faction": {
"vars": {
"v0-0": ["type", "cty-faction"]
}
},
"map-symbol-to-nav-territory-type": {
"vars": {
"v0-0": ["type", "nav-territory-type"]
}
},
"guard-type->city-target-type": {
"vars": {
"v0-0": ["type", "city-target-type"]
}
},
"(code die neo-sat)": {
"vars": {
"gp-0": ["hand", "handle"]
}
},
"(method 48 task-manager-desert-rescue)": {
"vars": {
"f30-0": ["f30-0", "float"]
}
},
"(method 31 gun-dummy)": {
"vars": {
"f0-0": "total-time",
"v1-0": "curr-frame"
}
},
"symbol->gun-pickup-type": {
"vars": {
"v0-0": ["type", "pickup-type"]
}
},
"symbol->faction-type": {
"vars": {
"v0-0": ["type", "assault-cmd-faction-type"]
}
},
"symbol->speech-type": {
"vars": {
"v0-0": ["type", "assault-cmd-speech-type"]
}
},
"symbol->assault-target-type": {
"vars": {
"v0-0": ["type", "assault-target-type"]
}
}
}
+41 -3
View File
@@ -515,8 +515,44 @@ TPageResultStats process_tpage(ObjectFileData& data,
// currently not needed.
break;
case int(PSM::PSMT8):
ASSERT(tex.clutpsm == int(CPSM::PSMCT32));
{
if (tex.clutpsm == (int)CPSM::PSMCT16) {
// will store output pixels, rgba (8888)
std::vector<u8> index_out;
// width is like the TEX0 register, in 64 texel units.
// not sure what the other widths are yet.
int read_width = 64 * tex.width[0];
// loop over pixels in output texture image
for (int y = 0; y < tex.h; y++) {
for (int x = 0; x < tex.w; x++) {
// read as the PSMT8 type. The dest field tells us a block offset.
auto addr8 = psmt8_addr(x, y, read_width) + tex.dest[0] * 256;
u8 value = *(u8*)(vram.data() + addr8);
index_out.push_back(value);
}
}
std::array<math::Vector4<u8>, 256> unscrambled_clut{};
for (int i = 0; i < 256; i++) {
u32 clut_chunk = i / 16;
u32 off_in_chunk = i % 16;
u8 clx = 0, cly = 0;
if (clut_chunk & 1) {
clx = 8;
}
cly = (clut_chunk >> 1) * 2;
if (off_in_chunk >= 8) {
off_in_chunk -= 8;
cly++;
}
clx += off_in_chunk;
u32 clut_addr = psmct16_addr(clx, cly, 64) + tex.clutdest * 256;
memcpy(&unscrambled_clut[i], vram.data() + clut_addr, 4);
}
texture_db.add_index_texture(texture_page.id, tex_id, index_out, unscrambled_clut,
tex.w, tex.h, tex.name, texture_page.name, level_names);
stats.successful_textures++;
} else if (tex.clutpsm == (int)PSM::PSMCT32) {
// will store output pixels, index (u8)
std::vector<u8> index_out;
@@ -555,10 +591,12 @@ TPageResultStats process_tpage(ObjectFileData& data,
texture_db.add_index_texture(texture_page.id, tex_id, index_out, unscrambled_clut,
tex.w, tex.h, tex.name, texture_page.name, level_names);
stats.successful_textures++;
} else {
ASSERT_NOT_REACHED();
}
break;
default:
lg::die("Animated texture {} format {}\n", tex.name, tex.psm);
lg::die("Animated texture {} format {} clut {}\n", tex.name, tex.psm, tex.clutpsm);
}
}
Loaded 100 of 2595 files, more files were not shown because too many files have changed in this diff. Show more