Skip to content

Commit

Permalink
Add ggxrd_gamestateDeinitialized trigger
Browse files Browse the repository at this point in the history
  • Loading branch information
super-continent committed Nov 15, 2024
1 parent d4e5f39 commit 515fce9
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 12 deletions.
7 changes: 7 additions & 0 deletions SAMMI_INFO.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,10 @@ victim: ObjectId,
victim_state: String,
victim_previous_state: String,
```

### `ggxrd_gamestateDeinitialized`

Triggers when the games battle state is being freed from memory,
to help track things like matches being exited early.

Currently contains no data.
11 changes: 11 additions & 0 deletions src/game/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ static_detour! {
static EndComboHook: unsafe extern "thiscall" fn (*mut u8);
static ActivateTimerHook: unsafe extern "thiscall" fn (*mut u8);
static ProcessHitHook: unsafe extern "thiscall" fn (*mut u8, *mut u8, *mut u8);
static DeInitGameStateHook: unsafe extern "C" fn ();
}

static MATCH_SCRIPTS: GlobalMut<BBScriptStorage> =
Expand Down Expand Up @@ -99,6 +100,16 @@ pub unsafe fn init_game_hooks() -> Result<(), retour::Error> {
sammi::process_hit_hook(attacker, victim);
})?
.enable()?;

let deinit_gamestate = make_fn!(get_aob_offset(&offset::FN_DEINIT_GAMESTATE).unwrap() => unsafe extern "C" fn ());
log::debug!("deinitialize_gamestate: {:X}", deinit_gamestate as usize);

DeInitGameStateHook
.initialize(deinit_gamestate, || {
sammi::deinit_gamestate_hook();
DeInitGameStateHook.call()
})?
.enable()?;
}
Ok(())
}
Expand Down
9 changes: 9 additions & 0 deletions src/game/offset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ pub const ROLLBACK_DELAY: Lazy<SigScan> = Lazy::new(|| {
))
});

pub const FN_DEINIT_GAMESTATE: Lazy<SigScan> = Lazy::new(|| {
SigScan::new_yara_style(concat!(
"83 3d ?? ?? ?? ?? ?? 74 ?? a1 ?? ?? ?? ?? 8b ?? ?? ?? ?? ?? 8b ?? ?? ?? ?? ?? ",
"c7 8? ?? ?? ?? ?? ?? ?? ?? ?? a1 ?? ?? ?? ?? 8b ?? ?? ?? ?? ?? 8b ?? ?? ?? ?? ?? ",
"c7 8? ?? ?? ?? ?? ?? ?? ?? ?? 8b ?? ?? ?? ?? ?? 5? 8b ?? 85 ?? 74 ?? e8 ?? ?? ?? ?? ",
"5? e8 ?? ?? ?? ?? 83 c? ?? c7 05 ?? ?? ?? ?? 00 00 00 00"
))
});

pub const ONLINE_MATCH_INFO: Offset = Offset::new(0x01737FC0);

pub const P1_REPLAY_STEAMID: Offset = Offset::new(0x19A23B0);
Expand Down
51 changes: 39 additions & 12 deletions src/sammi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};

use crate::{
game::offset::*,
global,
global::{self, MESSAGE_SENDER},
helpers::{read_type, Offset},
steam,
};
Expand All @@ -30,6 +30,7 @@ pub enum SammiMessage {
RoundStart,
RoundEnd(RoundEndInfo),
ComboEnd(ComboEndInfo),
StateDeInitialized,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
Expand Down Expand Up @@ -398,6 +399,16 @@ pub async fn message_handler(mut rx: tokio::sync::mpsc::Receiver<SammiMessage>)
config.timeout.abs() * 2.0,
);
}
SammiMessage::StateDeInitialized => {
let new_agent = agent.clone();

send_event(
new_agent,
"ggxrd_gamestateDeinitialized".into(),
"{}".into(),
config.timeout.abs() * 2.0,
);
}
};
}
}
Expand Down Expand Up @@ -427,7 +438,7 @@ pub unsafe fn game_loop_hook_sammi() {
return;
}

if !SAMMI_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
if !SAMMI_ENABLED.load(Ordering::Relaxed) {
return;
}

Expand Down Expand Up @@ -476,7 +487,7 @@ pub unsafe fn game_loop_hook_sammi() {
log::trace!("risc");
new_state.player_1.risc = gamestate.player_1().risc_meter();
new_state.player_2.risc = gamestate.player_2().risc_meter();

log::trace!("stun");
new_state.player_1.stun = gamestate.player_1().stun();
new_state.player_2.stun = gamestate.player_2().stun();
Expand Down Expand Up @@ -544,13 +555,13 @@ pub unsafe fn game_loop_hook_sammi() {
let tx = global::MESSAGE_SENDER.get().unwrap().clone();

// check ROUND_OVER to ensure RoundEnd isnt sent more than once per round
let round_over = ROUND_OVER.load(std::sync::atomic::Ordering::SeqCst);
let round_over = ROUND_OVER.load(Ordering::SeqCst);
if !round_over
&& (new_state.round_time_left == 0
|| new_state.player_1.health <= 0
|| new_state.player_2.health <= 0)
{
ROUND_OVER.store(true, std::sync::atomic::Ordering::SeqCst);
ROUND_OVER.store(true, Ordering::SeqCst);
let winner = if new_state.player_1.health > new_state.player_2.health {
Winner::Player1
} else if new_state.player_1.health < new_state.player_2.health {
Expand Down Expand Up @@ -648,7 +659,7 @@ pub unsafe fn game_loop_hook_sammi() {
}

pub unsafe fn round_begin() {
if !SAMMI_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
if !SAMMI_ENABLED.load(Ordering::Relaxed) {
return;
}

Expand All @@ -661,7 +672,7 @@ pub unsafe fn round_begin() {
}

pub unsafe fn create_object_with_arg_hook(object: *mut u8, arg: *mut u8, _ptr: *mut u8) {
if !SAMMI_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
if !SAMMI_ENABLED.load(Ordering::Relaxed) {
return;
}

Expand Down Expand Up @@ -703,7 +714,7 @@ pub unsafe fn create_object_with_arg_hook(object: *mut u8, arg: *mut u8, _ptr: *

// Must be called BEFORE the actual function runs and resets state.
pub unsafe fn end_combo_hook(object: *mut u8) {
if !SAMMI_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
if !SAMMI_ENABLED.load(Ordering::Relaxed) {
return;
}

Expand Down Expand Up @@ -754,10 +765,7 @@ struct HitEventInfoInternal {
static mut HIT_EVENT_INFO: Option<HitEventInfoInternal> = None;

pub unsafe fn process_hit_hook(attacker: *mut u8, victim: *mut u8) {
if !SAMMI_ENABLED.load(std::sync::atomic::Ordering::Relaxed)
|| attacker.is_null()
|| victim.is_null()
{
if !SAMMI_ENABLED.load(Ordering::Relaxed) || attacker.is_null() || victim.is_null() {
return;
}

Expand Down Expand Up @@ -793,3 +801,22 @@ pub unsafe fn process_hit_hook(attacker: *mut u8, victim: *mut u8) {
victim_id,
})
}

pub unsafe fn deinit_gamestate_hook() {
if !SAMMI_ENABLED.load(Ordering::Relaxed) {
return;
}

let gamestate = *(GAMESTATE_PTR.get_address() as *mut *mut u8);

// only send if the state is actually being deleted
if gamestate.is_null() {
return;
}

ROUND_OVER.store(true, Ordering::SeqCst);

let tx = global::MESSAGE_SENDER.get().unwrap().clone();

tx.blocking_send(SammiMessage::StateDeInitialized).unwrap();
}

0 comments on commit 515fce9

Please sign in to comment.