jak-project/goal_src/engine/level/level-h.gc
2022-02-05 16:30:50 -05:00

446 lines
22 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
;; name: level-h.gc
;; name in dgo: level-h
;; dgos: GAME, ENGINE
;; 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)
;;;;;;;;;;;;;;;
;; 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 :offset-assert 4)
(from-level symbol :offset-assert 8)
(from-bsp bsp-header :offset-assert 12)
(flags uint32 :offset-assert 16)
(length uint32 :offset-assert 20)
(allocated-length uint32 :offset-assert 24)
(dictionary-length uint32 :offset-assert 28)
(dictionary uint32 :offset-assert 32)
(string-block uint32 :offset-assert 36)
(ramdisk uint32 :offset-assert 40) ;; ramdisk file ID.
(vis-bits pointer :offset-assert 44)
(current-vis-string uint32 :offset-assert 48)
(vis-string uint32 :dynamic :offset-assert 52)
)
:method-count-assert 9
:size-assert #x34
:flag-assert #x900000034
)
(defmethod asize-of level-vis-info ((obj level-vis-info))
"Get the size of a level-vis-info in memory"
(the-as int (+ (-> level-vis-info size) (-> obj 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 :offset-assert 4)
(index int32 :offset-assert 16) ;; the level number (starting with 1?)
(name symbol :offset 4) ;; symbol with full name, like "misty"
(visname symbol :offset 8) ;; symbol with vis file name, like "misty-vis"
(nickname symbol :offset 12) ;; 3 letter name for DGO, like "mis"
(packages pair :offset-assert 20) ;; list of symbols, usually empty or the level name
(sound-banks pair :offset-assert 24) ;; require sound bank files (list of symbols)
(music-bank symbol :offset-assert 28) ;; name of level music
(ambient-sounds pair :offset-assert 32) ;; always empty list.
(mood symbol :offset-assert 36) ;; mood object name
(mood-func symbol :offset-assert 40) ;; mood update function name
(ocean symbol :offset-assert 44) ;; ocean map object
(sky symbol :offset-assert 48) ;; boolean to enable sky
(sun-fade float :offset-assert 52) ;; sun/sky setting
(continues pair :offset-assert 56) ;; list of checkpoints
(tasks pair :offset-assert 60) ;; list of boxed integers for tasks
(priority int32 :offset-assert 64) ;; either 100 or 200
(load-commands pair :offset-assert 68) ;; ??
(alt-load-commands pair :offset-assert 72) ;; ??
(bsp-mask uint64 :offset-assert 80) ;; ??
(bsphere sphere :offset-assert 88) ;; boundings sphere of level?
(buzzer int32 :offset-assert 92) ;; which task is the scout fly?
(bottom-height meters :offset-assert 96)
(run-packages pair :offset-assert 100) ;; possibly unused?
(prev-level basic :offset-assert 104)
(next-level basic :offset-assert 108)
(wait-for-load symbol :offset-assert 112)
)
:method-count-assert 9
:size-assert #x74
:flag-assert #x900000074
)
;; 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 :offset-assert 4)
(pos uint32 :offset-assert 8)
(elts uint32 :offset-assert 12)
(elt drawable 16 :offset-assert 16) ;; might be more specific
)
:method-count-assert 9
:size-assert #x50
:flag-assert #x900000050
)
;; The actual "level". This manages loading and running a game level.
(deftype level (basic)
((name symbol :offset-assert 4)
(load-name symbol :offset-assert 8)
(nickname symbol :offset-assert 12)
(index int32 :offset-assert 16)
(status symbol :offset-assert 20)
(other level :offset-assert 24) ;; the other level object
(heap kheap :inline :offset-assert 32) ;; level's ~10 MB heap
(bsp bsp-header :offset-assert 48) ;; the main level object in the DGO
(art-group load-dir-art-group :offset-assert 52) ;; the art (foreground models/anims) for the level
(info level-load-info :offset-assert 56)
(texture-page texture-page 9 :offset-assert 60)
(loaded-texture-page texture-page 16 :offset-assert 96)
(loaded-texture-page-count int32 :offset-assert 160)
; (foreground-sink-group-0 dma-foreground-sink-group :inline :offset-assert 176)
; (foreground-sink-group-1 dma-foreground-sink-group :inline :offset-assert 208)
; (foreground-sink-group-2 dma-foreground-sink-group :inline :offset-assert 240)
; (array-pad uint8 12)
(foreground-sink-group dma-foreground-sink-group 3 :inline :offset-assert 176) ;; inline basic
(foreground-draw-engine engine 3 :offset-assert 272)
(entity entity-links-array :offset-assert 284)
(ambient entity-ambient-data-array :offset-assert 288)
(closest-object float 9 :offset-assert 292)
(upload-size int32 9 :offset-assert 328)
(level-distance meters :offset-assert 364)
(inside-sphere? symbol :offset-assert 368)
(inside-boxes? symbol :offset-assert 372)
(display? symbol :offset-assert 376)
(meta-inside? symbol :offset-assert 380)
(mood mood-context :offset-assert 384)
(mood-func (function mood-context float int none) :offset-assert 388)
(vis-bits pointer :offset-assert 392)
(all-visible? symbol :offset-assert 396)
(force-all-visible? symbol :offset-assert 400)
(linking basic :offset-assert 404)
(vis-info level-vis-info 8 :offset-assert 408) ;; note: #f when doesn't exist.
(vis-self-index int32 :offset-assert 440)
(vis-adj-index int32 :offset-assert 444)
(vis-buffer uint8 2048 :offset-assert 448)
(mem-usage-block memory-usage-block :offset-assert 2496)
(mem-usage int32 :offset-assert 2500)
(code-memory-start pointer :offset-assert 2504)
(code-memory-end pointer :offset-assert 2508)
(texture-mask uint32 9 :offset-assert 2512)
(force-inside? symbol :offset-assert 2548)
(pad uint8 56)
)
:method-count-assert 29
:size-assert #xa30
:flag-assert #x1d00000a30
(:methods
(deactivate (_type_) _type_ 9)
(is-object-visible? (_type_ int) symbol 10)
(add-irq-to-tex-buckets! (_type_) none 11)
(unload! (_type_) _type_ 12)
(bsp-name (_type_) symbol 13)
(compute-memory-usage (_type_ object) memory-usage-block 14)
(point-in-boxes? (_type_ vector) symbol 15)
(update-vis! (_type_ level-vis-info uint uint) symbol 16)
(load-continue (_type_) _type_ 17)
(load-begin (_type_) _type_ 18)
(login-begin (_type_) _type_ 19)
(vis-load (_type_) uint 20)
(dummy-21 (_type_) none 21)
(birth (_type_) _type_ 22)
(level-status-set! (_type_ symbol) _type_ 23)
(load-required-packages (_type_) _type_ 24)
(init-vis (_type_) int 25)
(vis-clear (_type_) int 26)
(debug-print-splitbox (_type_ vector string) none 27)
(art-group-get-by-name (_type_ string) art-group 28)
)
)
;; Main *level* object.
;; There are actually three levels. level0 and level1 correspond to the actual buffered levels
;; The level-default seems to be a fake level that can possibly be used by renderers that
;; don't belong to any level, for example to render Jak.
(deftype level-group (basic)
((length int32 :offset-assert 4)
(log-in-level-bsp bsp-header :offset-assert 8) ;; level currently logging in
(loading-level level :offset-assert 12) ;; currently loading
(entity-link entity-links :offset-assert 16) ;; not sure what's going on here
(border? basic :offset-assert 20)
(vis? basic :offset-assert 24)
(want-level basic :offset-assert 28)
(receiving-level basic :offset-assert 32)
(load-commands pair :offset-assert 36)
(play? symbol :offset-assert 40)
;; there's something? from 40 -> 96.
(_hack-pad uint8 :offset 90)
(level0 level :inline :offset-assert 96)
(level1 level :inline :offset-assert 2704)
(level-default level :inline :offset-assert 5312)
;; this actually went earlier,
(level level 3 :inline :offset 96)
;; and this one too. why another one?
(data level 3 :score -1 :inline :offset 96)
(pad uint32)
)
:method-count-assert 27
:size-assert #x1ef4
:flag-assert #x1b00001ef4
(:methods
(level-get (_type_ symbol) level 9)
(level-get-with-status (_type_ symbol) level 10)
(level-get-for-use (_type_ symbol symbol) level 11)
(activate-levels! (_type_) int 12)
(debug-print-entities (_type_ symbol type) none 13)
(debug-draw-actors (_type_ symbol) none 14)
(actors-update (_type_) object 15)
(level-update (_type_) int 16)
(level-get-target-inside (_type_) level 17)
(alloc-levels! (_type_ symbol) int 18)
(load-commands-set! (_type_ pair) pair 19)
(art-group-get-by-name (_type_ string) art-group 20)
(load-command-get-index (_type_ symbol int) pair 21)
(update-vis-volumes (_type_) none 22)
(update-vis-volumes-from-nav-mesh (_type_) none 23)
(print-volume-sizes (_type_) none 24)
(level-status (_type_ symbol) symbol 25)
(level-get-most-disposable (_type_) level 26)
)
)
(defun-extern level-update-after-load level login-state level)
;; Initialize the level structure. This assigns DMA buckets to each level.
;; 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
:foreground-sink-group
(new 'static 'inline-array dma-foreground-sink-group 3
(new 'static 'dma-foreground-sink-group
:sink (new 'static 'array dma-foreground-sink 3
(new 'static 'dma-foreground-sink :bucket 10)
(new 'static 'generic-dma-foreground-sink
:bucket 11 :foreground-output-bucket 1
)
)
)
(new 'static 'dma-foreground-sink-group
:sink (new 'static 'array dma-foreground-sink 3
(new 'static 'dma-foreground-sink
:bucket 49
:foreground-texture-page 1
)
(new 'static 'generic-dma-foreground-sink
:bucket 50 :foreground-texture-page 1
:foreground-output-bucket 1)
)
)
(new 'static 'dma-foreground-sink-group
:sink (new 'static 'array dma-foreground-sink 3
(new 'static 'dma-foreground-sink
:bucket 58
:foreground-texture-page 2
)
(new 'static 'generic-dma-foreground-sink
:bucket 59
: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
:foreground-sink-group
(new 'static 'inline-array dma-foreground-sink-group 3
(new 'static 'dma-foreground-sink-group
:sink (new 'static 'array dma-foreground-sink 3
(new 'static 'dma-foreground-sink
:bucket 17
:foreground-texture-level 1
)
(new 'static 'generic-dma-foreground-sink
:bucket 18
:foreground-texture-level 1
:foreground-output-bucket 1
)
)
)
(new 'static 'dma-foreground-sink-group
:sink (new 'static 'array dma-foreground-sink 3
(new 'static 'dma-foreground-sink
:bucket 52
:foreground-texture-page 1
:foreground-texture-level 1
)
(new 'static 'generic-dma-foreground-sink
:bucket 53
:foreground-texture-page 1
:foreground-texture-level 1
:foreground-output-bucket 1
)
)
)
(new 'static 'dma-foreground-sink-group
:sink (new 'static 'array dma-foreground-sink 3
(new 'static 'dma-foreground-sink
:bucket 61
:foreground-texture-page 2
:foreground-texture-level 1
)
(new 'static 'generic-dma-foreground-sink
:bucket 62
: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
:foreground-sink-group
(new 'static 'inline-array dma-foreground-sink-group 3
(new 'static 'dma-foreground-sink-group
:sink (new 'static 'array dma-foreground-sink 3
(new 'static 'dma-foreground-sink
:bucket 45
:foreground-texture-level 2
)
(new 'static 'generic-dma-foreground-sink
:bucket 46
:foreground-texture-level 2
:foreground-output-bucket 1
)
)
)
(new 'static 'dma-foreground-sink-group
:sink (new 'static 'array dma-foreground-sink 3
(new 'static 'dma-foreground-sink
:bucket 55
:foreground-texture-page 1
:foreground-texture-level 2
)
(new 'static 'generic-dma-foreground-sink
:bucket 56
:foreground-texture-page 1
:foreground-texture-level 2
:foreground-output-bucket 1
)
)
)
(new 'static 'dma-foreground-sink-group
:sink (new 'static 'array dma-foreground-sink 3
(new 'static 'dma-foreground-sink
:bucket 58
:foreground-texture-page 2
:foreground-texture-level 2
)
(new 'static 'generic-dma-foreground-sink
:bucket 59
: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))