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 }