Files
jak-project/goal_src/jak1/engine/load/file-io.gc
T
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

172 lines
6.3 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
(bundles "ENGINE.CGO" "GAME.CGO")
(require "kernel/gstring.gc")
;; GOAL File I/O
;; This is mostly not used in the retail game and was more for loading stuff during development.
;; The file-stream is an inefficient way to load data, but is flexible and can load
;; from the CD, or over the network in development.
;; The file-info type is used in actual game data for checking versions.
;; represents a file that can be read/written, similar to FILE* in C.
;; NOTE: this is a special type in three ways:
;; 1). It is used in the C runtime. This must be kept in sync with kmachine.h's FileStream
;; 2). This type is built-in to the compiler (see TypeSystem.cpp, add_builtin_types)
;; It must be kept up to date with that definition as well.
;; 3). The C runtime constructs this type before anything is loaded. The sizes
;; must be kept up to date there as well.
;; DECOMP BEGINS
(deftype file-stream (basic)
((flags uint32)
(mode symbol)
(name string)
(file uint32))
(:methods
(new (symbol type string symbol) _type_)))
(defconstant SCE_SEEK_SET 0)
(defconstant SCE_SEEK_CUR 1)
(defconstant SCE_SEEK_END 2)
(defmacro file-stream-valid? (fs)
`(>= (the-as int (-> ,fs file)) 0))
(defmacro file-stream-tell (fs)
`(file-stream-seek ,fs 0 SCE_SEEK_CUR))
(defmethod new file-stream ((allocation symbol) (type-to-make type) (name string) (mode symbol))
"Allocate a file-stream and open it."
(let ((a0-1 (object-new allocation type-to-make (the-as int (-> type-to-make size)))))
(file-stream-open a0-1 name mode)))
;; we already have a length method for a file-stream defined in C.
;; just store that in the method table.
(set! (-> file-stream method-table 4) file-stream-length)
(defun file-stream-read-string ((stream file-stream) (str string))
"Fill a string with data from a file stream.
Note: this function does not work."
;; makes the length of the string 0.
(clear str)
;; so this will read nothing.
(file-stream-read stream (-> str data) (length str))
str)
;; A common file header found in GOAL files.
(deftype file-info (basic)
((file-type symbol)
(file-name basic)
(major-version uint32)
(minor-version uint32)
(maya-file-name basic)
(tool-debug basic)
(mdb-file-name basic)))
(defmethod print ((this file-info))
"Print information about a file"
(format #t
"#<~A ~A :version ~D.~D @ #x~X>"
(-> this type)
(-> this file-name)
(-> this major-version)
(-> this minor-version)
this)
this)
;; allocate a temporary string
(define *file-temp-string* (new 'global 'string 128 (the string #f)))
(defenum file-kind
:bitfield #f
(level-bt 0) ;; aka bsp-header.
(art-group 1)
(tpage 2)
(dir-tpage 3)
(level-vs 4)
(tx 5)
(vis 6))
(defconstant LEVEL_BT_FILE_VERSION 30)
(defconstant ART_GROUP_FILE_VERSION 6)
(defconstant TPAGE_FILE_VERSION 7) ;; also used for dir
(defconstant LEVEL_VS_FILE_VERSION 30)
(defconstant TX_FILE_VERSION 1)
(defun make-file-name ((kind file-kind) (name string) (art-group-version int) (arg3 symbol))
"Get a file name to open a file with the given kind and name.
The art-group-version argument can be used to override the version
of the art-group. Set it to 0 or less to use the default version
Similar to MakeFileName in C.
Note: file type enum is different between C and GOAL.
File versions should match those in versions.h.
Uses a single *file-temp-string* buffer, shared with make-vfile-name.
arg3 is unused."
(clear *file-temp-string*)
(cond
((= kind (file-kind dir-tpage)) (format *file-temp-string* "texture-page~D/dir-tpages" TPAGE_FILE_VERSION))
((= kind (file-kind tpage))
(#if PC_PORT
(format *file-temp-string* "tpage-~S" name)
(format *file-temp-string* "texture-page~D/tpage-~S" TPAGE_FILE_VERSION name)))
((= kind (file-kind level-bt)) (format *file-temp-string* "level~D/~S-bt" LEVEL_VS_FILE_VERSION name))
((= kind (file-kind tx)) (format *file-temp-string* "res~D/~S-tx" TX_FILE_VERSION name))
((= kind (file-kind level-vs)) (format *file-temp-string* "level~D/~S-vs" LEVEL_BT_FILE_VERSION name))
((= kind (file-kind vis)) (format *file-temp-string* "~S.VIS" name))
((= kind (file-kind art-group))
(#if PC_PORT
(format *file-temp-string* "~S-ag" name)
(format *file-temp-string*
"art-group~D/~S-ag"
(if (> art-group-version 0) art-group-version ART_GROUP_FILE_VERSION)
name))))
*file-temp-string*)
(defun make-vfile-name ((kind file-kind) (name string))
"Make virtual? file name. This makes a name that the kernel knows how to
handle in a specific way. This function is not used."
(clear *file-temp-string*)
(cond
((= kind (file-kind level-bt)) (format *file-temp-string* "$LEVEL/~S" name))
((= kind (file-kind art-group)) (format *file-temp-string* "$ART_GROUP/~S" name)))
*file-temp-string*)
(defun file-info-correct-version? ((info file-info) (kind file-kind) (version-override int))
"Check if the version and kind in the info is valid. The version-override can specify a
non-default version, or set to 0 for the default version"
(let* ((expected-version (cond
((zero? version-override)
(case kind
(((file-kind tpage) (file-kind dir-tpage)) 7)
(((file-kind level-bt)) 30)
(((file-kind art-group)) 6)))
(else version-override)))
(v1-1 kind)
(kind-name (cond
((= v1-1 (file-kind tpage)) "texture-page")
((= v1-1 (file-kind level-bt)) "bsp-header")
((= v1-1 (file-kind art-group)) "art-group"))))
(cond
((not (name= (the-as basic (-> info file-type value)) kind-name))
(format 0 "ERROR: file ~A is of type ~S but needs to be ~S.~%" (-> info file-name) (-> info file-type) kind-name)
#f)
((!= expected-version (-> info major-version))
(format 0
"ERROR: file ~A is version ~D.~D, but needs to be ~D.x~%"
(-> info file-name)
(-> info major-version)
(-> info minor-version)
expected-version)
#f)
(else
;; all checks passed!
#t))))