jak-project/goal_src/jak1/engine/level/level-h.gc
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

420 lines
17 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
(bundles "ENGINE.CGO" "GAME.CGO")
(require "engine/gfx/vu1-user-h.gc")
(require "engine/dma/dma-h.gc")
;; The level system is responsible for loading and managning the two levels,
;; including the visible data.
;; The "level" type contains runtime information about a level (possibly one that is loading)
;; and the "level-group" type contains two levels.
(defconstant LEVEL_COUNT 2) ;; there are two levels in memory!
(declare-type bsp-header basic)
(declare-type drawable basic)
(declare-type engine basic)
(declare-type entity-links-array basic)
(declare-type entity-ambient-data-array basic)
(declare-type mood-context basic)
(declare-type entity-links structure)
;; DECOMP BEGINS
;;;;;;;;;;;;;;;
;; VIS
;;;;;;;;;;;;;;;
;; each game "level" has some precomputed visibility.
;; There's a binary space partition (bsp)
;; Each leaf node corresponds to a bit string with (up to) 16384 bits
;; These bits tell you if a certain "drawable" is visible or not.
;; The drawable's index is the index of its visibilty bit.
;; Note that not all drawables have a visibility bit - drawable groups sometimes don't and shrub's don't.
;; One challenge of the visibility system is that you can't actually load the visibility for two levels
;; at the same time. Each level has a large .VIS file that must be loaded.
;; The actual level files contain a small amount of VIS file for areas on their borders.
;; While the .VIS is loading (or you are on the border of two levels), the engine will look in these
;; small visibility infos.
;; The large .VIS files are stored on the IOP. As a result, there's a small delay to actually
;; fetch a visibility string.
(defenum vis-info-flag
:bitfield #t
:type uint32
(from-vis-file 29) ;; is .VIS file vis?
(waiting-for-iop-to-ee 30) ;; not here yet
(using-this-as-only-vis 31) ;; using this as the only visibility data
)
;; Information related to visibility data for a level.
;; This is just metadata that describes the actual visibiltiy data.
;; The typical use is to do (-> info vis-string idx) to get the offset (in the .VIS file) of the
;; compressed visibility string for a given bsp leaf.
;; Each level may have multiple level-vis-infos.
;; One level-vis-info (the first) is always for the
;; actual level (stored in .VIS file), and there is typically one for each neighboring level.
;; The final level-vis-info (7) should always be empty (set to 0 in the bsp-header)
;; When travelling between two levels, the game will only have one .VIS file loaded,
;; and it does two lookups in this .VIS file - one for the current level, and one for the nearby
;; levels. This means that visibility for "beach" near the border of "village1" is stored in
;; both BEA.VIS and VI1.VIS.
(deftype level-vis-info (basic)
((level symbol)
(from-level symbol)
(from-bsp bsp-header)
(flags uint32)
(length uint32)
(allocated-length uint32)
(dictionary-length uint32)
(dictionary uint32)
(string-block uint32)
(ramdisk uint32)
(vis-bits pointer)
(current-vis-string uint32)
(vis-string uint32 :dynamic)))
(defmethod asize-of ((this level-vis-info))
"Get the size of a level-vis-info in memory"
(the-as int (+ (-> level-vis-info size) (-> this dictionary-length))))
;; Per level information related to how to load the level.
;; These are stored in level-info.gc which is always loaded, so this should have all the information required
;; to do a level load.
(deftype level-load-info (basic)
((name-list symbol 3)
(index int32) ;; the level number (starting with 1?)
(name symbol :overlay-at (-> name-list 0))
(visname symbol :overlay-at (-> name-list 1))
(nickname symbol :overlay-at (-> name-list 2))
(packages pair)
(sound-banks pair)
(music-bank symbol)
(ambient-sounds pair)
(mood symbol)
(mood-func symbol)
(ocean symbol)
(sky symbol)
(sun-fade float)
(continues pair)
(tasks pair)
(priority int32)
(load-commands pair)
(alt-load-commands pair)
(bsp-mask uint64)
(bsphere sphere)
(buzzer int32)
(bottom-height meters)
(run-packages pair)
(prev-level basic)
(next-level basic)
(wait-for-load symbol)))
;; The levels are initialized (called "login") over multiple frames.
;; The state of this process is stored in a login-state.
(deftype login-state (basic)
((state int32)
(pos uint32)
(elts uint32)
(elt drawable 16)))
;; The actual "level". This manages loading and running a game level.
;; These are allocated by the engine and aren't in static level data.
(deftype level (basic)
((name symbol)
(load-name symbol)
(nickname symbol)
(index int32)
(status symbol)
(other level)
(heap kheap :inline)
(bsp bsp-header)
(art-group load-dir-art-group)
(info level-load-info)
(texture-page texture-page 9)
(loaded-texture-page texture-page 16)
(loaded-texture-page-count int32)
(tfrag-tex-foreground-sink-group dma-foreground-sink-group :inline)
(pris-tex-foreground-sink-group dma-foreground-sink-group :inline)
(water-tex-foreground-sink-group dma-foreground-sink-group :inline)
(foreground-sink-group dma-foreground-sink-group 3 :inline :overlay-at tfrag-tex-foreground-sink-group)
(foreground-draw-engine engine 3)
(entity entity-links-array)
(ambient entity-ambient-data-array)
(closest-object float 9)
(upload-size int32 9)
(level-distance meters)
(inside-sphere? symbol)
(inside-boxes? symbol)
(display? symbol)
(meta-inside? symbol)
(mood mood-context)
(mood-func (function mood-context float int none))
(vis-bits pointer)
(all-visible? symbol)
(force-all-visible? symbol)
(linking basic)
(vis-info level-vis-info 8)
(vis-self-index int32)
(vis-adj-index int32)
(vis-buffer uint8 2048)
(mem-usage-block memory-usage-block)
(mem-usage int32)
(code-memory-start pointer)
(code-memory-end pointer)
(texture-mask uint32 9)
(force-inside? symbol)
(pad uint8 56))
(:methods
(deactivate (_type_) _type_)
(is-object-visible? (_type_ int) symbol)
(add-irq-to-tex-buckets! (_type_) none)
(unload! (_type_) _type_)
(bsp-name (_type_) symbol)
(compute-memory-usage (_type_ object) memory-usage-block)
(point-in-boxes? (_type_ vector) symbol)
(update-vis! (_type_ level-vis-info uint uint) symbol)
(load-continue (_type_) _type_)
(load-begin (_type_) _type_)
(login-begin (_type_) _type_)
(vis-load (_type_) uint)
(unused-21 (_type_) none)
(birth (_type_) _type_)
(level-status-set! (_type_ symbol) _type_)
(load-required-packages (_type_) _type_)
(init-vis (_type_) int)
(vis-clear (_type_) int)
(debug-print-splitbox (_type_ vector string) none)
(art-group-get-by-name (_type_ string) art-group)))
(deftype level-group (basic)
((length int32)
(log-in-level-bsp bsp-header)
(loading-level level)
(entity-link entity-links)
(border? basic)
(vis? basic)
(want-level basic)
(receiving-level basic)
(load-commands pair)
(play? symbol)
(_hack-pad uint8 :offset 90)
(level0 level :inline)
(level1 level :inline)
(level-default level :inline)
(level level 3 :inline :overlay-at level0)
(data level 3 :inline :overlay-at level0)
(pad uint32))
(:methods
(level-get (_type_ symbol) level)
(level-get-with-status (_type_ symbol) level)
(level-get-for-use (_type_ symbol symbol) level)
(activate-levels! (_type_) int)
(debug-print-entities (_type_ symbol type) none)
(debug-draw-actors (_type_ symbol) none)
(actors-update (_type_) object)
(level-update (_type_) int)
(level-get-target-inside (_type_) level)
(alloc-levels! (_type_ symbol) int)
(load-commands-set! (_type_ pair) pair)
(art-group-get-by-name (_type_ string) art-group)
(load-command-get-index (_type_ symbol int) pair)
(update-vis-volumes (_type_) none)
(update-vis-volumes-from-nav-mesh (_type_) none)
(print-volume-sizes (_type_) none)
(level-status (_type_ symbol) symbol)
(level-get-most-disposable (_type_) level)))
(defun-extern level-update-after-load level login-state level)
;; Initialize the level structure. This assigns DMA buckets to each level.
;; there are 3 foreground sinks per texture bucket: merc, generic, and an unused one.
;; TODO: figure out exactly which buckets are used for what.
(define-extern *level* level-group)
(if (zero? *level*)
(set! *level*
(new 'static
'level-group
:length 2
:log-in-level-bsp #f
:loading-level #f
:entity-link #f
:border? #f
:want-level #f
:load-commands
'()
:play? #f
:level0
(new 'static
'level
:name #f
:status 'inactive
:tfrag-tex-foreground-sink-group
(new 'static
'dma-foreground-sink-group
:sink
(new 'static
'array
dma-foreground-sink
3
(new 'static 'dma-foreground-sink :bucket (bucket-id merc-tfrag-tex0))
(new 'static 'generic-dma-foreground-sink :bucket (bucket-id generic-tfrag-tex0) :foreground-output-bucket 1)))
:pris-tex-foreground-sink-group
(new 'static
'dma-foreground-sink-group
:sink
(new 'static
'array
dma-foreground-sink
3
(new 'static 'dma-foreground-sink :bucket (bucket-id merc-pris0) :foreground-texture-page 1)
(new 'static
'generic-dma-foreground-sink
:bucket (bucket-id generic-pris0)
:foreground-texture-page 1
:foreground-output-bucket 1)))
:water-tex-foreground-sink-group
(new 'static
'dma-foreground-sink-group
:sink
(new 'static
'array
dma-foreground-sink
3
(new 'static 'dma-foreground-sink :bucket (bucket-id merc-water0) :foreground-texture-page 2)
(new 'static
'generic-dma-foreground-sink
:bucket (bucket-id generic-water0)
:foreground-texture-page 2
:foreground-output-bucket 1)))
:inside-sphere? #f
:inside-boxes? #f
:force-inside? #f)
:level1
(new 'static
'level
:name #f
:index 1
:status 'inactive
:tfrag-tex-foreground-sink-group
(new 'static
'dma-foreground-sink-group
:sink
(new 'static
'array
dma-foreground-sink
3
(new 'static 'dma-foreground-sink :bucket (bucket-id merc-tfrag-tex1) :foreground-texture-level 1)
(new 'static
'generic-dma-foreground-sink
:bucket (bucket-id generic-tfrag-tex1)
:foreground-texture-level 1
:foreground-output-bucket 1)))
:pris-tex-foreground-sink-group
(new 'static
'dma-foreground-sink-group
:sink
(new 'static
'array
dma-foreground-sink
3
(new 'static 'dma-foreground-sink :bucket (bucket-id merc-pris1) :foreground-texture-page 1 :foreground-texture-level 1)
(new 'static
'generic-dma-foreground-sink
:bucket (bucket-id generic-pris1)
:foreground-texture-page 1
:foreground-texture-level 1
:foreground-output-bucket 1)))
:water-tex-foreground-sink-group
(new 'static
'dma-foreground-sink-group
:sink
(new 'static
'array
dma-foreground-sink
3
(new 'static 'dma-foreground-sink :bucket (bucket-id merc-water1) :foreground-texture-page 2 :foreground-texture-level 1)
(new 'static
'generic-dma-foreground-sink
:bucket (bucket-id generic-water1)
:foreground-texture-page 2
:foreground-texture-level 1
:foreground-output-bucket 1)))
:inside-sphere? #f
:inside-boxes? #f
:force-inside? #f)
:level-default
(new 'static
'level
:name 'default
:index 2
:status 'reserved
:tfrag-tex-foreground-sink-group
(new 'static
'dma-foreground-sink-group
:sink
(new 'static
'array
dma-foreground-sink
3
(new 'static 'dma-foreground-sink :bucket (bucket-id merc-alpha-tex) :foreground-texture-level 2)
(new 'static
'generic-dma-foreground-sink
:bucket (bucket-id generic-alpha-tex)
:foreground-texture-level 2
:foreground-output-bucket 1)))
:pris-tex-foreground-sink-group
(new 'static
'dma-foreground-sink-group
:sink
(new 'static
'array
dma-foreground-sink
3
(new 'static
'dma-foreground-sink
:bucket (bucket-id merc-pris-common)
:foreground-texture-page 1
:foreground-texture-level 2)
(new 'static
'generic-dma-foreground-sink
:bucket (bucket-id generic-pris-common)
:foreground-texture-page 1
:foreground-texture-level 2
:foreground-output-bucket 1)))
:water-tex-foreground-sink-group
(new 'static
'dma-foreground-sink-group
:sink
(new 'static
'array
dma-foreground-sink
3
(new 'static 'dma-foreground-sink :bucket (bucket-id merc-water0) :foreground-texture-page 2 :foreground-texture-level 2)
(new 'static
'generic-dma-foreground-sink
:bucket (bucket-id generic-water0)
:foreground-texture-page 2
:foreground-texture-level 2
:foreground-output-bucket 1)))
:inside-sphere? #f
:inside-boxes? #f
:force-inside? #f))))
(define-extern *level-load-list* pair)
(define-extern lookup-level-info (function symbol level-load-info))