mirror of https://github.com/n64decomp/mk64.git
parent
a86b3b0a2e
commit
da5c5b5624
98
README.md
98
README.md
|
|
@ -1,5 +1,5 @@
|
|||
# Mario Kart 64
|
||||
This work-in-progress decompilation of Mario Kart 64 pursues historical and educational elements within the game found via taking it apart and putting it back together. Inspiration to do so not only emanates from the game's hardware and technology but also its immensely positive effects on the cultures and families of nearly every nationality. See [progress](#Progress) for more information.
|
||||
This work-in-progress decompilation of Mario Kart 64 pursues historical and educational elements within the game found via taking it apart and putting it back together. Inspiration to do so not only emanates from the game's hardware and technology but also its immensely positive effects on the cultures and families of nearly every nationality.
|
||||
|
||||
This repository does not contain assets. Compiling requires asset extraction from a prior copy of the game.
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ It supports and builds the following versions:
|
|||
| mk64.eu-1.0.z64 | EUR 1.0 | a729039453210b84f17019dda3f248d5888f7690 |
|
||||
| mk64.eu-final.z64 | EUR 1.1 | f6b5f519dd57ea59e9f013cc64816e9d273b2329 |
|
||||
|
||||
## Score progress
|
||||
## Progress
|
||||
|
||||
Total progress consists of all code segments together.
|
||||
|
||||
|
|
@ -30,96 +30,23 @@ Game code progress consists of `main`, `ending` and `racing`.
|
|||
- [](https://ci.valandil.ca/job/mk64/job/master/)
|
||||
- [](https://ci.valandil.ca/job/mk64/job/master/)
|
||||
|
||||
## Dependencies
|
||||
## Quick Start
|
||||
|
||||
The build system has the following package requirements:
|
||||
|
||||
binutils-mips >= 2.27
|
||||
python3 >= 3.6
|
||||
libaudiofile
|
||||
|
||||
To add submodules run `git submodule update --init --recursive` after cloning.
|
||||
|
||||
## EU Specific Steps (All versions)
|
||||
Both EU builds first requires US to be built first:
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
```
|
||||
make -j
|
||||
```
|
||||
|
||||
Now build either EU 1.0 `eu-1.0` or EU 1.1 `eu-final`
|
||||
```
|
||||
make -j VERSION=eu-final
|
||||
```
|
||||
|
||||
diff/first-diff commands
|
||||
```
|
||||
python3 first-diff.py --eu
|
||||
./diff <function> -eu
|
||||
```
|
||||
|
||||
#### Debian / Ubuntu
|
||||
```
|
||||
sudo apt install build-essential pkg-config git binutils-mips-linux-gnu python3 zlib1g-dev libaudiofile-dev libcapstone-dev
|
||||
```
|
||||
|
||||
#### Arch Linux
|
||||
|
||||
To install build dependencies:
|
||||
```
|
||||
sudo pacman -S base-devel capstone python
|
||||
```
|
||||
Install the following AUR packages:
|
||||
* [mips64-elf-binutils](https://aur.archlinux.org/packages/mips64-elf-binutils) (AUR)
|
||||
|
||||
Review the n64decomp/sm64 readme for instructions to compile in other distributions.
|
||||
|
||||
#### Windows
|
||||
|
||||
Compiling on Windows requires `MSYS2 MinGW x64`. The setup process is a tad intensive.
|
||||
|
||||
[Instructions here](docs/BUILD_WINDOWS.md)
|
||||
|
||||
#### macOS
|
||||
|
||||
Install [Homebrew](https://brew.sh), then install the following dependencies:
|
||||
```
|
||||
brew update
|
||||
brew install python3 capstone coreutils make pkg-config tehzz/n64-dev/mips64-elf-binutils
|
||||
```
|
||||
|
||||
When building, use `gmake` to ensure that homebrew `make` is used instead of the old, macOS system `make`.
|
||||
|
||||
#### Docker
|
||||
|
||||
Build the Docker image:
|
||||
```
|
||||
docker build -t mk64 .
|
||||
```
|
||||
|
||||
When building and using other tools, append the following in front of every command you run:
|
||||
```bash
|
||||
docker run --rm -v ${PWD}:/mk64 mk64
|
||||
```
|
||||
|
||||
For example:
|
||||
```bash
|
||||
docker run --rm -v ${PWD}:/mk64 mk64 make -C tools
|
||||
docker run --rm -v ${PWD}:/mk64 mk64 make
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
Place a US version of Mario Kart 64 called `baserom.us.z64` into the project folder for asset extraction.
|
||||
Build instructions located in the [API docs](https://n64decomp.github.io/mk64/compiling.html)
|
||||
See also, the comprehensive API and documentation which includes an overview of the code-base while also discussing significant concepts, features, and modding.
|
||||
|
||||
Run the following commands after pulling:
|
||||
```bash
|
||||
make -C tools
|
||||
make
|
||||
```
|
||||
## Current State
|
||||
|
||||
## Progress
|
||||
|
||||
The source is in a 'shiftable' state that may allow modding but glitches may exist. Keep in-mind the code-base will alter significantly overtime. Feedback that raises awareness of new shift issues are welcome as a comment on issue #6. Note that some segments must be moved manually to prevent them colliding into each other.
|
||||
The code-base may change significanty overtime as naming and documentation continues. The code-base is shiftable.
|
||||
|
||||
Some menu textures are compressed using a format called tkmk00. A byte-matching compressor/decompressor does not yet exist.
|
||||
|
||||
|
|
@ -156,8 +83,9 @@ Some menu textures are compressed using a format called tkmk00. A byte-matching
|
|||
|
||||
## Documentation
|
||||
|
||||
[Doxygen](https://www.doxygen.nl/index.html) is used to generate documentation. To generate the documentation, run `doxygen Doxyfile` from the project root. The documentation will be generated in the `docs/html` folder.
|
||||
The documentation is also available online at [https://n64decomp.github.io/mk64/](https://n64decomp.github.io/mk64/).
|
||||
Documentation available online at [https://n64decomp.github.io/mk64/](https://n64decomp.github.io/mk64/).
|
||||
|
||||
Documentation generated using [Doxygen](https://www.doxygen.nl/index.html). Run `make doc -j` to test locally. Documentation resides in `docs/html`. Open index.html to view the site.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
|||
|
|
@ -50,13 +50,13 @@ https://github.com/N64-tools/mips64-gcc-toolchain
|
|||
|
||||
Merge the inner folders (bin, share, etc.) with the respective folders in `C:\msys64\mingw64\`
|
||||
|
||||
### Step 5: Compiling recomp.exe in `MSYS2 MinGW x64`
|
||||
### Step 5: Compiling recomp.exe in MSYS2 MinGW x64
|
||||
In `MSYS2 MinGW x64` run in `mk64/tools/ido5.3_recomp/`:
|
||||
```
|
||||
g++ recomp.cpp -o recomp -g -lcapstone -Dugen53
|
||||
```
|
||||
|
||||
### Step 6: Generate Recomp Source Files in `MSYS2 MinGW x64`
|
||||
### Step 6: Generate Recomp Source Files in MSYS2 MinGW x64
|
||||
|
||||
Generate the .c files which will compile into the recomp binaries.
|
||||
mk64 requires the following compiler binaries: `as1, cc, cfe, copt, ugen, ujoin, uld, umerge, uopt`
|
||||
|
|
@ -78,7 +78,7 @@ The binary for cc is in `/ido5.3_compiler/usr/bin/` so do:
|
|||
```
|
||||
./recomp ../ido5.3_compiler/usr/bin/cc > cc_c.c
|
||||
```
|
||||
### Step 7: Compiling the recomp compiler in `MSYS2 MSYS`
|
||||
### Step 7: Compiling the recomp compiler in MSYS2 MSYS
|
||||
In `MSYS2 MSYS` run in the directory `mk64/tools/ido5.3_recomp/`:
|
||||
```
|
||||
gcc libc_impl.c as1_c.c -o as1 -g -fno-strict-aliasing -lm -no-pie -DIDO53 -O2
|
||||
|
|
@ -93,7 +93,7 @@ gcc libc_impl.c uopt_c.c -o uopt -g -fno-strict-aliasing -lm -no-pie -DIDO53 -O2
|
|||
```
|
||||
`-O2` is an optional optimization flag.
|
||||
|
||||
### Step 8: Compile mk64 in `MSYS2 MinGW x64`
|
||||
### Step 8: Compile mk64 in MSYS2 MinGW x64
|
||||
In `/mk64/` run:
|
||||
```
|
||||
make -j#
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# Actors
|
||||
If you are familiar with oot or sm64 prepare to be very disappointed. Both games split actors into separate files. In an unorderly fashion, mk64 appears to place all actors in the same file save for the odd exception.
|
||||
|
||||
Actor setup:
|
||||
Example actor setup based on @ref update_course_actors
|
||||
```c
|
||||
// Loop through the actor list and run that particular actors behaviour.
|
||||
for actorListSize {
|
||||
|
|
@ -32,7 +32,7 @@ Check actor_types.h for a full list of options. You can create a new actor struc
|
|||
|
||||
See `update_obj_railroad_crossing` for an example of how a timer may be setup and used.
|
||||
|
||||
Audio may be activated in the following method:
|
||||
`func_800C98B8(actor->pos, actor->velocity, s32_audio_flag);`
|
||||
Audio may be activated using the following method:
|
||||
@ref func_800C98B8
|
||||
|
||||
For more complex uses such as distanceFrom and collision, you will need to analyze the other actors.
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@ The actor code has two main parts; the update code and the render code. The upda
|
|||
|
||||
`gObjectList` contains:
|
||||
```
|
||||
thwomps, bowser fire-breath, moles, hedgehogs, snowmen, crabs, etc (also, probably penguins and birds).
|
||||
thwomps, bowser fire-breath, moles, hedgehogs, snowmen, crabs, particles, leaves, etc (also, probably penguins and birds).
|
||||
```
|
||||
The object system is much more complex than actors and is not well documented.
|
||||
|
||||
\htmlonly
|
||||
<br><br>
|
||||
<br>
|
||||
<style>
|
||||
.pagebutton {
|
||||
display: inline-block;
|
||||
|
|
|
|||
|
|
@ -1,33 +1,37 @@
|
|||
@page concepts Basic Concepts
|
||||
See terminology for explanations of terms.
|
||||
See [terminology](terminology.html) for explanations of terms.
|
||||
|
||||
## Addresses
|
||||
Computers use addresses to jump through code. This works similar to finding a house using its address. Except, that reaching the house is nearly instantaneous and it only contains more instructions and jumps or some data such as a texture or a text string. Also, when finished with the house, you travel back to the previous destination which may have some left-over instructions or more jumps. You can imagine this quickly becoming a spaghetti monster jumping all over the place.
|
||||
# Addresses
|
||||
Computers use addresses to jump through code. This works similar to a house number.
|
||||
* A house contains a series of instructions or some data (ex. a texture).
|
||||
* A house can contain more jumps.
|
||||
* When business in a house completes, the computer jumps to the last house it was in.
|
||||
* The program execution completes when there are no more branches left.
|
||||
* Programs run in a big infinite loop so it cannot run out of branches.
|
||||
* A program may be imagined as a big spaghetti monster.
|
||||
* Note that n64 only runs one command/thread at a time.
|
||||
|
||||
A typical N64 address: `0x8029E158`
|
||||
A typical N64 address: `0x80160158`
|
||||
|
||||
In an N64 program, addresses begin at `0x80000000`. As you create code, data, and the like, the compiler will add onto this base number and assign variables to an address.
|
||||
```
|
||||
s32 a_value = 2; // Note that a_value can be any name: fox, pig, siodfj, etc.
|
||||
s32 b_value = 7;
|
||||
s32 a = 2; // 0x80000004
|
||||
s32 b = 7; // 0x80000008
|
||||
s32 c = 5; // 0x8000000C
|
||||
s32 d = 1; // 0x80000010
|
||||
s32 e = 3; // 0x80000014
|
||||
```
|
||||
Might compile a_value to `0x80000004` and b_value to `0x80000008`. At anytime if you manually wrote:
|
||||
Replacing a variable with a hard-coded address grabs the value at that address.
|
||||
```
|
||||
print(0x80000004); // or
|
||||
print(a_value);
|
||||
```
|
||||
Both would output `2`. This allows some trickery. Such as pointer math: `print(0x800000004 + 0x80000004)` would output `7`.
|
||||
|
||||
Addresses generally count up by fours: `0x4, 0x8, 0xC, 0x10, 0x14, etc.`
|
||||
|
||||
It does not when working with s8 and s16 integer types. An s32 or int always takes up eight digits: `00000001`
|
||||
```
|
||||
s32 a = 1;
|
||||
print(a);
|
||||
```
|
||||
Will output `1` but if you opened the program in a hexadecimal file you will notice that its written to disc as `0x00000001`
|
||||
Both would output `2`. This allows some trickery. Such as pointer math: `print(0x800000004 + 0x80000004)` would output `7`.
|
||||
Pointers may be similarily influenced: `&a + 4` results in `0x800000008` thus printing the value at `b`.
|
||||
|
||||
An s16 looks like: `0x0001` an s8 looks like: `0x01`.
|
||||
The compiler may `align` or offset variables to certain addresses. Generally, certain types of data is aligned to 0x10.
|
||||
|
||||
If `c` were placed in a new file, the compiler would place `c` at `0x80000010` and `e` would be placed at `0x80000020`.
|
||||
|
||||
Data can take up tonnes of space:
|
||||
```
|
||||
|
|
@ -35,18 +39,42 @@ Texture a_texture[] = {
|
|||
0x01, 0x0A, 0xAA, 0x34, 0x23, // Imagine five-hundred lines of this
|
||||
};
|
||||
```
|
||||
The address of this could extend from `0x80000100` to `0x800000534`. However, you would not see `0x80000533`. The compiler generally aligns objects to 4, 8, 0xC, or 0x10 (Note that files are generally aligned to 0x10). With the exception being when you're working with s16 and s8. If you have:
|
||||
The address of this could extend from `0x80000100` to `0x800000534`. However, you would not see data begin at `0x80000533`. The compiler generally aligns objects to 4, 8, 0xC, or 0x10. With the exception being when you're working with s16 and s8. If you have:
|
||||
```
|
||||
s16 a = 3;
|
||||
s32 b = 5;
|
||||
s16 a = 3; // Value compiled to 0x0003
|
||||
s32 b = 5; // Value compiled to 0x00000005
|
||||
```
|
||||
You might expect to see this: `000300000005` or `0x0003 0x00000005` But actually, it will be this:
|
||||
In a hexadecimal editor you may expect to see this: `000300000005` or `0x0003 0x00000005` But actually, it will be this:
|
||||
```
|
||||
0003000000000005 or 0x0003 0x0000 0x00000005
|
||||
```
|
||||
This is called alignment. The compiler *aligned* `b` to the next 'major' address. Of course, if you program two s16's then the blank `0x0000` will be used. The max size of an s8 is 0xFF (255). Trying to write a number higher than 255 to an s8 type may crash the program as it might try to write onto the next variable.
|
||||
The compiler aligned `b` to the nearest 0x4. If there were two s16's then the blank `0x0000` will be used.
|
||||
|
||||
### Code
|
||||
# How Errors Happen
|
||||
The maximum value of an s8 (0x00) is 0xFF or 255. `0xFF + 1 = 0x100` imagine this scenario:
|
||||
```
|
||||
s8 a = 1;
|
||||
s8 b = 2;
|
||||
s8 c = 3;
|
||||
s8 d = 255;
|
||||
f32 e = 5.0f;
|
||||
```
|
||||
If `d` was set to 0x100, the final `0` would be written to the first bit of `e`. This could result in an invalid float value or perhaps flipping the signedness of an s32 (from negative to positive and vice-versa).
|
||||
|
||||
Issues such as this could result in glitches or crashes. Once humble math calculating to immeasurable values.
|
||||
|
||||
## Array Overflows
|
||||
In the below example, my_func writes a value at the fifth index which does not exist. This results in writing 5.0f into the next variable lkely resulting in a crash. Array overflows may be easy to miss in complex programs and sometimes only crash on rare occasion.
|
||||
```
|
||||
f32 myArray[4] = {8.0f, 3.0f, 9.0f, 1.0f};
|
||||
|
||||
void my_func(index) {
|
||||
myArray[index] = 5.0f;
|
||||
}
|
||||
my_func(5);
|
||||
```
|
||||
|
||||
# Code
|
||||
Code contains addresses too. Lets take a look at some example assembly:
|
||||
```
|
||||
glabel entry_point
|
||||
|
|
@ -65,13 +93,13 @@ The `lui, addiu, ori, etc.` are just representations of the machine-code. For ex
|
|||
`op-code, parameters`
|
||||
0x3C is the op-code (lui or load-upper-immediate) this command loads an address. The `08` tells the CPU to use the register `t0` and the `0x800F` is the first-half of the address to load. So, in the register t0 (which is the size of an int: 0x00000000) the value `0x800F0000` is written.
|
||||
|
||||
Note that one machine-code command is the size of an int/s32/word. How do we load an address (which is the size of an int). There isn't enough room when you include the op-code and register: `0x3C08800F6990`. That no worky. So we have to do this with two commands called a hi and a lo:
|
||||
Note that one machine-code command is the size of an int/s32/word. How do we load an address (which is the size of an int). There isn't enough room when you include the op-code and register: `0x3C08800F6990`. That no worky. As such, loading data at an address requires two commands. The first half of the address is called a hi and the second half is called a lo:
|
||||
```
|
||||
/* 001008 80000408 25086910 */ addiu $t0, %lo(_mainSegmentEnd) # addiu $t0, $t0, 0x6910
|
||||
```
|
||||
Now, we're going to *add* the *offset*: `t0: 0x800F0000 + 0x6910 = 0x800F6910`.
|
||||
If you run the game and use a memory viewer at this location. You will quickly realize this region of data (it's actually .bss but lets not get into that), is the controller data. The data alters to reflect which controller buttons are pressed. So if I just wanted to read one of these values, the assembly will do two commands to put the address in the register. Then another command can read the address in that register to receive the value at that location. This value can be compared to see if the button is active. Ex. zero might mean not pressed, whereas one might mean pressed.
|
||||
If you run the game and use a memory viewer at this location. You will quickly realize this region of data (it's actually .bss but lets not get into that), is the controller data. The data alters to reflect which controller buttons are pressed. So if I just wanted to read one of these values, the cpu will run two commands to put the address into the register. Then another command can read the address in that register to receive the value at that location. This value can be compared to see if the button is active. Ex. zero might mean not pressed, whereas one might mean pressed.
|
||||
|
||||
Now, earlier it was mentioned that code contains addresses. If I wanted to, I could do this: `Jump to: 0x80000410`. Which would make the CPU start running code at that location. Or I could read the value that exists there: `0x2129FFF8`. Not sure what I might do with that number, but it does act like a normal number. In decimal it is: `556,400,632`. I could add and subtract to it (Which would likely crash the game if it tried to run that command after). Now, jumping to any code address in the middle of a function would almost certainly crash the game or result in strange behaviour. The purpose of this explanation is really to show that everything is just a bunch of numbers or values, represented by an address. Even code itself.
|
||||
Now, earlier it was mentioned that code contains addresses. If I wanted to, I could do this: `Jump to: 0x80000410`. Which would make the CPU start running code at that location. Or I could read the value that exists there: `0x2129FFF8`. Not sure what I might do with that number, but it does act like a normal number. In decimal it is: `556,400,632`. I could add and subtract to it (Which would likely crash the game if it tried to run that command after). Now, jumping to any code address in the middle of a function would almost certainly crash the game or result in strange behaviour. The purpose of this explanation is really to show that everything is just a bunch of numbers or values, represented by an address. Even the code itself.
|
||||
|
||||
For a more refined explanation of addresses and pointers its suggested to use the Googles. However, this explanation was written with the N64 in-mind.
|
||||
|
|
|
|||
|
|
@ -19,11 +19,9 @@ Essential skills and concepts to help you get started with mk64 decomp.
|
|||
}
|
||||
.pagelink:hover {
|
||||
box-shadow: 0 5px 15px 5px rgba(0,0,0,1);
|
||||
|
||||
}
|
||||
.pagelink:hover img {
|
||||
transform: scale3d(1.1,1.1,1.1);
|
||||
|
||||
}
|
||||
.pageimg {
|
||||
display: inline-block;
|
||||
|
|
@ -102,9 +100,9 @@ p {
|
|||
<div class="pagelink">
|
||||
<div class="pageimg"><img width=320 src="buttonimage.png" /></div>
|
||||
<div class="content">
|
||||
<div class="pageheading">Control Flow</div>
|
||||
<div class="pageheading">Codebase Overview</div>
|
||||
<div class="pagedescription">
|
||||
<p>Introduction to mk64's operating states and threading. Acclimate to the codebase with this essential read.</p>
|
||||
<p>Introduction to mk64's functionality, operating states, and threading. Acclimate to the codebase with this essential read.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -122,7 +120,7 @@ p {
|
|||
<div class="content">
|
||||
<div class="pageheading">Basic Concepts</div>
|
||||
<div class="pagedescription">
|
||||
<p>Decomp, hexadecimal, cpu threads, addresses, and types to provide foundation knowledge.</p>
|
||||
<p>n64 addressing, alignment, and basic types.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,26 +1,16 @@
|
|||
@page compiling Installing mk64 Decomp
|
||||
## Build Instructions
|
||||
# Build Instructions
|
||||
The build system has the following package requirements:
|
||||
|
||||
binutils-mips >= 2.27
|
||||
python3 >= 3.6
|
||||
libaudiofile
|
||||
|
||||
* [Linux and WSL](#linux)
|
||||
* [Arch](#arch)
|
||||
* [Windows](#windows)
|
||||
* [macOS](#macos)
|
||||
* [Docker](#docker)
|
||||
|
||||
### Compiling
|
||||
* [US](#building-us)
|
||||
* [EU](#building-eu)
|
||||
|
||||
|
||||
[TOC]
|
||||
|
||||
To add submodules run `git submodule update --init --recursive` after cloning.
|
||||
|
||||
## Linux
|
||||
# Linux
|
||||
```
|
||||
sudo apt install build-essential pkg-config git binutils-mips-linux-gnu python3 zlib1g-dev libaudiofile-dev libcapstone-dev
|
||||
```
|
||||
|
|
@ -35,13 +25,13 @@ Install the following AUR package:
|
|||
|
||||
Review the [n64decomp/sm64](https://github.com/n64decomp/sm64) readme for instructions to compile in other distributions.
|
||||
|
||||
## Windows
|
||||
# Windows
|
||||
|
||||
Not recommended. Use WSL unless this is your only option.
|
||||
|
||||
[Instructions here](docs/BUILD_WINDOWS.md)
|
||||
[Instructions here](buildwindows.html)
|
||||
|
||||
## macOS
|
||||
# macOS
|
||||
|
||||
Install [Homebrew](https://brew.sh), then install the following dependencies:
|
||||
```
|
||||
|
|
@ -51,7 +41,7 @@ brew install python3 capstone coreutils make pkg-config tehzz/n64-dev/mips64-elf
|
|||
|
||||
Build using `gmake` ensuring homebrew `make` is used instead of the old macOS system `make`.
|
||||
|
||||
## Docker
|
||||
# Docker
|
||||
|
||||
Build the Docker image:
|
||||
```
|
||||
|
|
@ -69,7 +59,7 @@ docker run --rm -v ${PWD}:/mk64 mk64 make -C tools
|
|||
docker run --rm -v ${PWD}:/mk64 mk64 make
|
||||
```
|
||||
|
||||
## Building US
|
||||
# Building US
|
||||
|
||||
Place a US version of Mario Kart 64 called `baserom.us.z64` into the project folder for asset extraction.
|
||||
|
||||
|
|
@ -79,7 +69,7 @@ make -C tools
|
|||
make -j
|
||||
```
|
||||
|
||||
## Building EU
|
||||
# Building EU
|
||||
|
||||
Building EU requires US to be built first. See above.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,12 @@
|
|||
\page controlflow Control Flow
|
||||
\page controlflow Codebase Overview
|
||||
|
||||
# Introduction to State
|
||||
The developers wrote mk64 using a state-driven paradigm. This manifests itself in a variety of ways but as a quick example lets discuss the following variables. `gGamestate`, `gGameMode`, and `gCurrentCourseId`. Code for menus, racing, and credits must be modularized in some fashion. The gamestate variable contains the current state and during runtime branches into the relevant code while skipping code not pertaining to the current state. The racing code does not run while the user operates the menu. Let's inspect a simple example of a state-driven mechanism:
|
||||
```c
|
||||
switch(gCurrentCourseId) {
|
||||
case YOSHI_VALLEY:
|
||||
load_and_render_yoshi_egg();
|
||||
break;
|
||||
case MARIO_RACEWAY:
|
||||
load_and_render_pipe();
|
||||
break;
|
||||
}
|
||||
```
|
||||
This code loads resources based on a specific course. An entire spaghetti tree of code may be imagined based on many series of conditional statements.
|
||||
[TOC]
|
||||
|
||||
# Paradigm
|
||||
The developers wrote mk64 using a state-driven paradigm. Gamestate, gamemode, course, actors, structs, and more decide which branches code should follow. As an example, a condition can check the current course to load that courses resources or run logic based on that.
|
||||
|
||||
# Threading
|
||||
The game begins by setting up its four threads; idle, video, audio, and the game loop.
|
||||
After boot, the game begins by setting up its four threads; idle, video, audio, and the game loop.
|
||||
The idle thread allows the cpu to sleep. Without it, if at any time execution of all threads were paused, the cpu would never be able to continue. The idle thread is active if all the other threads are paused.
|
||||
|
||||
As such, the idle thread runs the following loop: `while(TRUE);` (it runs in a perpetual loop of nothing; sleep). In mips assembly it looks like this:
|
||||
|
|
@ -55,3 +46,80 @@ video:
|
|||
If mk64 is in a menu state it will branch off to the menu code, running relevant bits of code based on more flags such as which particular menu the user is in. This will loop until the state changes to a different one such as race mode. If mk64 is in a race state, then race related code is ran and it spaghetti's off into a wide series of branches. This may include concepts such as `isLinedUp, isRacing, isRaceFinished, gotoNextCourse, isHuman, and isAI`.
|
||||
|
||||
This relatively primitive design could be defined as a state machine from an abstract point of view. This would differ from an OOP design that uses objects and hierarchy. You will become very familiar with this design principle as you explore the code-base. During any step of the game loop, a switch can be setup to check a flag then run code relevant to the situation. For instance, a flag can check whether a race is in-progress or complete. If in-progress set the player to human controlled. If complete, set player to AI controlled.
|
||||
|
||||
# Segments
|
||||
mk64 code is split into three sections
|
||||
|Segment|desc|
|
||||
|---|---|
|
||||
|Main|Menus, audio, libultra, rsp|
|
||||
|Racing|Memory management, courses, players, actors, skybox, collision, math |
|
||||
|Ending|Podium ceremony, credits|
|
||||
|
||||
Racing segment loads after selecting a grand prix. Note that it is always reloaded preventing randomization of cpu's at the start of the first race due to no time for the random seed to actually become random.
|
||||
|
||||
# Code Breakdown
|
||||
|
||||
## Players
|
||||
Player related code resides in
|
||||
|file|desc|
|
||||
|---|---|
|
||||
|player_controller.c| Applies physics to players |
|
||||
|camera.c| Player cameras |
|
||||
|
||||
## Actors
|
||||
Actor related code resides in
|
||||
|file|desc|
|
||||
|---|---|
|
||||
|actors.c|Variety of [actors](actorsmenu.html), see link for specifics.|
|
||||
|actors_extended.c|Shells and bananas|
|
||||
|
||||
## Objects
|
||||
Object related code resides in
|
||||
|file|desc|
|
||||
|---|---|
|
||||
|code_80057C60.c|Objects|
|
||||
|code_80071F00.c|Objects|
|
||||
|code_80086E70.c|Objects|
|
||||
|
||||
Documentation of the specifics still in-progress. See [actors](actorsmenu.html) for more information.
|
||||
|
||||
## Courses
|
||||
Course related code resides in
|
||||
|file|desc|
|
||||
|---|---|
|
||||
|memory.c| Loads and extracts course data|
|
||||
|render_courses.c|Renders course content|
|
||||
|common_textures.inc.c|Content accessible to every course such as items and portraits|
|
||||
|
||||
### Course Folder
|
||||
|file|desc|
|
||||
|---|---|
|
||||
|courses/course_name/course_data.inc.c|Course data|
|
||||
|courses/course_name/course_vertices.inc.c|Course vertices (this + _displaylists.inc.c makes the course geography)|
|
||||
|courses/course_name/course_displaylists.inc.c|Course displaylists (these get compressed during compile)|
|
||||
|courses/course_name/course_offsets.inc.c|Textures used in the course|
|
||||
|
||||
## UI & Other 2D Screen data
|
||||
|file|desc|
|
||||
|---|---|
|
||||
|hud_renderer.c|ItemWindows|
|
||||
|
||||
## Engine
|
||||
|file|desc|
|
||||
|---|---|
|
||||
|collision.c| |
|
||||
|
||||
## Math
|
||||
Math related code resides in
|
||||
|file|desc|
|
||||
|---|---|
|
||||
|math_util.c| |
|
||||
|math_util_2.c| |
|
||||
|
||||
## Ending
|
||||
|file|desc|
|
||||
|---|---|
|
||||
|ceremony_and_credits.c|Camera rails for podium ceremony and credits|
|
||||
|podium_ceremony_actors.c|Fireworks and balloons for podium ceremony|
|
||||
|ceremony_data.inc.c|Trophies and podium models. Paths.|
|
||||
|credits.c|Credits text and UI positions|
|
||||
|
|
|
|||
|
|
@ -1,2 +1,27 @@
|
|||
\page surfacetypes Surface Types
|
||||
# Surface Types
|
||||
|
||||
Surfaces produce effects, driven on sounds, and other behaviour. Note that surface type is not generally used for out of bounds behaviour. As such, out of bounds areas may use any combination of surface types or flags.
|
||||
|
||||
| id | Name | Desc | Courses |
|
||||
|---|---|---|---|
|
||||
| 1 | Solid | Pavement, tunnel walls/floor | Koopa Troopa Beach, Rainbow Road |
|
||||
| 2 | Dirt | Several courses, edge of water | Royal Raceway |
|
||||
| 3 | Sand | Dirt track and oob beach sand | Koopa Troopa Beach |
|
||||
| 4 | Cement | | |
|
||||
| 5 | Snow | Ice cave interior | Frappe Snowland, Sherbet Land |
|
||||
| 6 | Bridge | Bridges and guardrails, castle bridge | Royal Raceway |
|
||||
| 7 | Dirt Off-road | | |
|
||||
| 8 | Grass | | |
|
||||
| 9 | Ice | | Sherbet Land |
|
||||
| 10 | Wet Sand | | Koopa Troopa Beach |
|
||||
| 11 | Snow Off-road | | |
|
||||
| 12 | Rock Walls | Also used for choco walls | Choco Mountain |
|
||||
| 13 | Dirt Off-road | | Kalimari Desert |
|
||||
| 14 | Track Ballast | The dirt used in railways | Kalimari Desert |
|
||||
| 15 | Cave | Cave interior | Jungle Parkway |
|
||||
| 16 | Rope Bridge | Rickety | Jungle Parkway |
|
||||
| 17 | Wood Bridge | Solid wood | |
|
||||
| 252 | Boost Ramp | Locks speed to ~60km/h | Jungle Parkway |
|
||||
| 253 | Out of Bounds | Lakitu activates on touch | Jungle Parkway |
|
||||
| 254 | Gravity Ramp | Boost ramp that locks speed with reduced gravity | Royal Raceway |
|
||||
| 255 | Walls/Ramps | Walls and ramps | Koopa Troopa Beach |
|
||||
|
|
|
|||
|
|
@ -1,7 +1,15 @@
|
|||
\page terminology Terminology
|
||||
#### Definitions
|
||||
* `Jump/Branch/Function` - Tells the cpu to execute instructions somewhere else and come back here when done.
|
||||
* `Hexadecimal` - A [numbering system](https://en.wikipedia.org/wiki/Hexadecimal) just like decimal (also called base-ten) or roman numerals. An easy method for programmers and computers to understand each other which groups/separates bytes of information in a readable format. Representing information as decimal results in an unreadable mess.
|
||||
* `Hexadecimal` - A [numbering system](https://en.wikipedia.org/wiki/Hexadecimal). Similar numbering sytems include decimal (also called base-ten) and roman numerals.
|
||||
* Easy method for programmers and computers to understand each other which groups/separates bytes of information in a readable format.
|
||||
* Representing computer numbers as decimal results in an unreadable mess.
|
||||
* `s32/word/int` - A max size for a number. Data represented as 32 bits or 4 bytes: `0x00000001`. It consists of eight digits.
|
||||
* `s16/half-word/short` - A number represented as 16 bits or 2 bytes: `0x0001`. It consists of four digits. Maximum value 65,535 (0xFFFF).
|
||||
* `s8/byte/char` - A number represented as 8 bits or 1 byte: `0x01`. It consists of two digits. Maximum value 255 (0xFF).
|
||||
* `s8/byte/char` - A number represented as 8 bits or 1 byte: `0x01`. It consists of two digits. Maximum value 255 (0xFF).
|
||||
* `unsigned` - A positive integer. 0, 1 to maximum value.
|
||||
* `signed` - A positive or negative integer. 0, -1 to -max, 1 to max.
|
||||
* Max value slightly lower than unsigned due to a bit being used to set whether negative or positive.
|
||||
* Google "Two's complement" for an indepth technical explanation.
|
||||
* `f32/float` - A positive or negative value containing a decimals such as `5.0f` or `5.1f` or `5.148282f`
|
||||
* `f64/double` - A positive or negative value of high-precision. Ex. `5.5784298538832` (many decimals).
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
Complete resources for learning about mk64 decomp
|
||||
|
||||
\htmlonly
|
||||
<br><br>
|
||||
<br>
|
||||
<style>
|
||||
.pagebutton {
|
||||
display: inline-block;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
\page boostramps Boostramps
|
||||
# Boostramps
|
||||
\page boostramps Boost Ramps
|
||||
# Boost Ramps
|
||||
|
||||
Boostramps use a surface-type and is part of the course geography.
|
||||
Boost ramps use a surface-type and is part of the course geography.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Topics discussing how to work with certain features.
|
||||
|
||||
\htmlonly
|
||||
<br><br>
|
||||
<br>
|
||||
<style>
|
||||
.pagebutton {
|
||||
display: inline-block;
|
||||
|
|
@ -87,9 +87,9 @@ p {
|
|||
<div class="pagelink">
|
||||
<div class="pageimg"><img width=320 src="buttonimage.png" /></div>
|
||||
<div class="content">
|
||||
<div class="pageheading">Boostramps</div>
|
||||
<div class="pageheading">Boost Ramps</div>
|
||||
<div class="pagedescription">
|
||||
<p>Steps for creating your own boostramps</p>
|
||||
<p>Steps for creating your own boost ramps</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue