mirror of
https://github.com/zeldaret/ph
synced 2026-05-27 16:13:04 -04:00
141 lines
5.5 KiB
Markdown
141 lines
5.5 KiB
Markdown
# Contribution guide
|
|
- [Project structure](#project-structure)
|
|
- [Decompiling a function](#decompiling-a-function)
|
|
- [Code style](#code-style)
|
|
- [Creating new `.c`/`.cpp` files](#creating-new-ccpp-files)
|
|
- [Non-matching functions](#non-matching-functions)
|
|
|
|
## Project structure
|
|
- `asm/`: Non-decompiled assembly code
|
|
- `ovXX/`: Code for overlay `XX`
|
|
- `*.s`: Source file in assembly
|
|
- `include/*.inc`: External symbols imported by respective source file
|
|
- `build/`: Build output
|
|
- `arm9_linker_script.lcf`: Linker command file for ARM9 program, specifies the order to put code and data into the ROM
|
|
- `arm9_objects.txt`: List of object files to pass to the linker
|
|
- `eur/`: Compiled/linked files
|
|
- `asm/`: Built assembly code
|
|
- `src/`: Built C/C++ code
|
|
- `overlays/`: Contains `.bin` and `.lz` files for each overlay
|
|
- `*.bin`: Linked code/data to compress or put in the ROM
|
|
- `*.lz`: Compressed code to put in the ROM
|
|
- `main.bin.xMAP`: Map file listing RAM addresses for all symbols
|
|
- `docs/`: Documentation about the game
|
|
- `include/`: Include files
|
|
- `ph_eur/`: Game assets, extracted from your own supplied ROM
|
|
- `assets/`: Unmodified assets
|
|
- `banner/`: Banner logo and text that shows on the DS home menu
|
|
- `arm7.bin`: Extracted ARM7 program
|
|
- `arm9_ovdata.bin`: Data about ARM9 overlays
|
|
- `src/`: Source C/C++ files
|
|
- `tools/`: Tools for this project
|
|
- `compress/`: Compresses code before it is put in the ROM
|
|
- `mwccarm/`: Compiler toolchain
|
|
- `rom/`: Extracts and builds ROMs
|
|
- `lcf.py`: Generates `arm9_linker_script.lcf`
|
|
- `patch_mwcc.py`: Patches bugs in the toolchain
|
|
- `requirements.txt`: Python libraries
|
|
- `setup.py`: Sets up the project
|
|
- `assets.txt`: The order of asset directories to put in the ROM
|
|
- `*.sha1`: SHA-1 digests of different versions of the game
|
|
|
|
## Decompiling a function
|
|
WIP
|
|
|
|
## Creating new `.c`/`.cpp` files
|
|
New source files must be added to the LCF (Linker Command File). This is done via `lcf.py`, which generates the LCF when
|
|
building.
|
|
|
|
In `lcf.py`, you will see a list of overlays near the top. Each overlay then has a list of source files ending in `.s`, `.c` or
|
|
`.cpp`. Those source files, when compiled, are appended to the ROM in the order that they appear in the list.
|
|
|
|
So, to create a new source file, you put the path to the source file in the correct overlay so that it appears in the correct
|
|
order in relation to other source files.
|
|
|
|
## Code style
|
|
The code style is not strict, but please try to mimic the existing style as much as possible.
|
|
|
|
If it's impossible to match a function while following the code style, then it's OK to not follow it. But do let us know when
|
|
this happens so we may amend the code style.
|
|
|
|
Below is an example of the code style in this project. If something is unclear, look at existing code. If the existing code is
|
|
insufficient, then you may decide the code style in that situation.
|
|
```cpp
|
|
// Space before pointer asterisk * and reference ampersand &
|
|
s32 MyClass::MyMethod(MyStruct *myStruct, s32 &anInteger) {
|
|
// Opening brace { on the same line
|
|
// Space after `if`, `while`, `for` and `switch`
|
|
if (myStruct->isCool) {
|
|
// Access member fields using `this`
|
|
// Class member fields are prefixed with "m"
|
|
this->mInteger = anInteger;
|
|
}
|
|
// No space before asterisk * in pointer casts
|
|
// Space after cast operator
|
|
this->mPointer = (u32*) &anInteger;
|
|
|
|
// Prefer pre-increment ++i
|
|
// Use s32, s16, s8, etc. instead of int, short, char
|
|
for (s32 i = 0; i < 10; ++i) {
|
|
// Use `char` instead of s8 to indicate actual characters
|
|
char ch = 'A' + i * 2;
|
|
this->mString[i] = ch;
|
|
}
|
|
|
|
// Put long conditions on new line
|
|
if (
|
|
// Add clarifying parentheses for bool operators
|
|
(this->mInteger > 10 && this->mPointer != NULL) ||
|
|
(this->mInteger < 5)
|
|
) {
|
|
// Add clarifying parentheses for bitwise operators
|
|
this->mBool = ((this->mInteger >> 5) & 1) != 0;
|
|
}
|
|
|
|
do {
|
|
// Call member functions using `this`
|
|
this->DoStuff();
|
|
// In do-while loops, `while` on same line as closing brace }
|
|
} while (this->CanDoStuff());
|
|
|
|
switch (this->mInteger) {
|
|
// Indent `case`
|
|
// If possible, put braces after `case`
|
|
case 8: {
|
|
return *this->mPointer;
|
|
// If possible, put `break` after closing brace }
|
|
} break;
|
|
}
|
|
|
|
// No parentheses around return value
|
|
return this->mInteger;
|
|
}
|
|
```
|
|
|
|
## Non-matching functions
|
|
This project supports non-matching functions, and you can build them by using `make NONMATCHING=1`.
|
|
|
|
Non-matching functions must be written as follows:
|
|
```cpp
|
|
#include "global.hpp"
|
|
|
|
NONMATCH void MyFunction() {
|
|
#ifndef NONMATCHING
|
|
#include "../asm/path/to/asm.inc"
|
|
#else
|
|
// non-matching code here
|
|
#endif
|
|
}
|
|
```
|
|
|
|
When building normally, the `NONMATCH` macro will mark `MyFunction` as an assembly function, and the `NONMATCHING` macro will
|
|
not be defined so that the `asm.inc` file will be included.
|
|
|
|
Conversely, when building in non-matching mode, `MyFunction` will be a regular C/C++ function, and the non-matching code will
|
|
be inserted instead of `asm.inc`.
|
|
|
|
When contributing non-matching functions to this project, please build in both modes and fix any build errors you may get.
|
|
Delete the `.o` file between building in each mode so that the `Makefile` runs the compiler both times.
|
|
|
|
> [!NOTE] The inline assembler does not function the same as the standalone assembler. [See differences here.](inline_assembler.md#differences-from-standalone-assembler)
|