simtime isn't networked as a time.
it's 8 bits: ticks since a base thats the current tick rounded down to 100 (
when fakelagging, cmds all land at once, 15 in one packet, one server frame. until they land his simtime is frozen(normal, server hasnt seen our packets). the base moves every 100 ticks and
so it arrives as 0ms -> 62.5ms(spliced) -> 218.75ms(example values, these actually have high variance) instead of one clean 0ms -> 218.75ms. your client thinks the simulation was split in two(normal, you receive 2 different simtimes). it wasnt, the server ran it as one batch.
that matters because velocity for other players is estimated straight off the delta (
(as done in supremacy, along with every others hacks)
split in two it runs twice: once with time but no origin change, velocity 0. then the whole origin jump over the leftover slice, a huge velocity that never happened.
(you can try it yourself, print m_velocity.length( ), every 1.5~s your length will go == 0.f then jump)
wire-0 just means "hasnt simulated since the base", and the real update still arrives with the batch, so dropping it loses nothing:
and boom, chokes come through whole again: one update, one clean jump.
ps: some people(FATALITY, cough cough,! simon's favourite source to paste from) count lag off layer 11 (the alive loop) instead, stepping its cycle forward a tick at a time until it matches the new update's cycle. dont. the server rolls that layer with rng (
when it does match your choke thats coincidence: the batch updates the animstate once, m_flLastUpdateIncrement just happens to cover the same gap. one big step equals the 15 small ones. and that only lines up on builds past 2019, which simulate on the last tick instead of the oldest.
simtime with the fix gives you the tick count outright. and it has to be simtime, not server_tick: that one only ever counts up, while simtime goes backwards on anyone shifting their tickbase. you want to follow him there, not keep incrementing.
BONUS:
if you want to effectively check for animation updates, don't rely on simulation time, rely on animation layers
they are networked and cannot diverge from the server (apart from encoding for cycle)
so the following:
will always match when the server updates
it's 8 bits: ticks since a base thats the current tick rounded down to 100 (
GetNetworkBase).SendProxy_SimulationTime (
You must be registered for see links
):
C++:
int addt = 0;
if ( ticknumber >= tickbase ) // cant encode the past
addt = ( ticknumber - tickbase ) & 0xff;
pOut->m_Int = addt;
when fakelagging, cmds all land at once, 15 in one packet, one server frame. until they land his simtime is frozen(normal, server hasnt seen our packets). the base moves every 100 ticks and
SPROP_ENCODED_AGAINST_TICKCOUNT forces a repack when it does (
You must be registered for see links
), so if that happens mid choke his simtime is "the past" and you get sent 0. the client (
You must be registered for see links
) decodes 0 as "simulated right at the base tick".so it arrives as 0ms -> 62.5ms(spliced) -> 218.75ms(example values, these actually have high variance) instead of one clean 0ms -> 218.75ms. your client thinks the simulation was split in two(normal, you receive 2 different simtimes). it wasnt, the server ran it as one batch.
that matters because velocity for other players is estimated straight off the delta (
You must be registered for see links
):
C++:
float flTimeDelta = m_flSimulationTime - m_flOldSimulationTime;
Vector newVelo = ( GetNetworkOrigin() - GetOldOrigin() ) / flTimeDelta;
SetLocalVelocity( newVelo );
// supremacy does the following equivalent:
// record->m_velocity = ( record->m_origin - previous->m_origin ) * ( 1.f / game::TICKS_TO_TIME( record->m_lag ) );
(as done in supremacy, along with every others hacks)
split in two it runs twice: once with time but no origin change, velocity 0. then the whole origin jump over the leftover slice, a huge velocity that never happened.
(you can try it yourself, print m_velocity.length( ), every 1.5~s your length will go == 0.f then jump)
wire-0 just means "hasnt simulated since the base", and the real update still arrives with the batch, so dropping it loses nothing:
C++:
if ( !pData->m_Value.m_Int ) // fix segmenting of updates
return;
and boom, chokes come through whole again: one update, one clean jump.
ps: some people(FATALITY, cough cough,! simon's favourite source to paste from) count lag off layer 11 (the alive loop) instead, stepping its cycle forward a tick at a time until it matches the new update's cycle. dont. the server rolls that layer with rng (
SetUpAliveloop,
You must be registered for see links
): cycle starts at RandomFloat( 0, 1 ), rate re-rolls by RandomFloat( 0.8, 1.1 ) every time the sequence finishes, sequence changes on weapon switch. you cant replay random numbers, and when nothing matches those impls throw the whole record away, bones and all.when it does match your choke thats coincidence: the batch updates the animstate once, m_flLastUpdateIncrement just happens to cover the same gap. one big step equals the 15 small ones. and that only lines up on builds past 2019, which simulate on the last tick instead of the oldest.
simtime with the fix gives you the tick count outright. and it has to be simtime, not server_tick: that one only ever counts up, while simtime goes backwards on anyone shifting their tickbase. you want to follow him there, not keep incrementing.
BONUS:
if you want to effectively check for animation updates, don't rely on simulation time, rely on animation layers
they are networked and cannot diverge from the server (apart from encoding for cycle)
so the following:
C++:
if( stored_layer.m_sequence != cur_layer.m_sequence
|| stored_layer.m_weight != cur_layer.m_weight
|| stored_layer.m_weight_delta_rate != cur_layer.m_weight_delta_rate
|| stored_layer.m_cycle != cur_layer.m_cycle
|| stored_layer.m_playback_rate != cur_layer.m_playback_rate
) {
update = true;
}