use super::*;
use crate::Game;
use crate::test_support::edicts::{
edict_table, set_change_accessor, set_shared_change_info, take_flag_changes,
};
use crate::test_support::sdk_core::change_tracking_engine;
use sdk_raw::edicts::{FL_EDICT_CHANGED, FL_EDICT_FULL, FL_FULL_EDICT_CHANGED, MAX_EDICTS};
use sdk_raw::test_support::edicts::mock_edict;
use std::ptr::null_mut;
#[test]
fn reads_the_cached_index_and_free_flag() {
let mut table = edict_table(3, |slot| slot == 1);
let base = table.as_mut_ptr();
let edict = |slot: usize| unsafe { Edict::from_raw(NonNull::new(base.add(slot)).unwrap()) };
assert_eq!(edict(0).index(), 0);
assert_eq!(edict(2).index(), 2);
assert!(!edict(0).is_free());
assert!(edict(1).is_free());
assert_eq!(edict(1).entity(), None);
assert_eq!(edict(0).class_name(), None);
}
#[test]
fn setting_the_transmit_state_keeps_the_other_flags() {
let engine = change_tracking_engine();
let mut slot = mock_edict(6, false);
slot._base.m_fStateFlags = FL_EDICT_FULL | FL_EDICT_CHANGED | FL_EDICT_ALWAYS;
let edict = unsafe { Edict::from_raw(NonNull::from(&mut slot)) };
take_flag_changes();
assert_eq!(edict.transmit_state(), TransmitState::Always);
edict.set_transmit_state(engine, TransmitState::PvsCheck);
assert_eq!(edict.transmit_state(), TransmitState::PvsCheck);
assert_eq!(
slot._base.m_fStateFlags,
FL_EDICT_FULL | FL_EDICT_CHANGED | FL_EDICT_PVSCHECK
);
assert_eq!(take_flag_changes(), []);
edict.set_transmit_state(engine, TransmitState::DontSend);
edict.set_transmit_state(engine, TransmitState::DontSend);
assert_eq!(take_flag_changes(), [6]);
edict.set_transmit_state(engine, TransmitState::FullCheck);
assert_eq!(slot._base.m_fStateFlags, FL_EDICT_FULL | FL_EDICT_CHANGED);
assert_eq!(take_flag_changes(), [6]);
let mut free = mock_edict(7, true);
let flags = free._base.m_fStateFlags;
let edict = unsafe { Edict::from_raw(NonNull::from(&mut free)) };
edict.set_transmit_state(engine, TransmitState::DontSend);
assert_eq!(free._base.m_fStateFlags, flags);
assert_eq!(take_flag_changes(), []);
}
#[test]
fn state_changes_reach_the_engines_change_tracking() {
let engine = change_tracking_engine();
let mut accessor = sys::IChangeInfoAccessor {
m_iChangeInfo: 0,
m_iChangeInfoSerialNumber: 0,
};
let mut shared = Box::new(unsafe { std::mem::zeroed::<sys::CSharedEdictChangeInfo>() });
shared.m_iSerialNumber = 7;
shared.m_nChangeInfos = 3;
set_change_accessor(&raw mut accessor);
set_shared_change_info(&raw mut *shared);
let mut slot = mock_edict(4, false);
let edict = unsafe { Edict::from_raw(NonNull::from(&mut slot)) };
edict.state_changed(engine, 40);
assert_eq!(slot._base.m_fStateFlags, FL_EDICT_CHANGED);
assert_eq!(
(accessor.m_iChangeInfo, accessor.m_iChangeInfoSerialNumber),
(3, 7)
);
assert_eq!(shared.m_nChangeInfos, 4);
assert_eq!(shared.m_ChangeInfos[3].m_nChangeOffsets, 1);
assert_eq!(shared.m_ChangeInfos[3].m_ChangeOffsets[0], 40);
edict.full_state_changed(engine);
assert_eq!(
slot._base.m_fStateFlags,
FL_EDICT_CHANGED | FL_FULL_EDICT_CHANGED
);
assert_eq!(accessor.m_iChangeInfoSerialNumber, 0);
set_change_accessor(null_mut());
set_shared_change_info(null_mut());
let mut slot = mock_edict(5, false);
let edict = unsafe { Edict::from_raw(NonNull::from(&mut slot)) };
edict.state_changed(engine, 40);
assert_eq!(
slot._base.m_fStateFlags,
FL_EDICT_CHANGED | FL_FULL_EDICT_CHANGED
);
}
#[test]
fn transmit_checks_read_the_client_and_the_edicts_sent() {
let mut client = mock_edict(1, false);
let mut sent = [0_u32; MAX_EDICTS as usize / 32];
sent[0] = 1 << 1 | 1 << 9;
sent[2] = 1 << 4;
let mut info: Box<sys::CCheckTransmitInfo> = Box::new(unsafe { std::mem::zeroed() });
info.m_pClientEnt = &raw mut client;
info.m_pTransmitEdict = sent.as_mut_ptr().cast();
let scope = ();
let server = crate::test_support::server::null_server(Game::TeamFortress2, &scope);
let check = unsafe { TransmitCheck::from_live(server, NonNull::from(&mut *info)) };
assert_eq!(check.client().map(Edict::index), Some(1));
assert!(check.is_sent(1));
assert!(check.is_sent(9));
assert!(check.is_sent(68));
assert!(!check.is_sent(2));
assert!(!check.is_sent(MAX_EDICTS));
info.m_pClientEnt = null_mut();
info.m_pTransmitEdict = null_mut();
assert_eq!(check.client(), None);
assert!(!check.is_sent(1));
}
#[test]
fn transmit_states_are_read_as_the_game_checks_them() {
use TransmitState::*;
for (flags, state) in [
(0, FullCheck),
(FL_EDICT_FULL | FL_EDICT_CHANGED, FullCheck),
(FL_EDICT_ALWAYS, Always),
(FL_EDICT_PVSCHECK, PvsCheck),
(FL_EDICT_DONTSEND, DontSend),
(FL_EDICT_DONTSEND | FL_EDICT_ALWAYS, DontSend),
(FL_EDICT_ALWAYS | FL_EDICT_PVSCHECK, Always),
] {
assert_eq!(TransmitState::from_flags(flags), state, "{flags:#x}");
assert_eq!(TransmitState::from_flags(state.flag()), state);
}
}