diff --git a/src/entity.rs b/src/entity.rs index 50d8f32..a8d4177 100644 --- a/src/entity.rs +++ b/src/entity.rs @@ -1,9 +1,11 @@ use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::iter::once; use std::mem::replace; +use std::num::NonZeroU32; use tf_demo_parser::demo::message::packetentities::{ EntityId, PacketEntitiesMessage, PacketEntity, UpdateType, }; +use tf_demo_parser::demo::packet::datatable::ClassId; use tf_demo_parser::demo::sendprop::SendPropIdentifier; use tf_demo_parser::ParserState; @@ -11,12 +13,22 @@ use tf_demo_parser::ParserState; pub struct ActiveEntities { entities: BTreeMap, max_entities: u16, + deleted_entities: BTreeSet, + removed_entities: BTreeSet, } impl ActiveEntities { pub fn handle_message(&mut self, msg: &PacketEntitiesMessage, state: &ParserState) { self.max_entities = self.max_entities.max(msg.max_entries); for entity in &msg.entities { + self.removed_entities.remove(&entity.entity_index); + + if entity.update_type == UpdateType::Delete { + self.deleted_entities.insert(entity.entity_index); + } else { + self.deleted_entities.remove(&entity.entity_index); + } + if entity.update_type == UpdateType::Delete || entity.update_type == UpdateType::Leave { self.remove_entity(entity.entity_index); } else { @@ -25,6 +37,7 @@ impl ActiveEntities { } for deleted in msg.removed_entities.iter() { self.remove_entity(*deleted); + self.removed_entities.insert(*deleted); } } @@ -61,10 +74,23 @@ impl ActiveEntities { self.entities.keys().copied().collect() } + pub fn baseline_ids(&self, state: &ParserState) -> BTreeSet { + state.instance_baselines[0] + .keys() + .chain(state.instance_baselines[1].keys()) + .copied() + .collect() + } + pub fn encode( mut self, state: &ParserState, - ) -> impl IntoIterator { + delta: u32, + ) -> ( + impl IntoIterator, + PacketEntitiesMessage, + PacketEntitiesMessage, + ) { // baselines in reverse order let mut baselines = [ encode_entities( @@ -73,6 +99,8 @@ impl ActiveEntities { .into_values() .collect::>(), self.max_entities, + None, + Vec::new(), ), encode_entities( state.instance_baselines[0] @@ -80,31 +108,78 @@ impl ActiveEntities { .into_values() .collect::>(), self.max_entities, + None, + Vec::new(), ), ]; for entity in self.entities.values_mut() { - entity.update_type = UpdateType::Enter; + if state.instance_baselines[0].contains_key(&entity.entity_index) { + entity.update_type = UpdateType::Preserve; + } else { + entity.update_type = UpdateType::Enter; + } } + + // create deletes for all entities that have an updated baseline but are since removed + let removed_entities = self + .baseline_ids(state) + .into_iter() + .filter(|id| !self.entities.contains_key(id)) + .collect::>() + .into_iter(); + let entities = encode_entities( - self.entities.into_values().collect::>(), + self.entities + .into_values() + .chain(removed_entities.map(|removed| PacketEntity { + server_class: ClassId::from(0), + entity_index: removed, + baseline_props: vec![], + props: vec![], + in_pvs: false, + update_type: if self.deleted_entities.contains(&removed) { + UpdateType::Delete + } else { + UpdateType::Leave + }, + serial_number: 0, + delay: None, + })) + .collect::>(), self.max_entities, + Some(delta), + Vec::new(), ); baselines[0].updated_base_line = true; baselines[1].updated_base_line = true; baselines[1].base_line = 1; - baselines.into_iter().chain(once(entities)) + ( + baselines.into_iter(), + entities, + encode_entities( + Vec::new(), + self.max_entities, + Some(delta + 1), + self.removed_entities.into_iter().collect(), + ), + ) } } -fn encode_entities(mut entities: Vec, max_entries: u16) -> PacketEntitiesMessage { +fn encode_entities( + mut entities: Vec, + max_entries: u16, + delta: Option, + removed_entities: Vec, +) -> PacketEntitiesMessage { entities.sort_by(|a, b| a.entity_index.cmp(&b.entity_index)); PacketEntitiesMessage { entities, - removed_entities: vec![], + removed_entities, max_entries, - delta: None, + delta: delta.and_then(|delta| NonZeroU32::new(delta)), base_line: 0, updated_base_line: false, } diff --git a/src/lib.rs b/src/lib.rs index 693bfec..e9b92c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,12 +99,31 @@ pub fn cut(input: &[u8], start_tick: u32, end_tick: u32) -> Vec { .encode() .into_iter() .map(|msg| Message::UpdateStringTable(msg)); - let entity_updates = entities - .encode(&start_handler.state_handler) - .into_iter() - .map(Message::PacketEntities); - let start_packets = string_table_updates.chain(entity_updates).map(|msg| { - Packet::Message(MessagePacket { + let (baseline_updates, entity_update, removed_update) = + entities.encode(&start_handler.state_handler, delta_tick - 2); + let baseline_updates = baseline_updates.into_iter().map(Message::PacketEntities); + let start_packets = string_table_updates + .chain(baseline_updates) + .map(|msg| { + Packet::Message(MessagePacket { + tick: 0, + messages: vec![ + Message::NetTick(NetTickMessage { + tick: delta_tick - 2, + frame_time: 1881, + std_dev: 263, + }), + msg, + ], + meta: MessagePacketMeta { + flags: 0, + view_angles: Default::default(), + sequence_in: 0, + sequence_out: 0, + }, + }) + }) + .chain(once(Packet::Message(MessagePacket { tick: 0, messages: vec![ Message::NetTick(NetTickMessage { @@ -112,7 +131,7 @@ pub fn cut(input: &[u8], start_tick: u32, end_tick: u32) -> Vec { frame_time: 1881, std_dev: 263, }), - msg, + Message::PacketEntities(entity_update), ], meta: MessagePacketMeta { flags: 0, @@ -120,8 +139,24 @@ pub fn cut(input: &[u8], start_tick: u32, end_tick: u32) -> Vec { sequence_in: 0, sequence_out: 0, }, - }) - }); + }))) + .chain(once(Packet::Message(MessagePacket { + tick: 0, + messages: vec![ + Message::NetTick(NetTickMessage { + tick: delta_tick, + frame_time: 1881, + std_dev: 263, + }), + Message::PacketEntities(removed_update), + ], + meta: MessagePacketMeta { + flags: 0, + view_angles: Default::default(), + sequence_in: 0, + sequence_out: 0, + }, + }))); for packet in start_packets { packet .encode(&mut out_stream, &handler.state_handler) @@ -130,13 +165,15 @@ pub fn cut(input: &[u8], start_tick: u32, end_tick: u32) -> Vec { } // create the net ticks needed for later deltas - let fill_ticks = (delta_tick..=last_server_tick).into_iter().map(|tick| { - Message::NetTick(NetTickMessage { - tick, - frame_time: 1881, - std_dev: 263, - }) - }); + let fill_ticks = ((delta_tick + 1)..=last_server_tick) + .into_iter() + .map(|tick| { + Message::NetTick(NetTickMessage { + tick, + frame_time: 1881, + std_dev: 263, + }) + }); let fill_packets = fill_ticks.map(|msg| { Packet::Message(MessagePacket { tick: 0,