Found out the hard way that the `abutton` array for pressure sensitivity
uses a different order than the `pad-buttons` enum, so I created a new
enum for abutton indexing.
I replaced any magic numbers across the codebase where it made sense,
e.g.
`(-> *cpad-list* cpads (-> self control unknown-cpad-info00 number)
abutton 6)`
becomes
`(-> *cpad-list* cpads (-> self control unknown-cpad-info00 number)
abutton (abutton-idx x))`
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)
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)
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)
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.
- `fma-sphere`
- `prim-beam-h`
- `cam-start`
- `ragdoll`
- `light-trails-h`
- `light-trails`
- `menu`
- `water`
- `water-flow`
- `hud`
- `hud-classes`
- `progress`
- `progress-draw`
---
The `get-texture` macro replaces calls to `lookup-texture-by-id` and
`lookup-texture-by-id-fast`. The `defpart` macro detection was modified
to print a pair like `(texture-name tpage-name)` for the texture field
that gets turned into a `texture-id` constant. Only used in Jak 3 at the
moment, I'll probably go through the other games at a later point.
- `speech`
- `ambient`
- `water-h`
- `vol-h`
- `generic-obs`
- `carry-h`
- `pilot-h`
- `board-h`
- `gun-h`
- `flut-h`
- `indax-h`
- `lightjak-h`
- `darkjak-h`
- `target-util`
- `history`
- `collide-reaction-target`
- `logic-target`
- `sidekick`
- `projectile`
- `voicebox`
- `ragdoll-edit`
- most of `ragdoll` (not added to gsrc yet)
- `curves`
- `find-nearest`
- `lightjak-wings`
- `target-handler`
- `target-anim`
- `target`
- `target2`
- `target-swim`
- `target-lightjak`
- `target-invisible`
- `target-death`
- `target-gun`
- `gun-util`
- `board-util`
- `target-board`
- `board-states`
- `mech-h`
- `vol`
- `vent`
- `viewer`
- `gem-pool`
- `collectables`
- `crates`
- `secrets-menu`
Additionally:
- Detection of non-virtual state inheritance
- Added a config file that allows overriding the process stack size set
by `stack-size-set!` calls
- Fix for integer multiplication with `r0`
- Fixed detection for the following macros:
- `static-attack-info`
- `defpart` and `defpartgroup` (probably still needs adjustments, uses
Jak 2 implementation at the moment)
- `sound-play` (Jak 3 seems to always call `sound-play-by-name` with a
`sound-group` of 0, so the macro has been temporarily defaulted to use
that)
One somewhat significant change made here that should be noted is that
the return type of `process::init-from-entity!` was changed to `object`.
I've been thinking about this for a while, since it looks a bit nicer
without the `(none)` at the end and I have recently encountered init
methods that early return `0`.
During level extraction, the last 4 characters of the level name are
always removed, because it is assumed that '-vis' is there. But it isn't
always there. This is especially true in post-TPL games.
This causes multiple problems:
- There can be levels in the extraction that will miss their last 4
characters from their name, which is sad, and may make it harder to
identify them.
- If there are '-vis'-less levels whose names are identical apart from
the last 4 characters, the extractor will only get the last one (it
probably extracts all but overwrites everything but the last one). For
example 'ctyasha' and 'ctykora'.
This issue affects the glb extraction and the entities json extraction.
I personally think that just keeping the -vis in the name would be the
best solution, but I guess there was a reason why it was decided that it
should be removed from the name. So to adapt to this, my implementation
will still remove '-vis' from the name, but only if it is actually in
the name - otherwise it won't remove anything.
I hope my changes didn't break anything. Extraction seemed to run fine
after my changes, and I was able to see both ctyasha and ctykora json
files. And didn't see any '-vis', so it is still properly removed.
---------
Co-authored-by: Tyler Wilding <xtvaser@gmail.com>
Added a new `rip_collision` flag to the decompiler config and wired it
up. Cleaned up the comments around these fields in the JSON too for
clarity
Also refactored a bunch of the related extract functions to read from
`config` object rather than pass down a bunch of booleans
Currently only tracks enemy kills, and how they were killed. There is
currently no menu for this, but I've already added most of the text for
it. Also did a bunch of misc decompilation fixes and renamed some
methods.
Fixes#3277Fixes#3278
Major change to how `deftype` shows up in our code:
- the decompiler will no longer emit the `offset-assert`,
`method-count-assert`, `size-assert` and `flag-assert` parameters. There
are extremely few cases where having this in the decompiled code is
helpful, as the types there come from `all-types` which already has
those parameters. This also doesn't break type consistency because:
- the asserts aren't compared.
- the first step of the test uses `all-types`, which has the asserts,
which will throw an error if they're bad.
- the decompiler won't emit the `heap-base` parameter unless necessary
now.
- the decompiler will try its hardest to turn a fixed-offset field into
an `overlay-at` field. It falls back to the old offset if all else
fails.
- `overlay-at` now supports field "dereferencing" to specify the offset
that's within a field that's a structure, e.g.:
```lisp
(deftype foobar (structure)
((vec vector :inline)
(flags int32 :overlay-at (-> vec w))
)
)
```
in this structure, the offset of `flags` will be 12 because that is the
final offset of `vec`'s `w` field within this structure.
- **removed ID from all method declarations.** IDs are only ever
automatically assigned now. Fixes#3068.
- added an `:overlay` parameter to method declarations, in order to
declare a new method that goes on top of a previously-defined method.
Syntax is `:overlay <method-name>`. Please do not ever use this.
- added `state-methods` list parameter. This lets you quickly specify a
list of states to be put in the method table. Same syntax as the
`states` list parameter. The decompiler will try to put as many states
in this as it can without messing with the method ID order.
Also changes `defmethod` to make the first type definition (before the
arguments) optional. The type can now be inferred from the first
argument. Fixes#3093.
---------
Co-authored-by: Hat Kid <6624576+Hat-Kid@users.noreply.github.com>
This change adds a few new features:
- Decompiler automatically knows the type of `find-parent-method` use in
jak 1 and jak2 when used in a method or virtual state handler.
- Decompiler inserts a call to `call-parent-method` or
`find-parent-state`
- Removed most casts related to these functions
There are still a few minor issues around this:
- There are still some casts needed when using `post` methods, as `post`
is just a `function`, and needs a cast to `(function none)` or similar.
It didn't seem easy to change the type of `post`, so I'm not going to
worry about it for this PR. It only shows up in like 3 places in jak 2.
(and 0 in jak 1)
- If "call the handler if it's not #f" logic should probably be another
macro.
Fixes#805
Adds controller LED features to Jak 2:
- progressive flickering denoting health
- copies tomb simon says puzzle colors
- unique colors for each gun
- orange color for being indax
- yellow color for being in mech
- purple color for being darkjak
- blue color for being in board
- red flash when wanted.
May add more features later?
Also did some minor clean-up on some types.
This renames the method object in `defmethod`s to `this` and adds
detection for the `set-time!` and `time-elapsed?` macros.
Definitely my biggest PR yet...
- state handlers that are not inlined lambdas have smarter type
checking, getting rid of 99.9% of the casts emitted (they were not
useful)
- art groups were not being properly linked to their "master" groups.
- `max` in `ja` in Jak 2 was not being detected.
Another huge PR...
Previously, `object` and `none` were both top-level types. This made
decompilation rather messy as they have no LCA and resulted in a lot of
variables coming out as type `none` which is very very wrong and
additionally there were plenty of casts to `object`. This changes it so
`none` becomes a child of `object` (it is still represented by
`NullType` which remains unusable in compilation).
This change makes `object` the sole top-level type, and the type that
can represent *any* GOAL object. I believe this matches the original
GOAL built-in type structure. A function that has a return type of
`object` can now return an integer or a `none` at the same time.
However, keep in mind that the return value of `(none)` is still
undefined, just as before. This also makes a cast to `object`
meaningless in 90% of the situations it showed up in (as every single
thing is already an `object`) and the decompiler will no longer emit
them. Casts to `none` are also reduced. Yay!
Additionally, state handlers also don't get the final `(none)` printed
out anymore. The return type of a state handler is completely
meaningless outside the event handler (which is return type `object`
anyway) so there are no limitations on what the last form needs to be. I
did this instead of making them return `object` to trick the decompiler
into not trying to output a variable to be used as a return value
(internally, in the decompiler they still have return type `none`, but
they have `object` elsewhere).
Fixes#1703Fixes#830Fixes#928
Fixes#2167
Reduces test flakiness if ran on multiple threads and gets rid of a few
hundred files from the source tree
I believe this also makes #1434 irrelevant and it can be closed.
---------
Co-authored-by: ManDude <7569514+ManDude@users.noreply.github.com>
Fix the bug described in
https://github.com/open-goal/jak-project/issues/2882 where some shrubs
are transparent when they shouldn't be. The problem was that we never
carefully looked at the settings in `gs-prim`, which has a bit to
enable/disable alpha blending entirely. Now it should be correct for
both jak 1 and jak 2. To see this change, you'll need to re-extract.
Also adds a setting to disable saving texture .pngs, to speed up
decompilation. I left it on for jak 1 (to avoid confusion for texture
swapping(, but off for jak 2 for now.
```lisp
(defenum collide-action
:type uint32
:bitfield #t
(solid 0) ;; used for solid things
(rider-plat-sticky 1) ;; used for platforms in rider/platform interactions
(rider-target 2) ;; used for target in rider/platform interactions
(edgegrab-active 3) ;; set/cleared when entering/exiting edgegrab states
(rider-plat 4) ;; used for platforms in rider/platform interactions
(unused 5) ;; totally unused?
(edgegrab-possible 6) ;; used when edge grab checks should be done
(edgegrab-cam 7) ;; set/cleared when entering/exiting edgegrab states
(swingpole-active 8) ;; set/cleared when entering/exiting swingpole states
(racer 9) ;; set/cleared when entering/exiting racer states
(attackable 10) ;; used for something to do with attacking/damaging
(attackable-unused 11) ;; seems to relate to attacking - set in several places but never tested for?
(snowball 12) ;; set/cleared when entering/exiting snowball states
(tube 13) ;; set/cleared when entering/exiting tube states
(flut 14) ;; set/cleared when entering/exiting flutflut states
(racer-grounded 15) ;; set/cleared when entering/exiting certain racer states w/ extra conditions
(racer-unused 16) ;; seems to relate to racer - never set, only cleared in one place?
)
```
Gives proper names to almost every color. It is very apparent that some
colors are context-sensitive/made for a specific purpose, so those
colors were named after that purpose instead of a generic color name.
Updates the decompiler for the new format and there's new macros. This
new format should be easier to read/parse.
Also rewrote `sp-init-fields!` (both jak 1 and 2) from assembly to GOAL.
Hopefully I did not miss any regressions in Jak 1/2 while updating the
files, it's a lot.
Cleans up every `dummy-*` and `TODO-RENAME-*` method up with either
proper names or by renaming them to `[type-name]-method-[method-id]`
similar to Jak 2's `all-types`.
Also fixes the bad format string in `collide-cache` and adds the event
handler hack to Jak 1.
The game boots and runs fine, but I might have missed a PAL patch or
other manual patches here and there, please double-check if possible.
Reasons for doing so include:
1. This should stop the confusion around editing the wrong config file's
flags -- when for example, extracting a level. Common settings can be in
one central place, with bespoke overrides being provided for each
version
2. Less verbose way of supporting multiple game versions. You don't have
to duplicate the entire `type_casts` file for example, just add or
override the json objects required.
3. Makes the folder structure consistent, Jak 1's `all-types` is now in
a `jak1` folder, etc.