diff --git a/INSTALL.md b/INSTALL.md index bea8eff4..816f3278 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -12,13 +12,12 @@ Contents: 1. Use one of these platforms: - Windows (MSYS) - Linux via WSL - - Recommended for Windows users - Linux 2. Install the following: - Python 3.11+ and pip - GCC 9+ - Make - - **On Linux/WSL**: Wine + - **On Linux/WSL**: Wine/Wibo 3. Install the Python dependencies: ```shell python -m pip install -r tools/requirements.txt @@ -28,6 +27,9 @@ python -m pip install -r tools/requirements.txt python tools/setup.py ``` +> [!NOTE] +> For Linux users: If you plan to use Wibo instead of Wine, run make with `make WINE= ...`. + ## Build the ROM This repository does not include any of the game's assets, and you will need an original decrypted base ROM. diff --git a/Makefile b/Makefile index 0dc3c52a..bf37505a 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ endif ifeq ($(OS),Windows_NT) WINE := else - WINE := wine + WINE ?= wine PYTHON ?= python3.11 endif @@ -27,11 +27,13 @@ ASSETS_TXT := assets.txt ASM_FILES := $(shell find asm -name *.s) CXX_FILES := $(shell find src -name *.cpp) $(shell find libs -name *.cpp) -C_FILES := $(shell find src -name *.c) $(shell find libs -name *.c) -ASM_OBJS = $(ASM_FILES:%.s=$(TARGET_DIR)/%.s.o) -ASM_INCS = $(ASM_FILES:%.s=%.inc) -CXX_OBJS = $(CXX_FILES:%.cpp=$(TARGET_DIR)/%.cpp.o) -C_OBJS = $(C_FILES:%.c=$(TARGET_DIR)/%.c.o) +C_FILES := $(shell find src -name *.c) $(shell find libs -name *.c) +ASM_OBJS = $(ASM_FILES:%.s=$(TARGET_DIR)/%.s.o) +ASM_INCS = $(ASM_FILES:%.s=%.inc) +CXX_OBJS = $(CXX_FILES:%.cpp=$(TARGET_DIR)/%.cpp.o) +C_OBJS = $(C_FILES:%.c=$(TARGET_DIR)/%.c.o) +CXX_CTXS = $(CXX_FILES:%.cpp=$(TARGET_DIR)/%.cpp.ctx) +C_CTXS = $(C_FILES:%.c=$(TARGET_DIR)/%.c.ctx) OV_BINS := $(wildcard $(TARGET_DIR)/overlays/*.bin) OV_LZS = $(OV_BINS:%.bin=%.lz) @@ -124,16 +126,20 @@ $(ASM_OBJS): $(TARGET_DIR)/%.o: % mkdir -p $(dir $@) LM_LICENSE_FILE=$(MW_LICENSE) $(WINE) $(MW_ASM) $(ASM_FLAGS) $< -o $@ -$(CXX_OBJS): $(TARGET_DIR)/%.o: % +$(CXX_OBJS): $(TARGET_DIR)/%.o: % $(TARGET_DIR)/%.ctx mkdir -p $(dir $@) LM_LICENSE_FILE=$(MW_LICENSE) $(WINE) $(MW_CC) $(CC_FLAGS) $(CXX_FLAGS) $< -o $@ $(TOOLS_DIR)/elf/elfkill -s $< -e $@ -$(C_OBJS): $(TARGET_DIR)/%.o: % +$(C_OBJS): $(TARGET_DIR)/%.o: % $(TARGET_DIR)/%.ctx mkdir -p $(dir $@) LM_LICENSE_FILE=$(MW_LICENSE) $(WINE) $(MW_CC) $(CC_FLAGS) $(C_FLAGS) $< -o $@ $(TOOLS_DIR)/elf/elfkill -s $< -e $@ +$(CXX_CTXS) $(C_CTXS): $(TARGET_DIR)/%.ctx: % + mkdir -p $(dir $@) + $(PYTHON) $(TOOLS_DIR)/m2ctx.py -f $@ $< + .PHONY: link link: lcf $(ASM_OBJS) $(CXX_OBJS) $(C_OBJS) cd $(TARGET_DIR) && LM_LICENSE_FILE=$(MW_LICENSE) $(WINE) $(MW_LD) $(LD_FLAGS) $(LCF_FILE) @$(OBJS_FILE) diff --git a/docs/build_system.md b/docs/build_system.md index ee46340f..a81d6e4e 100644 --- a/docs/build_system.md +++ b/docs/build_system.md @@ -56,7 +56,7 @@ When the code is linked, all code of the same section will be written adjacent t ## Compiling code This game was written in C++, so most of the code we decompile will be in this programming language. In C++, we typically don't have to express which section we want the code to be written to. Instead, the compiler determines the section automatically. -Here are a few examples of how to +Here are a few examples of how to generate code for different section types. - `.text` - Functions and member functions (aka methods) diff --git a/docs/decompiling.md b/docs/decompiling.md index 3ff23f2b..caf723de 100644 --- a/docs/decompiling.md +++ b/docs/decompiling.md @@ -20,43 +20,55 @@ again. Remember to make a pull request of any notable progress you made on the s [non-matching functions](/CONTRIBUTING.md#non-matching-functions). ## Decompiling a source file -It can be tricky to fully decompile an assembly file into a C/C++ source file, so here's some advice to make it easier: -- C/C++ code is built before assembly code - - This means you can take one function from the top of your assembly file, decompile it, and append it to the bottom of - your C/C++ file. -- Build the ROM often - - We recommend building every time you decompile a function. - - This is because functions can sometimes match in decomp.me, but not when building. - - If your ROM doesn't match, it's easier to know which function is wrong if it's the only function added since the last - successful build. +We use the object diffing tool [`objdiff`](https://github.com/encounter/objdiff) to track differences between C++ and assembly +code. +1. [Download the latest release.](https://github.com/encounter/objdiff/releases/latest) +1. Run `python tools/objdiff.py ` to generate `objdiff.json` in the project root. +1. In `objdiff`, set the project directory to the root of this project. This will load `objdiff.json`. +1. Select your source file in the left sidebar: +![List of objects in objdiff](images/objdiff_objects.png) +5. See the list of functions and data to decompile: +![List of symbols in objdiff](images/objdiff_symbols.png) + +> [!NOTE] +> If a source file is missing in `objdiff`, or `objdiff` fails to build a file, first rerun `objdiff.py` to update +> `objdiff.json`. If the problem persists, feel free to ask for help. ## Decompiling a function -Say you've found a function you want to decompile. Here are the steps we recommend for decompiling it: -1. Visit [decomp.me](https://decomp.me/) and start decomping. -1. Under the platforms, select "Nintendo DS". -1. Select compiler preset "Phantom Hourglass". -1. Copy and paste the target assembly for your function, including the `func_start` and `func_end` macros, and the pool -constants. For example: -```arm - .global func_ov09_0211bf48 - thumb_func_start func_ov09_0211bf48 -func_ov09_0211bf48: ; 0x0211bf48 - ldr r0, _0211bf50 ; =data_ov09_0211f59c - ldrb r0, [r0] - bx lr - nop - thumb_func_end func_ov09_0211bf48 -_0211bf50: .word data_ov09_0211f59c +Once you've opened a source file in `objdiff`, you can choose to decompile the functions in any order. We recommend starting +with a small function if you're unfamiliar with decompilation. Here's an example: + +![Function in objdiff](images/objdiff_function.png) + +As a starting point, we look at the decompiler output in Ghidra. You can request access to our shared Ghidra project [in this section](#the-ghidra-project). + +![Decompiler in Ghidra](images/ghidra_decomp.png) + +Looking at this output, we might try writing something like this: +```cpp +ARM bool Actor::SetVelocity(Vec3p *vel) { + if (mUnk_11b) { + mVel = *vel; + mUnk_11b = false; + return true; + } + return false; +} ``` -5. Run `m2ctx.py include/MyHeader.hpp -c` to generate a context and put it in your clipboard. - - If no suitable header file exists, make a new one and put any structs and types you need in there. -1. Paste the context into decomp.me, and create the scratch. -1. Decompile the function and try to get a 100% match. - - There's no ARM decompiler in decomp.me yet, but Ghidra does the job quite well. See [the Ghidra section](#the-ghidra-project) - for more info. - - If you're unable to get a 100% match, share your decomp.me scratch with other contributors and they may assist you. - - In the worst case, you can also contribute [non-matching functions](/CONTRIBUTING.md#non-matching-functions) to this - project. + +Now we can go back to `objdiff` and look at the result: + +![Matching function in objdiff](images/objdiff_match.png) + +Success! Note that this was a simple example and that you'll sometimes get stuck on a function. In that case, try the +following: +- Decompile a different function and come back later. +- Export to [decomp.me](https://decomp.me/): + 1. Press the `decomp.me` button in `objdiff`. + 1. Once you're sent to `decomp.me`, go to "Options" and change the preset to "Phantom Hourglass". + 1. Paste your code into the "Source code" tab. + 1. Share the link with us! +- In the worst case, add the function as a [non-matching function](/CONTRIBUTING.md#non-matching-functions). ## Decompiling `.init` functions > [!NOTE] diff --git a/docs/images/ghidra_decomp.png b/docs/images/ghidra_decomp.png new file mode 100644 index 00000000..d54ff6ab Binary files /dev/null and b/docs/images/ghidra_decomp.png differ diff --git a/docs/images/objdiff_function.png b/docs/images/objdiff_function.png new file mode 100644 index 00000000..34e8a164 Binary files /dev/null and b/docs/images/objdiff_function.png differ diff --git a/docs/images/objdiff_match.png b/docs/images/objdiff_match.png new file mode 100644 index 00000000..a43726b7 Binary files /dev/null and b/docs/images/objdiff_match.png differ diff --git a/docs/images/objdiff_objects.png b/docs/images/objdiff_objects.png new file mode 100644 index 00000000..0bde5aaa Binary files /dev/null and b/docs/images/objdiff_objects.png differ diff --git a/docs/images/objdiff_symbols.png b/docs/images/objdiff_symbols.png new file mode 100644 index 00000000..d1af868b Binary files /dev/null and b/docs/images/objdiff_symbols.png differ diff --git a/docs/inline_assembler.md b/docs/inline_assembler.md index 0ef8d669..72339c4e 100644 --- a/docs/inline_assembler.md +++ b/docs/inline_assembler.md @@ -21,7 +21,7 @@ dcd 0x1234 #### `ldconst`: Loads a literal 32-bit value ```asm -ldconst 0x1234 +ldconst r0, 0x1234 bx lr ``` This code is equivalent to the above example using `dcd`. diff --git a/include/Actor/ActorType.hpp b/include/Actor/ActorType.hpp index 7e9e777b..06fd3b59 100644 --- a/include/Actor/ActorType.hpp +++ b/include/Actor/ActorType.hpp @@ -140,6 +140,7 @@ struct ActorType { /* 10 */ ActorType *next; /* 14 */ + inline ActorType() {} ActorType(ActorTypeId id, ActorCreateFunc create, unk32 (*unk_08)()); ~ActorType(); unk32 func_0203e7c8(); diff --git a/include/Player/LinkStateRoll.hpp b/include/Player/LinkStateRoll.hpp index 9ff28899..52b42b43 100644 --- a/include/Player/LinkStateRoll.hpp +++ b/include/Player/LinkStateRoll.hpp @@ -42,4 +42,5 @@ public: void func_ov00_020aee58(s16 param1, u16 param2); void func_ov00_020aee84(); + bool func_ov00_020aeeac(); }; diff --git a/src/00_Core/Actor/ActorManager.cpp b/src/00_Core/Actor/ActorManager.cpp index 613f5f42..472eede2 100644 --- a/src/00_Core/Actor/ActorManager.cpp +++ b/src/00_Core/Actor/ActorManager.cpp @@ -1,14 +1,12 @@ #include "Actor/ActorManager.hpp" -#ifdef STUBS - void ActorManager::DeleteActor(u32 index, bool param2) {} void ActorManager::func_ov00_020c3484(ActorRef *ref, Actor *actor, unk32 param3) {} void ActorManager::Actor_vfunc_10(u32 param1) {} Actor* ActorManager::FindActorById(u32 id) {} Actor* ActorManager::GetActor(ActorRef *ref) {} bool FilterActor::Filter(Actor *actor) {} -s32 ActorManager::FilterActors(ActorFilterBase *filter, ActorList *filteredActors) {} +s32 ActorManager::FilterActors(FilterActorBase *filter, ActorList *filteredActors) {} void ActorManager::FindActorByType(ActorRef *ref, ActorManager *manager, ActorTypeId type) {} void ActorManager::FindNearestActorOfType(ActorRef *ref, ActorManager *manager, ActorTypeId type, Vec3p *pos) {} bool ActorManager::func_ov00_020c398c(u32 index) {} @@ -20,4 +18,3 @@ void ActorManager::func_ov00_020c3ce8(unk32 param1, unk32 param2) {} void ActorManager::Actor_vfunc_28() {} bool ActorManager::ActorTypeIsOneOf(u32 type, ActorTypeId *types) {} -#endif diff --git a/src/00_Core/Item/Item.cpp b/src/00_Core/Item/Item.cpp index 522dd51d..817d86db 100644 --- a/src/00_Core/Item/Item.cpp +++ b/src/00_Core/Item/Item.cpp @@ -1,8 +1,4 @@ #include "Item/Item.hpp" -#ifdef STUBS - bool Item::func_ov00_020ad020(ItemId item) {} bool Item::func_ov00_020ad068(ItemId item) {} - -#endif diff --git a/src/00_Core/Map/Course.cpp b/src/00_Core/Map/Course.cpp index 560169e8..316b05ee 100644 --- a/src/00_Core/Map/Course.cpp +++ b/src/00_Core/Map/Course.cpp @@ -1,7 +1,5 @@ #include "Map/Course.hpp" -#ifdef STUBS - void Course::GetDungeonProgress(CourseProgress *param_2) {} void Course::func_ov00_0207ca28(s32 param_2, unk32 param_3, unk32 param_4) {} char* Course::SetCourseName(char *src) {} @@ -51,5 +49,3 @@ void Course::SetMapDataFlag4(unk32 param_2, unk32 param_3) {} bool Course::GetMapDataFlag4(unk32 param_2) {} MapData* Course::FindMapData(u32 map) {} MapData* Course::FindCurrentMapData() {} - -#endif diff --git a/src/00_Core/Map/MapBase.cpp b/src/00_Core/Map/MapBase.cpp index 5a5ed636..1afc8c29 100644 --- a/src/00_Core/Map/MapBase.cpp +++ b/src/00_Core/Map/MapBase.cpp @@ -1,8 +1,6 @@ #include "Map/MapBase.hpp" #include "Map/MapManager.hpp" -#ifdef STUBS - MapBase::~MapBase() {} MapBase_Unk_180::~MapBase_Unk_180() {} void MapBase::SetBounds(unk32 map, unk32 course) {} @@ -112,5 +110,3 @@ unk32 TriggerBase::vfunc_10() {} void MapBase::func_ov00_02080de4() {} unk8 MapBase::func_ov00_02080de8(unk32 param_2) {} void MapBase::func_ov00_02080edc() {} - -#endif diff --git a/src/00_Core/Map/MapManager.cpp b/src/00_Core/Map/MapManager.cpp index 61dd5564..6305418e 100644 --- a/src/00_Core/Map/MapManager.cpp +++ b/src/00_Core/Map/MapManager.cpp @@ -1,7 +1,5 @@ #include "Map/MapManager.hpp" -#ifdef STUBS - void MapManager::func_ov00_020820ec(unk32 *param_2) {} void MapManager::func_ov00_020820fc(s32 param_2, unk32 param_3, unk32 param_4) {} unk8 MapManager::func_ov00_0208210c(unk32 param_2, unk32 param_3) {} @@ -200,5 +198,3 @@ unk8 MapManager::func_ov00_02085c60(unk32 param_2, unk32 param_3, unk32 param_4, unk8 MapManager::func_ov00_02086044(unk32 param_2, unk32 param_3, unk32 param_4) {} bool MapManager::func_ov00_02086284(s32 *param_2, Vec3p *param_3, Vec3p *param_4, s32 param_5, u16 param_6, Vec3p *param_7, Vec3p *param_8) {} bool MapManager::func_ov00_02086a84(s32 *param_2, Vec3p *param_3, Vec3p *param_4, s32 param_5, s32 param_6, unk32 param_7, Vec3p *param_8, Vec3p *param_9) {} - -#endif diff --git a/src/00_Core/Player/LinkStateBase.cpp b/src/00_Core/Player/LinkStateBase.cpp index 482a8371..abe7bd34 100644 --- a/src/00_Core/Player/LinkStateBase.cpp +++ b/src/00_Core/Player/LinkStateBase.cpp @@ -1,7 +1,5 @@ #include "Player/LinkStateBase.hpp" -#ifdef STUBS - void LinkStateBase::vfunc_00() {} void LinkStateBase::OnStateEnter() {} void LinkStateBase::OnStateLeave(s32 param1) {} @@ -85,5 +83,3 @@ unk32 LinkStateBase::Get_PlayerControlData_Unk120() {} s32 LinkStateBase::Get_PlayerLinkBase_Unk38() {} DebugHierarchy* LinkStateBase::GetDebugHierarchy0() {} DebugHierarchy* LinkStateBase::GetDebugHierarchy1() {} - -#endif diff --git a/src/00_Core/Player/LinkStateDamage.cpp b/src/00_Core/Player/LinkStateDamage.cpp index 84674461..c544b154 100644 --- a/src/00_Core/Player/LinkStateDamage.cpp +++ b/src/00_Core/Player/LinkStateDamage.cpp @@ -1,7 +1,5 @@ #include "Player/LinkStateDamage.hpp" -#ifdef STUBS - void LinkStateDamage::vfunc_00() {} void LinkStateDamage::CreateDebugHierarchy() {} void LinkStateDamage::OnStateEnter() {} @@ -16,5 +14,3 @@ bool LinkStateDamage::vfunc_24(s32 param1) {} bool LinkStateDamage::vfunc_20(s32 param1) {} void LinkStateDamage::func_ov00_020acfe8(bool param1) {} LinkStateId LinkStateDamage::GetId() {} - -#endif diff --git a/src/00_Core/Player/LinkStateFollow.cpp b/src/00_Core/Player/LinkStateFollow.cpp index 54e87938..69d173dd 100644 --- a/src/00_Core/Player/LinkStateFollow.cpp +++ b/src/00_Core/Player/LinkStateFollow.cpp @@ -1,7 +1,5 @@ #include "Player/LinkStateFollow.hpp" -#ifdef STUBS - void LinkStateFollow::vfunc_00() {} LinkStateId LinkStateFollow::GetId() {} void LinkStateFollow::MoveTowardTarget() {} @@ -12,5 +10,3 @@ LinkStateCutscene* LinkStateFollow::GetLinkStateCutscene() {} bool LinkStateFollow::vfunc_34(Vec3p *param1) {} bool LinkStateFollow::func_ov00_020a9180(Vec3p *param1) {} bool LinkStateFollow::func_ov00_020a9210(Vec3p *param1, Actor *param2) {} - -#endif diff --git a/src/00_Core/Player/LinkStateInteract.cpp b/src/00_Core/Player/LinkStateInteract.cpp index a3a7ddca..6cbda713 100644 --- a/src/00_Core/Player/LinkStateInteract.cpp +++ b/src/00_Core/Player/LinkStateInteract.cpp @@ -1,7 +1,5 @@ #include "Player/LinkStateInteract.hpp" -#ifdef STUBS - void LinkStateInteract::vfunc_00() {} LinkStateId LinkStateInteract::GetId() {} void LinkStateInteract::CreateDebugHierarchy() {} @@ -30,5 +28,3 @@ void LinkStateInteract::func_ov00_020abbdc(ActorRef *ref) {} void LinkStateInteract::func_ov00_020abc18(ActorRef *ref) {} bool LinkStateInteract::func_ov00_020abc40() {} bool LinkStateInteract::func_ov00_020abc78(ActorRef *ref) {} - -#endif diff --git a/src/00_Core/Player/LinkStateItem.cpp b/src/00_Core/Player/LinkStateItem.cpp index 1faf16ab..eaf3c8b6 100644 --- a/src/00_Core/Player/LinkStateItem.cpp +++ b/src/00_Core/Player/LinkStateItem.cpp @@ -1,7 +1,5 @@ #include "Player/LinkStateItem.hpp" -#ifdef STUBS - void LinkStateItem::vfunc_00() {} LinkStateId LinkStateItem::GetId() {} s32 LinkStateItem::IsHammerEquipped() {} @@ -10,5 +8,3 @@ EquipBombchu* LinkStateItem::GetEquipBombchu() {} LinkStateMove* LinkStateItem::GetLinkStateMove() {} bool LinkStateItem::func_ov00_020abf70() {} bool LinkStateItem::vfunc_28() {} - -#endif diff --git a/src/00_Core/Player/LinkStateMove.cpp b/src/00_Core/Player/LinkStateMove.cpp index 586a331e..918a92fe 100644 --- a/src/00_Core/Player/LinkStateMove.cpp +++ b/src/00_Core/Player/LinkStateMove.cpp @@ -1,7 +1,5 @@ #include "Player/LinkStateMove.hpp" -#ifdef STUBS - void LinkStateMove::vfunc_00() {} LinkStateId LinkStateMove::GetId() {} void LinkStateMove::CreateDebugHierarchy() {} @@ -10,5 +8,3 @@ void LinkStateMove::OnStateLeave(s32 param1) {} bool LinkStateMove::vfunc_24(s32 param1) {} bool LinkStateMove::func_ov00_020a8f2c() {} bool LinkStateMove::func_ov00_020a8f4c() {} - -#endif diff --git a/src/00_Core/Player/LinkStateRoll.cpp b/src/00_Core/Player/LinkStateRoll.cpp index d6a93463..91044e21 100644 --- a/src/00_Core/Player/LinkStateRoll.cpp +++ b/src/00_Core/Player/LinkStateRoll.cpp @@ -1,7 +1,5 @@ #include "Player/LinkStateRoll.hpp" -#ifdef STUBS - void LinkStateRoll::vfunc_00() {} LinkStateId LinkStateRoll::GetId() {} void LinkStateRoll::CreateDebugHierarchy() {} @@ -12,5 +10,3 @@ bool LinkStateRoll::vfunc_24(s32 param1) {} void LinkStateRoll::func_ov00_020aee58(s16 param1, u16 param2) {} void LinkStateRoll::func_ov00_020aee84() {} bool LinkStateRoll::func_ov00_020aeeac() {} - -#endif diff --git a/src/00_Core/Player/PlayerBase.cpp b/src/00_Core/Player/PlayerBase.cpp index dfdb4eb5..fc5c92fb 100644 --- a/src/00_Core/Player/PlayerBase.cpp +++ b/src/00_Core/Player/PlayerBase.cpp @@ -1,7 +1,5 @@ #include "Player/PlayerLinkBase.hpp" -#ifdef STUBS - bool PlayerBase::vfunc_04() {} ItemFlag PlayerBase::GetEquipId() {} bool PlayerBase::CanMove() {} @@ -20,5 +18,3 @@ void PlayerBase::AddHealth(s16 amount) {} bool PlayerBase::Teleport(Vec3p *pos, s16 angle, unk32 param3, bool param4, bool param5) {} bool PlayerBase::TeleportToEntrance(unk32 entranceId, bool param2) {} bool PlayerBase::TeleportToLastEntrance(bool param1) {} - -#endif diff --git a/src/00_Core/Player/PlayerControl.cpp b/src/00_Core/Player/PlayerControl.cpp index 48c52e7a..f51d0a89 100644 --- a/src/00_Core/Player/PlayerControl.cpp +++ b/src/00_Core/Player/PlayerControl.cpp @@ -1,7 +1,5 @@ #include "Player/PlayerControl.hpp" -#ifdef STUBS - bool PlayerControl::func_ov00_020aeeac() {} void PlayerControl::func_ov00_020aeef8() {} void PlayerControl::func_ov00_020aef30() {} @@ -52,5 +50,3 @@ bool PlayerControl::IsNotTouching() {} bool PlayerControl::IsTouchingFast() {} bool PlayerControl::IsTappedNow() {} bool PlayerControl::func_ov00_020b13c4() {} - -#endif diff --git a/src/00_Core/Player/TouchControl.cpp b/src/00_Core/Player/TouchControl.cpp index df8bbfe0..5cae75a5 100644 --- a/src/00_Core/Player/TouchControl.cpp +++ b/src/00_Core/Player/TouchControl.cpp @@ -1,7 +1,5 @@ #include "Player/TouchControl.hpp" -#ifdef STUBS - TouchControl::TouchControl() {} void TouchControl::IncreaseSpeed(s16 increase) {} void TouchControl::UpdateFlags(u16 speed) {} @@ -11,5 +9,3 @@ bool TouchControl::func_ov00_0207aeac() {} void TouchControl::UpdateConditionally(TouchState *state, u16 speed) {} void TouchControl::func_ov00_0207af38(u16 speed, bool param2) {} TouchControl::~TouchControl() {} - -#endif diff --git a/src/00_Core/Player/TouchGesture.cpp b/src/00_Core/Player/TouchGesture.cpp index 83879415..027e3e0a 100644 --- a/src/00_Core/Player/TouchGesture.cpp +++ b/src/00_Core/Player/TouchGesture.cpp @@ -1,7 +1,5 @@ #include "Player/TouchGesture.hpp" -#ifdef STUBS - TouchGesture::TouchGesture() {} void TouchGesture::ResetTouchHistory() {} void TouchGesture::Update(void *param1) {} @@ -9,5 +7,3 @@ TouchGesture::~TouchGesture() {} void TouchGestureBase::ResetTouchHistory() {} TouchGestureBase::~TouchGestureBase() {} - -#endif STUBS diff --git a/src/00_Core/Save/AdventureFlags.cpp b/src/00_Core/Save/AdventureFlags.cpp index dd05dff6..14f377c1 100644 --- a/src/00_Core/Save/AdventureFlags.cpp +++ b/src/00_Core/Save/AdventureFlags.cpp @@ -1,7 +1,5 @@ #include "Save/AdventureFlags.hpp" -#ifdef STUBS - bool AdventureFlags::Exists() {} void AdventureFlags::CopyTo(unk32 *flags) {} void AdventureFlags::func_ov00_02097674() {} @@ -50,5 +48,3 @@ bool AdventureFlags::func_ov00_0209809c() {} bool AdventureFlags::func_ov00_020980ac() {} void AdventureFlags::func_ov00_020980bc(s32 param1) {} void AdventureFlags::func_ov00_020980d0() {} - -#endif diff --git a/src/14_Land/Actor/ActorRupee.cpp b/src/14_Land/Actor/ActorRupee.cpp index 20d98de4..5288f3bd 100644 --- a/src/14_Land/Actor/ActorRupee.cpp +++ b/src/14_Land/Actor/ActorRupee.cpp @@ -1,8 +1,5 @@ #include "Actor/ActorRupee.hpp" -#ifdef STUBS - -Resource ActorRupee::gResource; ActorType ActorRupee::gType; ActorRupee* ActorRupee::Create() {} @@ -21,5 +18,3 @@ void ActorRupee::func_ov14_0213b5f4(RupeeId id, unk32 param2, Vec3p *param3, boo void ActorRupee::func_ov14_0213b6a4(RupeeId id, void *param2) {} bool ActorRupee::func_ov14_0213b70c(RupeeId id) {} ActorRupee::~ActorRupee() {} - -#endif diff --git a/tools/lcf.py b/tools/lcf.py index a352fadb..7a37598e 100644 --- a/tools/lcf.py +++ b/tools/lcf.py @@ -33,63 +33,45 @@ DTCM_OBJECTS = [ ov00 = Overlay(name='ov00', after='ARM9', objects=[ 'asm/ov00/ov00_020773c0.s', - 'src/00_Core/Player/TouchControl.cpp', 'asm/ov00/Player/TouchControl.s', 'asm/ov00/ov00_0207afa0.s', 'asm/ov00/Map/Course.s', - 'src/00_Core/Map/Course.cpp', 'asm/ov00/Map/MapBase.s', - 'src/00_Core/Map/MapBase.cpp', 'asm/ov00/ov00_0207da38.s', 'asm/ov00/Map/MapManager.s', - 'src/00_Core/Map/MapManager.cpp', 'asm/ov00/ov00_02086cd0.s', - 'src/00_Core/Save/AdventureFlags.cpp', 'asm/ov00/Save/AdventureFlags.s', 'asm/ov00/ov00_020980f4.s', - 'src/00_Core/Player/PlayerBase.cpp', 'asm/ov00/Player/PlayerBase.s', - 'src/00_Core/Player/LinkStateBase.cpp', 'asm/ov00/Player/LinkStateBase.s', - 'src/00_Core/Player/LinkStateMove.cpp', 'asm/ov00/Player/LinkStateMove.s', - 'src/00_Core/Player/LinkStateFollow.cpp', 'asm/ov00/Player/LinkStateFollow.s', - 'src/00_Core/Player/TouchGesture.cpp', 'asm/ov00/Player/TouchGesture.s', 'asm/ov00/ov00_020a8e04.s', - 'src/00_Core/Player/LinkStateInteract.cpp', 'asm/ov00/Player/LinkStateInteract.s', - 'src/00_Core/Player/LinkStateItem.cpp', 'asm/ov00/Player/LinkStateItem.s', - 'src/00_Core/Player/LinkStateDamage.cpp', 'asm/ov00/Player/LinkStateDamage.s', - 'src/00_Core/Item/Item.cpp', 'asm/ov00/Item/Item.s', 'src/00_Core/Item/ItemManager.cpp', - 'src/00_Core/Player/LinkStateRoll.cpp', 'asm/ov00/Player/LinkStateRoll.s', - 'src/00_Core/Player/PlayerControl.cpp', 'asm/ov00/Player/PlayerControl.s', 'asm/ov00/ov00_020b1498.s', - # 'src/00_Core/Actor/Actor.cpp', 'asm/ov00/Actor/Actor.s', 'asm/ov00/ov00_020c3348.s', - 'src/00_Core/Actor/ActorManager.cpp', 'asm/ov00/Actor/ActorManager.s', 'asm/ov00/ov00_020c3e54.s', @@ -136,7 +118,6 @@ ov13 = Overlay(name='ov13', after=[ov04, ov05, ov06, ov07], objects=[ ov14 = Overlay(name='ov14', after=[ov08, ov09, ov10, ov13], objects=[ 'asm/ov14/ov14_0211f640.s', - 'src/14_Land/Actor/ActorRupee.cpp', 'asm/ov14/Actor/ActorRupee.s', 'asm/ov14/ov14_0213b778.s', diff --git a/tools/m2ctx.py b/tools/m2ctx.py index 299d1834..24e12d7a 100755 --- a/tools/m2ctx.py +++ b/tools/m2ctx.py @@ -6,6 +6,8 @@ import subprocess import os from pathlib import Path import argparse +import re +import tempfile parser = argparse.ArgumentParser(description="Generates a context for decomp.me") parser.add_argument('file', help="Input file to preprocess") @@ -28,19 +30,40 @@ root_dir = script_dir / ".." def eprint(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) -try: - ctx: str = subprocess.check_output([ - 'gcc', - '-E', '-P', '-fworking-directory', '-undef', '-dD', - *CXX_FLAGS, - args.file - ], cwd=root_dir, encoding=args.encoding) -except subprocess.CalledProcessError as e: - eprint(f"Failed to preprocess '{args.file}'") - if args.verbose: eprint(e) - else: eprint("Use -v for more verbose error output") - exit(1) +# Finds all lines starting with #include followed by <...> or "..." +INCLUDE_REGEX = r'^\s*#\s*include\s*([<"][\S ]+[>"])\s*$' +# Finds all line comments and multiline comments +COMMENT_REGEX = r'\/\/.*$|\/\*(?:.|\r|\n)+?\*\/' +# Finds all lines from #ifndef NONMATCHING to #else +NONMATCH_REGEX = r'^\s*#\s*ifndef\s*NONMATCHING\s*(?:.|\r|\n)*\n\s*#\s*else\s*$' +with open(args.file, 'r') as f: + contents = f.read() +contents = re.sub(COMMENT_REGEX, '', contents, 0, re.MULTILINE) +contents = re.sub(NONMATCH_REGEX, '', contents, 0, re.MULTILINE) +includes = re.findall(INCLUDE_REGEX, contents, re.MULTILINE) + +_, suffix = os.path.splitext(args.file) + +with tempfile.NamedTemporaryFile(delete=True, suffix=suffix) as tmp_file: + # Write includes + for include in includes: + tmp_file.write(f'#include {include}\n'.encode()) + tmp_file.flush() + + # Run preprocessor + try: + ctx: str = subprocess.check_output([ + 'gcc', + '-E', '-P', '-fworking-directory', '-undef', '-dD', + *CXX_FLAGS, + tmp_file.name + ], cwd=root_dir, encoding=args.encoding) + except subprocess.CalledProcessError as e: + eprint(f"Failed to preprocess '{args.file}'") + if args.verbose: eprint(e) + else: eprint("Use -v for more verbose error output") + exit(1) lines = ctx.splitlines(True) for i in reversed(range(len(lines))): diff --git a/tools/mangle.py b/tools/mangle.py index a9bfcadf..d14bec54 100644 --- a/tools/mangle.py +++ b/tools/mangle.py @@ -38,7 +38,6 @@ cc.extend([ '-i', include_dir, '-i', libc_include_dir, '-i', libcpp_include_dir, - '-DSTUBS', args.file ]) diff --git a/tools/objdiff.py b/tools/objdiff.py index 80f91ca4..16078798 100644 --- a/tools/objdiff.py +++ b/tools/objdiff.py @@ -35,16 +35,16 @@ def find_asm_path(src_path: Path) -> Path | None: return asm_path -def get_build_path(path: Path) -> Path: +def get_build_path(path: Path, extension='.o') -> Path: region = args.region.lower() - return Path('build') / region / path.parent / (path.name + '.o') + return Path('build') / region / path.parent / (path.name + extension) config = dict() config["custom_make"] = "make" config["custom_args"] = [ - f"REGION={args.region}", - "-B" # Always build target + "-B", + f"REGION={args.region}" ] config["build_target"] = True config["watch_patterns"] = [ @@ -62,6 +62,7 @@ for (root, dirs, files) in os.walk(src_dir): src_path = Path(f'{root}/{file}') src_path = src_path.relative_to(src_dir) asm_path = find_asm_path(src_path) + src_path = 'src' / src_path if asm_path: asm_path = 'asm' / asm_path @@ -70,9 +71,17 @@ for (root, dirs, files) in os.walk(src_dir): obj = dict() obj["name"] = name if asm_path.exists(): obj["target_path"] = str(get_build_path(asm_path)) - obj["base_path"] = str(get_build_path('src' / src_path)) + obj["base_path"] = str(get_build_path(src_path)) obj["reverse_fn_order"] = False + scratch = dict() + scratch["platform"] = "nds_arm9" + scratch["compiler"] = "mwcc_30_131" + scratch["ctx_path"] = str(get_build_path(src_path, '.ctx')) + scratch["build_ctx"] = True + + obj["scratch"] = scratch + config["objects"].append(obj) with open(config_path, 'w') as f: