Skip to content
Draft
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
23,022 changes: 11,535 additions & 11,487 deletions src/mkb/mkb2.us.lst

Large diffs are not rendered by default.

210 changes: 205 additions & 5 deletions src/mkb/mkb2_ghidra.h

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions src/mods/banans.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@

#include "systems/pref.h"
#include "utils/patch.h"
#include "utils/relutil.h"

namespace banans {

void tick() {
if (pref::did_change(pref::BoolPref::BananaCounter9999)) {
if (pref::get(pref::BoolPref::BananaCounter9999)) {
patch::write_word(reinterpret_cast<void*>(0x802b8284), 0x2c00270f);
patch::write_word(reinterpret_cast<void*>(0x802b828c), 0x3800270f);
patch::write_word(relutil::relocate_addr(0x802b8284), 0x2c00270f);
patch::write_word(relutil::relocate_addr(0x802b828c), 0x3800270f);
} else {
patch::write_word(reinterpret_cast<void*>(0x802b8284), 0x2c0003e7);
patch::write_word(reinterpret_cast<void*>(0x802b828c), 0x380003e7);
patch::write_word(relutil::relocate_addr(0x802b8284), 0x2c0003e7);
patch::write_word(relutil::relocate_addr(0x802b828c), 0x380003e7);
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/mods/camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "systems/pref.h"
#include "utils/patch.h"
#include "utils/ppcutil.h"
#include "utils/relutil.h"

namespace camera {

Expand All @@ -26,7 +27,7 @@ void tick() {
mkb::cameras[0].mode = 0x4c;
}

patch::write_word(reinterpret_cast<void*>(0x802886c8), PPC_INSTR_LI(PPC_R0, 0x200));
patch::write_word(relutil::relocate_addr(0x802886c8), PPC_INSTR_LI(PPC_R0, 0x200));
mkb::g_camera_turn_rate_scale = 0.75;
mkb::camera_pivot_height = 0.18;
mkb::camera_height = 0.8;
Expand All @@ -39,7 +40,7 @@ void tick() {
mkb::cameras[0].mode = 0x4c;
}

patch::write_word(reinterpret_cast<void*>(0x802886c8), PPC_INSTR_LI(PPC_R0, 0x200));
patch::write_word(relutil::relocate_addr(0x802886c8), PPC_INSTR_LI(PPC_R0, 0x200));
mkb::g_camera_turn_rate_scale = 0.75;
mkb::camera_pivot_height = 0.18;
mkb::camera_height = 0.8;
Expand All @@ -55,7 +56,7 @@ void tick() {
// angle. Everything else brings the camera position/pivot values in-line with SMB1's
// values Camera mode 0x1 enables SMB1-like vertical camera tracking, camera mode 0x4c
// is SMB2's default
patch::write_word(reinterpret_cast<void*>(0x802886c8), PPC_INSTR_LI(PPC_R0, 0x400));
patch::write_word(relutil::relocate_addr(0x802886c8), PPC_INSTR_LI(PPC_R0, 0x400));
mkb::g_camera_turn_rate_scale = 0.6875;
mkb::camera_pivot_height = -0.5;
mkb::camera_height = 1;
Expand Down
3 changes: 2 additions & 1 deletion src/mods/freecam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "utils/draw.h"
#include "utils/macro_utils.h"
#include "utils/patch.h"
#include "utils/relutil.h"

namespace freecam {

Expand Down Expand Up @@ -112,7 +113,7 @@ static void call_camera_func_hook(mkb::Camera* camera, mkb::Ball* ball) {
}

void init() {
patch::write_branch_bl(reinterpret_cast<void*>(0x8028353c),
patch::write_branch_bl(relutil::relocate_addr(0x8028353c),
reinterpret_cast<void*>(call_camera_func_hook));

patch::hook_function(s_event_camera_tick_tramp, mkb::event_camera_tick, []() {
Expand Down
6 changes: 3 additions & 3 deletions src/mods/hide.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "mods/freecam.h"
#include "systems/pref.h"
#include "utils/patch.h"
#include "utils/relutil.h"

namespace hide {

Expand Down Expand Up @@ -75,11 +76,10 @@ static void init_hide_bg() {
});

// Black fog
patch::write_branch_bl(reinterpret_cast<void*>(0x80352e58),
patch::write_branch_bl(relutil::relocate_addr(0x80352e58),
reinterpret_cast<void*>(avdisp_set_fog_color_hook));
patch::write_branch_bl(reinterpret_cast<void*>(0x80352eac),
patch::write_branch_bl(relutil::relocate_addr(0x80352eac),
reinterpret_cast<void*>(nl2ngc_set_fog_color_hook));

}

static void init_hide_hud() {
Expand Down
5 changes: 3 additions & 2 deletions src/mods/iw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "systems/pref.h"
#include "utils/draw.h"
#include "utils/patch.h"
#include "utils/relutil.h"
#include "utils/timerdisp.h"

// TODO: track best times per world
Expand Down Expand Up @@ -92,9 +93,9 @@ static void handle_iw_timer() {
}

void init() {
patch::write_branch(reinterpret_cast<void*>(0x80274804),
patch::write_branch(relutil::relocate_addr(0x80274804),
reinterpret_cast<void*>(main::stage_select_menu_hook));
patch::write_branch(reinterpret_cast<void*>(0x8032a86c),
patch::write_branch(relutil::relocate_addr(0x8032a86c),
reinterpret_cast<void*>(main::pause_menu_text_hook));
}

Expand Down
10 changes: 5 additions & 5 deletions src/mods/jump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
#include "mods/physics.h"
#include "systems/pad.h"
#include "systems/pref.h"
#include "utils/draw.h"
#include "utils/macro_utils.h"
#include "utils/patch.h"
#include "utils/relutil.h"

namespace jump {

Expand Down Expand Up @@ -56,19 +56,19 @@ void patch_minimap() {

// Patch instructions if they aren't nop
if (*patch1_loc != 0x60000000) {
s_patch1 = patch::write_nop(reinterpret_cast<void*>(0x808f4d18));
s_patch1 = patch::write_nop(relutil::relocate_addr(0x808f4d18));
}
if (*patch2_loc != 0x60000000) {
s_patch2 = patch::write_nop(reinterpret_cast<void*>(0x808f5168));
s_patch2 = patch::write_nop(relutil::relocate_addr(0x808f5168));
}
}
}

static void restore_minimap() {
if (mkb::main_mode == mkb::MD_GAME) {
// These overwrites exist in main_game.rel which isn't always loaded
patch::write_word(reinterpret_cast<void*>(0x808f4d18), s_patch1);
patch::write_word(reinterpret_cast<void*>(0x808f5168), s_patch2);
patch::write_word(relutil::relocate_addr(0x808f4d18), s_patch1);
patch::write_word(relutil::relocate_addr(0x808f5168), s_patch2);
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/systems/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,23 +52,23 @@ static patch::Tramp<decltype(&mkb::smd_game_play_tick)> s_smd_game_play_tick_tra
static void perform_assembly_patches() {
// Inject the run function at the start of the main game loop
// Hooked after Workshop Mod's tick()
patch::write_branch_bl(reinterpret_cast<void*>(0x80270704),
patch::write_branch_bl(relutil::relocate_addr(0x80270704),
reinterpret_cast<void*>(start_main_loop_assembly));

/* Remove OSReport call ``PERF : event is still open for CPU!``
since it reports every frame, and thus clutters the console */
// Only needs to be applied to the US version
patch::write_nop(reinterpret_cast<void*>(0x80033E9C));
patch::write_nop(relutil::relocate_addr(0x80033E9C));

// Nop the conditional that guards `draw_debugtext`, enabling it even when debug mode is
// disabled
patch::write_nop(reinterpret_cast<void*>(0x80299f54));
patch::write_nop(relutil::relocate_addr(0x80299f54));
// Nop this pausemenu screenshot call so we can call it when we want to
patch::write_nop(reinterpret_cast<void*>(0x80270aac));
patch::write_nop(relutil::relocate_addr(0x80270aac));

// Titlescreen patches
mkb::strcpy(reinterpret_cast<char*>(0x8047f4ec), "SMB2 PRACTICE MOD");
patch::write_branch(reinterpret_cast<void*>(0x8032ad0c),
patch::write_branch(relutil::relocate_addr(0x8032ad0c),
reinterpret_cast<void*>(main::custom_titlescreen_text_color));
}

Expand Down
6 changes: 4 additions & 2 deletions src/utils/draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
#include "mkb/mkb.h"

#include "macro_utils.h"
#include "patch.h"
#include "systems/assembly.h"
#include "utils/patch.h"
#include "utils/relutil.h"

namespace draw {

Expand All @@ -15,7 +16,7 @@ static s32 s_notify_frame_counter;
static mkb::GXColor s_notify_color;

void init() {
patch::write_branch(reinterpret_cast<void*>(0x802aeca4),
patch::write_branch(relutil::relocate_addr(0x802aeca4),
reinterpret_cast<void*>(main::full_debug_text_color));
}

Expand Down Expand Up @@ -92,6 +93,7 @@ static Vec2d heart_verts[] = {

void heart() {
// "Blank" texture object which seems to let us set a color and draw a poly with it idk??
// TODO I guess this lives in the heap? fix w.r.t merge-heaps
mkb::GXTexObj* texobj = reinterpret_cast<mkb::GXTexObj*>(0x807ad0e0);
mkb::GXLoadTexObj_cached(texobj, mkb::GX_TEXMAP0);
mkb::GXSetTevColor(mkb::GX_TEVREG0, {0xFF, 0x07, 0x07, 0xFF});
Expand Down
12 changes: 5 additions & 7 deletions src/utils/libsavest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@

#include "mkb/mkb.h"
#include "mods/timer.h"
#include "systems/heap.h"
#include "systems/pad.h"
#include "systems/pref.h"
#include "utils/draw.h"
#include "utils/memstore.h"
#include "utils/patch.h"
#include "utils/relutil.h"

namespace libsavest {

Expand Down Expand Up @@ -54,8 +52,8 @@ void SaveState::pass_over_regions() {
m_store.do_region(&mkb::sub_mode, sizeof(mkb::sub_mode));
m_store.do_region(&mkb::mode_info.stage_time_frames_remaining,
sizeof(mkb::mode_info.stage_time_frames_remaining));
m_store.do_region(reinterpret_cast<void*>(0x8054E03C), 0xe0); // Camera region
m_store.do_region(reinterpret_cast<void*>(0x805BD830), 0x1c); // Some physics region
m_store.do_region(relutil::relocate_addr(0x8054E03C), 0xe0); // Camera region
m_store.do_region(relutil::relocate_addr(0x805BD830), 0x1c); // Some physics region
m_store.do_region(&mkb::mode_info.ball_mode, sizeof(mkb::mode_info.ball_mode));
m_store.do_region(mkb::g_camera_standstill_counters, sizeof(mkb::g_camera_standstill_counters));

Expand Down Expand Up @@ -102,8 +100,8 @@ void SaveState::pass_over_regions() {
m_store.do_region(mkb::goalbags, sizeof(mkb::GoalBag) * mkb::stagedef->goal_count);

// Pause menu
m_store.do_region(reinterpret_cast<void*>(0x8054DCA8), 56); // Pause menu state
m_store.do_region(reinterpret_cast<void*>(0x805BC474), 4); // Pause menu bitfield
m_store.do_region(relutil::relocate_addr(0x8054DCA8), 56); // Pause menu state
m_store.do_region(relutil::relocate_addr(0x805BC474), 4); // Pause menu bitfield

for (u32 i = 0; i < mkb::sprite_pool_info.upper_bound; i++) {
if (mkb::sprite_pool_info.status_list[i] == 0) continue;
Expand Down
112 changes: 69 additions & 43 deletions src/utils/relutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,59 +5,85 @@

namespace relutil {

struct RelEntry {
u16 offset;
u8 type;
u8 section;
u32 addend;
// Start of a loaded DOL, REL, or REL BSS
struct Region {
ModuleId id;
void* vanilla_ptr;
u32 size;
bool is_bss;
};
static_assert(sizeof(RelEntry) == 0x8);

struct Imp {
u32 module_id;
RelEntry* rel_offset;
static Region s_vanilla_regions[] = {
{ModuleId::Dol, reinterpret_cast<void*>(0x80000000), 0x199F84, false},
{ModuleId::MainLoop, reinterpret_cast<void*>(0x80270100), 0x2DC7CC, false},
{ModuleId::MainLoop, reinterpret_cast<void*>(0x8054C8E0), 0xDDA4C, true},
{ModuleId::MainGame, reinterpret_cast<void*>(0x808F3FE0), 0x8B484, false},
{ModuleId::MainGame, reinterpret_cast<void*>(0x8097F4A0), 0x65F0, true},
{ModuleId::SelNgc, reinterpret_cast<void*>(0x808F3FE0), 0x55C87, false},
{ModuleId::SelNgc, reinterpret_cast<void*>(0x80949CA0), 0x8BD4, true},
};
static_assert(sizeof(Imp) == 0x8);

struct RelHeader {
u32 id;
RelHeader* next;
RelHeader* prev;
u32 num_sections;
void* section_info_offset;
char* name_offset;
u32 name_size;
u32 version;
u32 bss_size;
RelEntry* rel_offset;
Imp* imp_offset;
u32 imp_size;
u8 prolog_section;
u8 epilog_section;
u8 unresolved_section;
u8 bss_section;
void* prolog;
void* epilog;
void* unresolved;
u32 align;
u32 bssAlign;
u32 fixSize;
};
static_assert(sizeof(RelHeader) == 0x4C);
static mkb::OSModuleHeader* find_loaded_rel(ModuleId id) {
mkb::OSModuleHeader* module = *reinterpret_cast<mkb::OSModuleHeader**>(0x800030C8);
while (module != nullptr) {
if (module->info.id == static_cast<u32>(id)) {
return module;
}
module = reinterpret_cast<mkb::OSModuleHeader*>(module->info.link.next);
}
return nullptr;
}

void* relocate_addr(u32 vanilla_addr) {
for (const auto& region : s_vanilla_regions) {
u32 region_addr = reinterpret_cast<u32>(region.vanilla_ptr);
if (vanilla_addr >= region_addr && vanilla_addr < (region_addr + region.size)) {
// Vanilla pointer can be treated as absolute address
if (region.id == ModuleId::Dol) {
return reinterpret_cast<void*>(vanilla_addr);
}

// Find the rel location, if it's loaded at all
mkb::OSModuleHeader* module = find_loaded_rel(region.id);
if (module != nullptr) {
u32 live_addr;
if (region.is_bss) {
if (region.id == ModuleId::MainLoop) {
live_addr = reinterpret_cast<u32>(mkb::mainloop_rel_buffer_info.bss_buffer);
} else if (region.id == ModuleId::MainGame || region.id == ModuleId::SelNgc) {
live_addr =
reinterpret_cast<u32>(mkb::additional_rel_buffer_info.bss_buffer);
} else {
// Sorry, we don't know where the BSS for that REL is
return nullptr;
}
} else {
live_addr = reinterpret_cast<u32>(module);
}

u32 relocated_addr = live_addr + (vanilla_addr - region_addr);

return reinterpret_cast<void*>(relocated_addr);
}
}
}

return nullptr;
}

void* compute_mainloop_reldata_boundary(void* start) {
RelHeader* module = *reinterpret_cast<RelHeader**>(0x800030C8);
for (u32 imp_idx = 0; imp_idx * sizeof(Imp) < module->imp_size; imp_idx++) {
Imp& imp = module->imp_offset[imp_idx];
mkb::OSModuleHeader* module = *reinterpret_cast<mkb::OSModuleHeader**>(0x800030C8);
for (u32 imp_idx = 0; imp_idx * sizeof(mkb::OSImportInfo) < module->impSize; imp_idx++) {
mkb::OSImportInfo& imp = reinterpret_cast<mkb::OSImportInfo*>(module->impOffset)[imp_idx];
// Look for end of relocation data against main_loop.rel itself
if (imp.module_id != 1) continue;
if (ModuleId(imp.id) != ModuleId::MainLoop) continue;

// Ignore space already allocated for this mod
// `rel_offset` may not be `sizeof(RelEntry)` aligned, so give `start` the same alignment
u32 start_aligned = reinterpret_cast<u32>(start) +
(reinterpret_cast<u32>(imp.rel_offset) % sizeof(RelEntry));
u32 first_valid_ptr = MAX(reinterpret_cast<u32>(imp.rel_offset), start_aligned);
RelEntry* first_valid = reinterpret_cast<RelEntry*>(first_valid_ptr);
u32 start_aligned =
reinterpret_cast<u32>(start) + (reinterpret_cast<u32>(imp.offset) % sizeof(mkb::OSRel));
u32 first_valid_ptr = MAX(reinterpret_cast<u32>(imp.offset), start_aligned);
mkb::OSRel* first_valid = reinterpret_cast<mkb::OSRel*>(first_valid_ptr);

u32 rel_idx = 0;
for (; first_valid[rel_idx].type != 203; rel_idx++)
Expand Down
Loading