Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions docs/contribute/contribute.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ We gladly accept contributions! If you're interested in helping with this projec

## What is needed?

To contribute to this project, you will need:
To contribute to this project, you will (at minimum) need:
- A dump of the GameCube USA version of Twilight Princess
- [Ghidra](https://github.com/NationalSecurityAgency/ghidra)
- [Ghidra](https://github.com/encounter/ghidra-ci/releases)
- Basic knowledge about using Git
- Basic knowledge about programming (preferrably in C++ / C)

Expand All @@ -24,7 +24,3 @@ A moderately powerful computer will also be beneficial, as building the project
:::caution Important note
You will have to **source your own dump of the game**. We **cannot** assist you in acquiring it.
:::

:::caution Windows users
The documentation here will assume you are using Linux (either native or through WSL). If you are on Windows, we strongly recommend setting up WSL and using it for this project. Native Windows is supported as well, but is not recommended.
:::
5 changes: 3 additions & 2 deletions docs/contribute/guidelines.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Coding Guidelines
description: Guidelines for writing code
sidebar_position: 2
sidebar_position: 3
---

This project aims to be as readable and easy-to-understand as is possible towards the average programmer. As such, it is important to us that the coding style is kept consistent and clean across the entire project.
Expand All @@ -16,7 +16,7 @@ Clang Format will take care of most style choices, however there are other styli

## General

- Lines should not be longer than 100 characters.
- Lines should not be longer than roughly 100 characters.
- Use 4 spaces to indent.
- Use spaces with operators and keywords:
- :heavy_check_mark: `if (x == 1 || x == 2)`
Expand All @@ -28,6 +28,7 @@ Clang Format will take care of most style choices, however there are other styli
- :heavy_check_mark: `if ((foo && bar) || (x && y))`
- :x: `if (foo && bar || x && y)`
<br /> The parenthesis here aren't necessary, but improve readability due to operator precedence not being immediately obvious.
- Use whitespace to separate blocks of code into more readable chunks.
- Declare variables close to their usage point when possible.
- Do not use `this->` with member variables unless it's absolutely necessary.

Expand Down
144 changes: 43 additions & 101 deletions docs/contribute/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,131 +6,73 @@ sidebar_position: 0

Follow these steps to set up the project.

## Set Up Dependencies
## Setting up dependencies
### Windows

The following tools will be needed for the project:
- Install [Python 3.10 or newer](https://www.python.org/downloads/) and add it to `%PATH%`
- Download [ninja](https://github.com/ninja-build/ninja/releases) and add it to `%PATH%`
- Quick install via pip: `pip install ninja`

* Python 3.10 or newer
* Build-essential tools
### macOS

If you are using a distribution under Linux or WSL2, you will also need to install either **Wine** or **[WiBo](https://github.com/decompals/wibo)**.
- Install [ninja](https://github.com/ninja-build/ninja/wiki/Pre-built-Ninja-packages):

You can install either WiBo or Wine but you should only install one of them. We recommend to install WiBo because it is faster and more lightweight.
```sh
brew install ninja
```

If you are on MacOS (only intel-based ones), only install:
- Install [wine-crossover](https://github.com/Gcenx/homebrew-wine):

* Wine (Install it with the MacOS step below)
```sh
brew install --cask --no-quarantine gcenx/wine/wine-crossover
```

Linux/WSL2:
```shell
sudo apt install build-essential python3
```
And if you chose to install Wine instead of WiBo:
```shell
sudo dpkg --add-architecture i386
```
```shell
sudo apt-get update
```
```shell
sudo apt-get install wine wine32
```
After OS upgrades, if macOS complains about `Wine Crossover.app` being unverified, you can unquarantine it using:

MacOS:
```shell
brew install python
```
```shell
xcode-select --install
```
```shell
brew cask install wine-stable
```sh
sudo xattr -rd com.apple.quarantine '/Applications/Wine Crossover.app'
```

## Setting Up The Repository
### Linux

1. Clone the repository and switch to it by running:
```shell
git clone https://github.com/zeldaret/tp.git && cd tp
```
- Install [ninja](https://github.com/ninja-build/ninja/wiki/Pre-built-Ninja-packages).
- For non-x86(_64) platforms: Install wine from your package manager.
- For x86(_64), [wibo](https://github.com/decompals/wibo), a minimal 32-bit Windows binary wrapper, will be automatically downloaded and used.

2. Place your copy of GameCube USA Twilight Princess in the root directory and call it `gz2e01.iso`

3. Install the necessary python modules with following command:
```shell
python3 -m pip install --user -r tools/requirements.txt
```

4. Setup the project by executing the following command:
```shell
./tp setup
```

5. Create the Expected directory (for diffing asm functions via diff.py):
```shell
./tp expected
```

## Building
### Building a playable ROM
To build a playable game, run:
```shell
make game
```
## Setting Up The Repository

:::caution Note
You can add the `-j#` argument where # is the amount of threads your system has in order to greatly speed up build times.
```shell
make game -j8
```
:::
- Clone the repository:

To make use of WiBo (if installed), append the environment variable like:
```shell
make game WINE=wibo
```
```sh
git clone https://github.com/zeldaret/tp.git
```

### Building the DOL
To build the DOL (main executable), simply run make:
```shell
make
```
- Copy your game disc image to `orig/GZ2E01`.
- Supported formats: ISO (GCM), RVZ, WIA, WBFS, CISO, NFS, GCZ, TGC.
- After the initial build, the disc image can be deleted to save space.

### Building the RELs
To build the RELs (Relocatable code), add the `rels` parameter:
```shell
make rels
```
- Configure:

### Extracting game assets
To extract the game assets (non-code files) from your provided ROM, add the `assets` parameter:
```sh
python configure.py
```

```shell
make assets
```
To use a version other than `GZ2E01` (USA), specify it with `--version`.
- Build:

### Cleanup
To delete only your built DOL, add the `clean` parameter:
```shell
make clean
```
```sh
ninja
```

To delete only the built RELs, add the `clean_rels` parameter:
```shell
make clean_rels
```
## Setting up Objdiff

To delete the built playable ROM, add the `clean_game` parameter:
Objdiff is the tool we use to compare our compiled code to the expected original code.

```shell
make clean_game
```
Download the latest release from [encounter/objdiff](https://github.com/encounter/objdiff). Under project settings, set `Project directory`. The configuration should be loaded automatically.

To delete your entire build, add the `clean_all` parameter:
Select an object from the left sidebar to begin diffing. Changes to the project will rebuild automatically: changes to source files, headers, `configure.py`, `splits.txt` or `symbols.txt`.

```shell
make clean_all
```
![](../../static/img/objdiff.png)

## Problems?

Expand Down
124 changes: 124 additions & 0 deletions docs/contribute/workflow.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
title: Workflow
description: General project workflow
sidebar_position: 2
---

Here we'll go over the general workflow for decompiling code and how you should be using the essential tools effectively. Note that this is just a general guide, you may choose to work however works best for you.

One extremely important point to drive home early on is that you should be **LOOKING AT THE DEBUG ROM!!!**
The debug rom (shield_chn_debug in ghidra) is special in that it was compiled without optimizations or inlining, which means it exposes much more info about how a function was originally written than the retail versions offer.

You should always be simultaneously looking at both the retail and debug versions in ghidra to get a proper idea of what the decompiled code should look like. If you are unsure of anything, please ask in the ZeldaRET discord for advice.

## Choosing a file
First off you'll want to pick a file (more accurately called a Translation Unit or TU) that you want to work on.

`d_a_obj_*.cpp` TUs tend to be smaller and easier so they're good choices when starting out, however you may pick anything that interests you.

You can check out our [GitHub Projects](https://github.com/zeldaret/tp/projects?query=is%3Aopen) to see what TUs have already been finished or are in progress to make sure you're not overlapping with anyone else

## Setting up classes/structs
After you pick a file to work on, you'll want to setup the necessary classes/structs as best as possible before diving into decompiling code. For actor TUs, this will usually mean setting up the primary actor-specific classes/structs.

This will generally consist of looking through all the functions that use a given class/struct within ghidra and figuring out what data types belong at which offset within the struct. Looking at class constructors (particularly within the debug rom) can give away many of the data types that belong in a class.

Here is a guide covering the basics of using ghidra to figure out data structures.
<iframe height="315" width="560" src="https://www.youtube.com/embed/fMQ_Thv93Ws" allowfullscreen="true"/>

## Decompiling functions
The process of decompiling functions most simply consists of looking at ghidra pseudocode for a function and translating it into actual compilable C++ code within the project. The ghidra pseudocode is often quite rough and may struggle to accurately represent what the assembly code is doing. You will need to manually cleanup these issues and decipher what the actual structure of the code should be.

Looking at the debug rom is crucial here to ensure you can cleanup the code as much as possible. In many instances the debug rom reveals information about the function that helps match the retail code that would be very difficult to figure out otherwise. Therefore it's most recommended to look at both the debug and retail versions of the function simulataneously to get the full picture.

There is an alternative decompiler [m2c](https://simonsoftware.se/other/mips_to_c.py) that in certain cases may offer better output than ghidra. However this decompiler is primarily suited for C code, so it's output quality may vary for our project. You can find the assembly code to paste into m2c in the `build/GZ2E01` folder.

Once you've finished attempting to decompile the function, you'll find the corresponding function in Objdiff and check whether your decompilation attempt matches. If it doesn't match, you'll select the function and try to fix the issues you see present.

Here is a basic introductory guide to getting started decompiling functions. It is slightly outdated as of October 2024, however most information still applies.
<iframe height="315" width="560" src="https://www.youtube.com/embed/0IPvRahaJTs" allowfullscreen="true"/>

## Cleanup
After finishing your function decompilation attempts, you'll want to cleanup the TU to remove unnecessary parts, ensure data and functions are in the correct order, and (optionally) name variables appropriately.

There's many parts of the TU that are not strictly necessary and were only there originally to help with building correctly. After successfully decompiling the file, these parts may be removed as they're unneeded anymore. Some examples of this are:

Externs:
```cpp
extern "C" void __ct__10fopAc_ac_cFv();
extern "C" void __dt__10fopAc_ac_cFv();
extern "C" u8 now__14mDoMtx_stack_c[48];
```

Force Active Pragmas:
```cpp
#pragma push
#pragma force_active on
...
#pragma pop
```

Stringbases:
```cpp
SECTION_DEAD static char const* const stringBase_80AB2120 = "";
SECTION_DEAD static char const* const stringBase_80AB2121 = "DEFAULT_GETITEM";
SECTION_DEAD static char const* const stringBase_80AB2131 = "NO_RESPONSE";
```

Vtables:
```cpp
SECTION_DATA extern void* __vt__11J3DTexNoAnm[3] = {
(void*)NULL /* RTTI */,
(void*)NULL,
(void*)calc__11J3DTexNoAnmCFPUs,
};
```

Literals:
```cpp
SECTION_RODATA static f32 const lit_4041 = 150.0f;
COMPILER_STRIP_GATE(0x80AB20AC, &lit_4041);

SECTION_DATA static void* lit_5334[13] = {
(void*)(((char*)cutHaveFavorToAsk__13daNpc_Pouya_cFi) + 0x454),
(void*)(((char*)cutHaveFavorToAsk__13daNpc_Pouya_cFi) + 0x454),
(void*)(((char*)cutHaveFavorToAsk__13daNpc_Pouya_cFi) + 0x554),
};

SECTION_DATA static void* lit_3818[3] = {
(void*)NULL,
(void*)0xFFFFFFFF,
(void*)cutHaveFavorToAsk__13daNpc_Pouya_cFi,
};
```

Many of these are automatically generated by the compiler when your code is built, therefore these can be removed. You will want to ensure that the order of data in the TU still matches after these changes.

Additionally, "weak functions" are also generated by the compiler and can be removed. Weak functions can generally be identified as small functions that are "out of place" in the TU you are working on, usually consisting of inline functions, constructors / destructors, and virtual functions.

```cpp
void daNpc_Pouya_c::CreateHeap() {
// NONMATCHING
}

// This is a weak function, generated by CreateHeap above
// J3DTevKColorAnm::~J3DTevKColorAnm() {
extern "C" void __dt__15J3DTevKColorAnmFv() {
// NONMATCHING
}
```

Like before, you will need to ensure that function order matches after these changes. Note that weak function ordering with this compiler is not entirely understood yet, so if you don't manage to fix it entirely that's okay.

Once the TU seems complete, you can try to switch it's configuration to `Matching` in configure.py.
```cpp
ActorRel(MatchingFor("GZ2E01"), "d_a_spinner"),
```
Run `ninja` again to ensure that everything builds OK. If the build fails, there may be more work to do first.

If all functions in a TU are matching but the only issues that remain are data ordering or weak function ordering issues, you may mark the configuration as `Equivalent` instead.
```cpp
ActorRel(Equivalent, "d_a_nbomb"), # weak func order
```

After this you are free to open a Pull Request to the main repo where we will review it ASAP.
Loading