/ examples / demo-plugin / src / lib.rs
lib.rs
  1  #![allow(clippy::missing_safety_doc)]
  2  
  3  use log::*;
  4  use std::ffi::{c_char, c_void};
  5  
  6  use emf_rs::macros::plugin;
  7  use emf_rs::safer_ffi::prelude::char_p;
  8  
  9  #[plugin(id = "dev.megu.demo-plugin")]
 10  mod plugin {
 11  	// #[hook_signature] is used to hook a function based on a byte signature, provided as a string.
 12  	// take a look at the register!() macro below to see how it's used.
 13  	//
 14  	// There is also a #[hook_address] attribute that uses a pointer instead of a signature.
 15  	// This is useful when finding the address is not as simple as providing a byte signature.
 16  	// e.g.
 17  	// register!(
 18  	//   let address = { some code }; // however you find your address
 19  	//   address // return the address
 20  	// );
 21  	#[hook_signature]
 22  	#[link_setting("godmode_enabled")]
 23  	extern "C" fn proc_dmg_and_stamina(motile_ptr: *mut c_void, _: f32) -> c_char {
 24  		// the register!() macro returns a signature to the target function when using #[hook_signature]
 25  		register!("53 56 48 8D 64 24 D8 48 89 CB 40 30 F6 8B 05 ?? ?? ?? ?? 89");
 26  
 27  		println!("Stopping damage for motile: {:p}", motile_ptr);
 28  
 29  		// calling proc_dmg_from_stamina from inside the hook runs the original function
 30  		proc_dmg_and_stamina(motile_ptr, 0.0)
 31  	}
 32  
 33  	// #[patch_signature] is used to patch a function based on a byte signature, provided as a string.
 34  	// take a look at the register!() macro below to see how it's used.
 35  	//
 36  	// Just like #[hook_address], there is also a #[patch_address] attribute, used in the same way.
 37  	//
 38  	// The address found at the signature (or address) is passed into the function as the first argument.
 39  	// This way, you can read the data from that address if you need to use it. See the examples below.
 40  	#[patch_signature]
 41  	#[link_setting("godhand_enabled")]
 42  	fn ignore_range_limit_for_placement(_address: *mut u8) -> Vec<u8> {
 43  		// the register!() macro returns a signature to the target memory when using #[patch_signature]
 44  		register!("48 8B 40 10 48 8D 48 20");
 45  
 46  		vec![
 47  			0x66_u8, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x0F, 0x1F, 0x84, 0x00,
 48  			0x00, 0x00, 0x00, 0x00, 0x45, 0x31, 0xED,
 49  		]
 50  	}
 51  
 52  	#[patch_signature(offset = 0x2)]
 53  	#[link_setting("godhand_enabled")]
 54  	fn ignore_range_limit_for_reach(_address: *mut u8) -> Vec<u8> {
 55  		register!("EB 0E 4C 89 E1");
 56  
 57  		vec![
 58  			0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x90, 0x45, 0x31, 0xED,
 59  		]
 60  	}
 61  
 62  	#[patch_signature(offset = 0xF)]
 63  	#[link_setting("godhand_enabled")]
 64  	fn ignore_range_limit_for_door_and_lever_reach(address: *mut u8) -> Vec<u8> {
 65  		register!("E9 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 8B 40 ?? 25 ?? ?? ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 8B 40 ?? 48 8B 80 ?? ?? ?? ?? 48 8D");
 66  
 67  		let instruction = Memory::read_bytes(address, 0x5);
 68  		Memory::reassemble_at_offset(instruction, 0xF)
 69  	}
 70  
 71  	#[patch_signature(offset = 0x19)]
 72  	#[link_setting("godhand_enabled")]
 73  	fn ignore_weight(_address: *mut u8) -> Vec<u8> {
 74  		register!("25 ?? ?? ?? ?? 75 ?? F3 0F ?? ?? ?? ?? ?? ?? 66 0F ?? ?? ?? ?? ?? ?? 7A");
 75  
 76  		vec![0xEB]
 77  	}
 78  
 79  	#[patch_signature(offset = 0x14)]
 80  	#[link_setting("godhand_enabled")]
 81  	fn interact_while_fallen(_address: *mut u8) -> Vec<u8> {
 82  		register!("74 ?? 48 8B 05 ?? ?? ?? ?? 8B 80 ?? ?? ?? ?? 25 ?? ?? ?? ?? 0F 87 ?? ?? ?? ??");
 83  
 84  		vec![0x90, 0x90, 0x90, 0x90, 0x90, 0x90]
 85  	}
 86  
 87  	#[patch_signature(offset = 0x12)]
 88  	#[link_setting("godhand_enabled")]
 89  	fn dont_interrupt_if_fallen(_address: *mut u8) -> Vec<u8> {
 90  		register!("48 8B 05 ?? ?? ?? ?? 8B 80 ?? ?? ?? ?? 25 ?? ?? ?? ?? ?? ?? E8");
 91  
 92  		vec![0xEB]
 93  	}
 94  }
 95  
 96  #[no_mangle]
 97  pub unsafe extern "C" fn enable() {
 98  	let mut plugin = plugin::get();
 99  	debug!("Enabling plugin {}", plugin.id);
100  
101  	let plugin_id = plugin.id.clone();
102  	for patch in plugin.patches.values_mut() {
103  		let enabled = patch.is_config_enabled(&plugin_id);
104  		patch.set_enabled(enabled);
105  	}
106  
107  	for hook in plugin.hooks.values_mut() {
108  		let enabled = hook.is_config_enabled(&plugin_id);
109  		hook.set_enabled(enabled);
110  	}
111  
112  	plugin.on_enable().unwrap();
113  }
114  
115  #[no_mangle]
116  pub unsafe extern "C" fn disable() {
117  	let mut plugin = plugin::get();
118  	plugin.on_disable().unwrap();
119  	debug!("Disabling plugin {}", plugin.id);
120  }
121  
122  #[no_mangle]
123  pub unsafe extern "C" fn on_message(s: char_p::Box, m: char_p::Box) {
124  	plugin::get().on_message(s, m, |sender, message| {
125  		debug!("Received message from {}: {}", sender, message);
126  	});
127  }
128  
129  #[no_mangle]
130  pub unsafe extern "C" fn setting_changed_bool(name: char_p::Box, value: bool) {
131  	// If the ID of a boolean setting starts with `patch::` or `hook::`,
132  	// the plugin will automatically enable/disable the corresponding patch/hook.
133  
134  	// Example:
135  	//
136  	// [[setting]]
137  	// name = "My Setting"
138  	// id = "patch::my_patch"
139  	//
140  	// or
141  	//
142  	// [[setting]]
143  	// name = "My Setting"
144  	// id = "hook::my_hook"
145  
146  	plugin::get().on_setting_changed_bool(name, value, |key, value| {
147  		// Do something with this
148  		debug!("Setting changed: {} = {}", key, value);
149  	});
150  }
151  
152  #[no_mangle]
153  pub unsafe extern "C" fn setting_changed_int(name: char_p::Box, value: i32) {
154  	plugin::get().on_setting_changed_int(name, value, |key, value| {
155  		// Do something with this
156  		debug!("Setting changed: {} = {}", key, value);
157  	});
158  }
159  
160  #[no_mangle]
161  pub unsafe extern "C" fn setting_changed_float(name: char_p::Box, value: f32) {
162  	plugin::get().on_setting_changed_float(name, value, |key, value| {
163  		// Do something with this
164  		debug!("Setting changed: {} = {}", key, value);
165  	});
166  }
167  
168  #[no_mangle]
169  pub unsafe extern "C" fn setting_changed_string(name: char_p::Box, value: char_p::Box) {
170  	plugin::get().on_setting_changed_string(name, value, |key, value| {
171  		// Do something with this
172  		debug!("Setting changed: {} = {}", key, value);
173  	});
174  }