More Examples

Now that you've made a basic plugin using hooks, here are some concise examples of things you can do with the plugin macros.

Function Hooks

Hooking By Signature

#[hook_signature]
extern "C" fn my_hook(arg1: u32, arg2: f32) -> bool {
	// Create the hook at the pointer identified using this signature.
	register!("DE AD BE EF ?? ?? ?? ??");

	// Call our own hook function again.
	my_hook::func(1, 3.5);

	// call the original Exanima function, and return the result.
	my_hook(arg1, 2.0)
}

Hooking By Signature With Offset

// When the register!() macro finds a pointer, it will add 0x20 (32) bytes to it.
// This also supports negative offsets, e.g. -0x20
#[hook_signature(offset = 0x20)]
extern "C" fn my_hook(arg1: u32, arg2: f32) -> bool {
	// Create the hook at the pointer identified using this signature.
	register!("DE AD BE EF ?? ?? ?? ??");

	// Call our own hook function again.
	my_hook::func(1, 3.5);

	// call the original Exanima function, and return the result.
	my_hook(arg1, 2.0)
}

Hooking By Pointer

#[hook_pointer]
extern "C" fn my_hook(arg1: u32, arg2: f32) -> bool {
	// Create the hook at the pointer returned from this macro
	register!(
		let pointer = "DE AD BE EF ?? ?? ?? ??";
		// Find our pointer using whatever method we want, and return it.
		emf_rs::Memory::sig_scan(pointer)
	);

	// Call our own hook function again.
	my_hook::func(1, 3.5);

	// call the original Exanima function, and return the result.
	my_hook(arg1, 2.0)
}

Memory Patching

Patching By Signature

#[patch_signature]
// The `address` argument is the pointer found by the register!() macro.
// It cannot be used inside the register!() macro as it doesn't exist yet at that point.
fn my_patch(address: *mut u8) -> Vec<u8> {
	// Apply the patch at the pointer identified using this signature.
	register!("DE AD BE EF ?? ?? ?? ??");
	
	// Return these bytes to be used for the patch.
	vec![0x1, 0x2, 0x3, 0x90, 0x90, 0x90]
}

Patching By Signature With Offset

// When the register!() macro finds a pointer, it will add 0x20 (32) bytes to it.
// This also supports negative offsets, e.g. -0x20
#[patch_signature(offset = 123)]
// The `address` argument is the pointer found by the register!() macro.
// It cannot be used inside the register!() macro as it doesn't exist yet at that point.
fn my_patch(address: *mut u8) -> Vec<u8> {
	// Apply the patch at the pointer identified using this signature, with the offset applied.
	register!("DE AD BE EF ?? ?? ?? ??");
	
	// Return these bytes to be used for the patch.
	vec![0x1, 0x2, 0x3, 0x90, 0x90, 0x90]
}

Patching By Pointer

#[patch_pointer]
// The `address` argument is the pointer found by the register!() macro.
// It cannot be used inside the register!() macro as it doesn't exist yet at that point.
fn my_patch(address: *mut u8) -> Vec<u8> {
	// Apply the patch at the pointer identified using this signature, with the offset applied.
	register!(
		let signature = "DE AD BE EF ?? ?? ?? ??");
		emf_rs::Memory::sig_scan(signature)
	);
	
	// Return these bytes to be used for the patch.
	vec![0x1, 0x2, 0x3, 0x90, 0x90, 0x90]
}

More things you can do with register!()

Register can be a one-liner

// Patch based on signature
#[patch_signature]
fn my_patch(address: *mut u8) -> Vec<u8> {
	// Use the signature
	register!("DE AD BE EF ?? ?? ?? ??");
	...
}

Register can be as many lines, and as complex as you want

#[patch_pointer]
fn my_patch(address: *mut u8) -> Vec<u8> {
	// register!() macro behaves like it's own code block.
	register!(
		// You can run pretty much anything in here. But try to keep it minimal.
		// Plugin initialisation pauses the game until it's complete, so these should be short and sweet.

		// You'd never really want to place a random loop like this in here,
		// it's just used to show you can treat this like any code block.
		for i in 0..16 {
			println!("Looped {} times!", i);
		}

		let signature = "DE AD BE EF ?? ?? ?? ??";
		let pointer = emf_rs::Memory::sig_scan(signature);
		// Increment the pointer by 0x20 (32) bytes. Negative number also work
		let pointer = pointer.byte_offset(0x20);

		return pointer;
	)
}

You can hardcode pointer for testing

Only do this for testing. Never release a plugin with hard-coded pointers.

// Patch based on hard-coded pointer
#[patch_pointer]
fn my_patch(address: *mut u8) -> Vec<u8> {
	// It's only acceptable to hard-code pointers during debugging, testing, and development.
	// Never release a plugin with hard-coded pointers!!
	register!(0x1234567);
	...
}