diff --git a/hook/src/hooks/mod.rs b/hook/src/hooks/mod.rs index 90308d23..33e59a86 100644 --- a/hook/src/hooks/mod.rs +++ b/hook/src/hooks/mod.rs @@ -1,5 +1,7 @@ #![allow(clippy::missing_transmute_annotations)] +mod server_list; + use std::{ ffi::c_void, path::{Path, PathBuf}, @@ -20,11 +22,9 @@ use crate::{ retour::static_detour! { static HookUFunctionBind: unsafe extern "system" fn(*mut ue::UFunction); - static GetServerName: unsafe extern "system" fn(*const c_void, *const c_void) -> *const ue::FString; static SaveGameToSlot: unsafe extern "system" fn(*const USaveGame, *const ue::FString, i32) -> bool; static LoadGameFromSlot: unsafe extern "system" fn(*const ue::FString, i32) -> *const USaveGame; static DoesSaveGameExist: unsafe extern "system" fn(*const ue::FString, i32) -> bool; - static USessionHandlingFSDFillSessionSetting: unsafe extern "system" fn(*const c_void, *mut c_void, bool); static UObjectTemperatureComponentTimerCallback: unsafe extern "system" fn(*mut c_void); } @@ -49,7 +49,9 @@ pub unsafe fn initialize() -> Result<()> { exec_print_string as ExecFn, ), ] - .into_iter() + .iter() + .chain(server_list::kismet_hooks().iter()) + .cloned() .collect::>(); HookUFunctionBind.initialize( @@ -75,59 +77,7 @@ pub unsafe fn initialize() -> Result<()> { )?; HookUFunctionBind.enable()?; - if let Ok(server_name) = &globals().resolution.server_name { - GetServerName - .initialize( - std::mem::transmute(server_name.get_server_name.0), - get_server_name_detour, - )? - .enable()?; - } - - if let Ok(server_mods) = &globals().resolution.server_mods { - let patch_addr = server_mods.semicolon_h_replace.0 as *mut u8; - patch_mem(patch_addr.add(2), [0xC3])?; - patch_mem(patch_addr.add(7), [0x0F, 0x1F, 0x44, 0x00, 0x00])?; - patch_mem(patch_addr.add(102), [0xEB])?; - - let mods_fname = server_mods.mods_fname.0; - let set_fstring = server_mods.set_fstring.0; - USessionHandlingFSDFillSessionSetting - .initialize( - std::mem::transmute(server_mods.fill_session_setting.0), - move |world, game_settings, full_server| { - USessionHandlingFSDFillSessionSetting.call(world, game_settings, full_server); - - #[derive(serde::Serialize)] - struct Wrapper { - name: String, - version: String, - category: i32, - } - - let s = serde_json::to_string(&vec![Wrapper { - name: globals().meta.to_server_list_string(), - version: "mint".into(), - category: 0, - }]) - .unwrap(); - - let s = ue::FString::from(s.as_str()); - - type Fn = unsafe extern "system" fn( - *const c_void, - *const c_void, - *const ue::FString, - u32, - ); - - let f: Fn = std::mem::transmute(set_fstring); - - f(game_settings, *(mods_fname as *const *const c_void), &s, 3); - }, - )? - .enable()?; - } + server_list::init_hooks()?; if !globals().meta.config.disable_fix_exploding_gas { if let Ok(gas_fix) = &globals().resolution.gas_fix { @@ -322,22 +272,6 @@ fn does_save_game_exist_detour(slot_name: *const ue::FString, user_index: i32) - } } -fn get_server_name_detour(a: *const c_void, b: *const c_void) -> *const ue::FString { - unsafe { - let name = GetServerName.call(a, b).cast_mut().as_mut().unwrap(); - - let mut new_name = widestring::U16String::new(); - new_name.push_str("[MODDED] "); - new_name.push_slice(name.as_slice()); - - name.clear(); - name.extend_from_slice(new_name.as_slice()); - name.push(0); - - name - } -} - unsafe extern "system" fn exec_get_mod_json( _context: *mut ue::UObject, stack: *mut ue::kismet::FFrame, diff --git a/hook/src/hooks/server_list.rs b/hook/src/hooks/server_list.rs index efaa804b..3c5ab8a9 100644 --- a/hook/src/hooks/server_list.rs +++ b/hook/src/hooks/server_list.rs @@ -46,7 +46,7 @@ fn detour_get_server_name(a: *const c_void, b: *const c_void) -> *const ue::FStr let name = GetServerName.call(a, b).cast_mut().as_mut().unwrap(); let mut new_name = widestring::U16String::new(); - new_name.push_slice([0x5b, 0x4d, 0x4f, 0x44, 0x44, 0x45, 0x44, 0x5d, 0x20, 0x0a]); + new_name.push_slice([0x5b, 0x4d, 0x4f, 0x44, 0x44, 0x45, 0x44, 0x5d, 0x20]); new_name.push_slice(name.as_slice()); name.clear(); diff --git a/hook_resolvers/src/lib.rs b/hook_resolvers/src/lib.rs index e875bd51..6ff07a5d 100644 --- a/hook_resolvers/src/lib.rs +++ b/hook_resolvers/src/lib.rs @@ -55,13 +55,16 @@ impl_resolver_singleton!(PEImage, FOnlineSessionSettingsSetFString, |ctx| async feature = "serde-resolvers", derive(serde::Serialize, serde::Deserialize) )] -pub struct USessionHandlingFSDFillSessionSettting(pub usize); -impl_resolver_singleton!(collect, USessionHandlingFSDFillSessionSettting); +pub struct USessionHandlingFSDFillSessionSetttingInner(pub usize); +impl_resolver_singleton!(collect, USessionHandlingFSDFillSessionSetttingInner); impl_resolver_singleton!( PEImage, - USessionHandlingFSDFillSessionSettting, + USessionHandlingFSDFillSessionSetttingInner, |ctx| async { - let patterns = ["48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 55 41 54 41 55 41 56 41 57 48 8B EC 48 83 EC 50 48 8B B9"]; + let patterns = [ + "48 89 5C 24 ?? 48 89 4C 24 ?? 55 56 57 41 54 41 55 41 56 41 57 48 8B EC 48 81 EC 80 00 00 00 4C 8B FA", + "48 89 5C 24 ?? 4C 89 4C 24 ?? 48 89 4C 24 ?? 55 56 57 41 54 41 55 41 56 41 57 48 8B EC 48 83 EC 70", + ]; let res = join_all(patterns.iter().map(|p| ctx.scan(Pattern::new(p).unwrap()))).await; Ok(Self(ensure_one(res.into_iter().flatten())?)) } @@ -99,19 +102,6 @@ impl_resolver_singleton!(PEImage, ModsFName, |ctx| async { )?)) }); -#[derive(Debug, PartialEq)] -#[cfg_attr( - feature = "serde-resolvers", - derive(serde::Serialize, serde::Deserialize) -)] -pub struct SemicolonHReplace(pub usize); -impl_resolver_singleton!(collect, SemicolonHReplace); -impl_resolver_singleton!(PEImage, SemicolonHReplace, |ctx| async { - let patterns = ["48 8B CB 48 8D 55 E0 E8 ?? ?? ?? ?? 4D 63 FE 48 8B F0 45 8D 77 01 44 89 75 B8 45 3B F4 7E 18 41 8B D7 48 8D 4D B0 E8 ?? ?? ?? ?? 44 8B 65 BC 44 8B 75 B8 4C 8B 6D B0 33 D2 49 8B CF 48 C1 E1 04 49 03 CD 48 89 11 48 8B 06 48 89 01 48 89 16 8B 46 08 89 41 08 8B 46 0C 89 41 0C 48 89 56 08 48 8B 4D E0 48 85 C9 74 05 E8"]; - let res = join_all(patterns.iter().map(|p| ctx.scan(Pattern::new(p).unwrap()))).await; - Ok(Self(ensure_one(res.into_iter().flatten())?)) -}); - #[derive(Debug, PartialEq)] #[cfg_attr( feature = "serde-resolvers", @@ -164,9 +154,8 @@ impl_try_collector! { )] pub struct ServerModsResolution { pub set_fstring: FOnlineSessionSettingsSetFString, - pub fill_session_setting: USessionHandlingFSDFillSessionSettting, + pub fill_session_setting: USessionHandlingFSDFillSessionSetttingInner, pub mods_fname: ModsFName, - pub semicolon_h_replace: SemicolonHReplace, } } diff --git a/src/integrate.rs b/src/integrate.rs index a6ff5d5e..25a745fc 100644 --- a/src/integrate.rs +++ b/src/integrate.rs @@ -1172,20 +1172,47 @@ fn patch_server_list_entry(asset: &mut Asset) -> Result<(), I }) .map(|(pi, _)| PackageIndex::from_import(pi as i32).unwrap()); + let fsd_target_platform = asset + .imports + .iter() + .enumerate() + .find(|(_, i)| { + i.class_package.get_content(|s| s == "/Script/CoreUObject") + && i.class_name.get_content(|s| s == "Function") + && i.object_name.get_content(|s| s == "FSDTargetPlatform") + }) + .map(|(pi, _)| PackageIndex::from_import(pi as i32).unwrap()); + let ver = AssetVersion::new_from(asset); let mut statements = extract_tracked_statements(asset, ver, &None); - for (_pi, statements) in statements.iter_mut() { + for (pi, statements) in statements.iter_mut() { + let name = &asset + .asset_data + .get_export(*pi) + .unwrap() + .get_base_export() + .object_name; + + let swap_platform = name.get_content(|c| ["GetMissionToolTip", "SetSession"].contains(&c)); + for statement in statements { walk(&mut statement.ex, &|ex| { - if let KismetExpression::ExCallMath(ex) = ex { - if Some(ex.stack_node) == get_mods_installed && ex.parameters.len() == 2 { - ex.parameters[1] = ExFalse { + if let KismetExpression::ExCallMath(cm) = ex { + if Some(cm.stack_node) == get_mods_installed && cm.parameters.len() == 2 { + cm.parameters[1] = ExFalse { token: EExprToken::ExFalse, } .into(); info!("patched server list entry"); } + if swap_platform && Some(cm.stack_node) == fsd_target_platform { + *ex = ExByteConst { + token: EExprToken::ExByteConst, + value: 0, + } + .into(); + } } }); }