Skip to content
This repository has been archived by the owner on Aug 1, 2024. It is now read-only.

LibCode

rankaisija edited this page Jul 29, 2023 · 1 revision

What is LibCode?

LibCode, aka lib_code, is library of function patches in C and MIPS. The important part of this is defining the z64rom and z64ram for the replaced function in OoT code.

#include <uLib.h>

/*
   z64ram = 0x80002130
   z64rom = 0x002D30
   z64next = 0x800021B0
 */

void osSyncPrintf(const char* fmt, ...) {
#ifdef DEV_BUILD
	if (gLibCtx.state.vanillaOsPrintf == 0)
		return;
	va_list args;
	
	va_start(args, fmt);
	
	_Printf(is_proutSyncPrintf, NULL, fmt, args);
	
	va_end(args);
#endif
}

This function above replaces the OoT function osSyncPrintf, which enables user to control if the system prints are outputted. This makes it easier to read through prints outputted by OoT.

There's also the #ifdef DEV_BUILD, which basically removes all the code here so that nothing gets printed out. This define will be absent for release build.

The reason why this is limited to only function at a time is because we can't ensure that multiple functions would land into their original ram addr positions. So this is simply not possible unless user goes through some padding/optimization to the first function in order to make the second function land in its original address. With z64rom the code simply isn't shiftable.

Making new LibCode patch

All you need in order to make a patch is to have the correct rom and ram address for the function you're replacing.

Simplest solution is to copy paste a function of your choice from OoT Decompilation Project into a C file inside src/lib_code/*

Use sym_info.py from decomp to fill in the following values:

./sym_info.py osSyncPrintf 
Symbol osSyncPrintf (RAM: 0x80002130, ROM: 0x002D30, build/src/boot/is_debug.o)
/*
   z64ram = 0x80002130
   z64rom = 0x002D30
 */

z64next is an optional, which is the ram address of the next function/variable from the function/variable you're replacing. This information is utilized to do size check on build so that z64rom knows to cancel build if it overwrites something else that comes after it. It's good practice to utilize this as overwritten function will most likely crash or at least cause some undefined behaviour.

/*
   z64next = 0x800021B0
 */

I can't make my patch fit into this limited space!

Utilize LibUser to have "hooks".

This happens by taking part of the code, or all of it into a function that will be stored in the LibUser.

One good example of how this is done is src/lib_code/!std/patch/Actor_InitTalk.c.

#include <uLib.h>

/*
   z64ram = 0x8002F1C4
   z64rom = 0xAA6364
   z64next = 0x8002F298
 */

s32 func_8002F1C4(Actor* actor, PlayState* playState, f32 arg2, f32 arg3, u32 exchangeItemId) {
	return Actor_TalkCondition(actor, playState, arg2, arg3, exchangeItemId);
}

All the arguments are forwarded from here to the new function that is in LibUser.