fmt + CL_PreserveExistingEntity wip fix

This commit is contained in:
Robin Appelman 2025-05-02 19:25:18 +02:00
commit e95a9e4a2c
11 changed files with 139 additions and 49 deletions

View file

@ -1,6 +1,7 @@
use tf_demo_parser::demo::message::Message;
use tf_demo_parser::demo::message::usermessage::UserMessageType;
use crate::missing_preserve::RemoveInvalidPreserveEntity;
use crate::mutate::MutatorList;
use tf_demo_parser::demo::message::usermessage::UserMessageType;
use tf_demo_parser::demo::message::Message;
/// General cleanup we always want to do
pub fn clean_demo(mutators: &mut MutatorList) {
@ -11,4 +12,5 @@ pub fn clean_demo(mutators: &mut MutatorList) {
true
}
});
mutators.push_message_mutator(RemoveInvalidPreserveEntity::new());
}

View file

@ -1,9 +1,9 @@
use tf_demo_parser::demo::message::Message;
use tf_demo_parser::demo::message::packetentities::{EntityId, PacketEntity};
use tf_demo_parser::demo::sendprop::{SendPropIdentifier, SendPropValue};
use tf_demo_parser::ParserState;
use crate::mutate::MessageMutator;
use crate::MutatorList;
use tf_demo_parser::demo::message::packetentities::{EntityId, PacketEntity};
use tf_demo_parser::demo::message::Message;
use tf_demo_parser::demo::sendprop::{SendPropIdentifier, SendPropValue};
use tf_demo_parser::ParserState;
#[allow(dead_code)]
#[derive(Copy, Clone, Debug)]

View file

@ -1,13 +1,11 @@
use std::collections::{BTreeMap, BTreeSet};
use tf_demo_parser::demo::data::{DemoTick, ServerTick};
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::demo::sendprop::SendPropIdentifier;
use tf_demo_parser::ParserState;
#[derive(Default)]
@ -20,7 +18,12 @@ pub struct ActiveEntities {
}
impl ActiveEntities {
pub fn handle_message(&mut self, msg: &PacketEntitiesMessage, state: &ParserState, tick: DemoTick) {
pub fn handle_message(
&mut self,
msg: &PacketEntitiesMessage,
state: &ParserState,
tick: DemoTick,
) {
self.max_entities = self.max_entities.max(msg.max_entries);
for entity in &msg.entities {
self.removed_entities.remove(&entity.entity_index);
@ -160,7 +163,7 @@ impl ActiveEntities {
},
serial_number: 0,
delay: None,
delta: None
delta: None,
}))
.collect::<Vec<_>>(),
self.max_entities,

View file

@ -2,7 +2,7 @@ mod entity;
mod string_tables;
use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
use std::cmp::{min};
use std::cmp::min;
use std::collections::BTreeSet;
use std::convert::TryInto;
use std::iter::once;
@ -10,19 +10,18 @@ use std::mem::take;
use tf_demo_parser::demo::header::Header;
use tf_demo_parser::demo::message::packetentities::{EntityId, PacketEntitiesMessage, UpdateType};
use tf_demo_parser::demo::data::{DemoTick, ServerTick};
use tf_demo_parser::demo::message::{Message, NetTickMessage};
use tf_demo_parser::demo::packet::message::{MessagePacket};
use tf_demo_parser::demo::packet::message::MessagePacket;
use tf_demo_parser::demo::packet::stop::StopPacket;
use tf_demo_parser::demo::packet::{Packet, PacketType};
use tf_demo_parser::demo::parser::{DemoHandler, Encode, NullHandler, RawPacketStream};
use tf_demo_parser::{Demo, ParserState};
use tf_demo_parser::demo::data::{DemoTick, ServerTick};
use crate::cut::entity::ActiveEntities;
use crate::cut::string_tables::StringTablesUpdates;
use crate::mutate::MessageMutator;
use crate::{EditOptions, find_stv, PacketMutator};
use crate::{find_stv, EditOptions, PacketMutator};
const PRESERVE_PACKETS: &[PacketType] = &[
PacketType::Signon,
@ -78,10 +77,12 @@ pub fn cut(input: &[u8], options: EditOptions) -> Vec<u8> {
.encode()
.into_iter()
.map(|msg| Message::UpdateStringTable(msg));
let (baseline_updates, entity_update, removed_update) =
start_state
.entities
.encode(&start_handler.state_handler, delta_tick - 2, start_tick, &start_handler.state_handler);
let (baseline_updates, entity_update, removed_update) = start_state.entities.encode(
&start_handler.state_handler,
delta_tick - 2,
start_tick,
&start_handler.state_handler,
);
let baseline_updates = baseline_updates.into_iter().map(Message::PacketEntities);
let start_packets = string_table_updates
.chain(baseline_updates)
@ -105,7 +106,8 @@ pub fn cut(input: &[u8], options: EditOptions) -> Vec<u8> {
}
// create the net ticks needed for later deltas
let fill_ticks = (delta_tick + 1).range_inclusive(start_state.server_tick)
let fill_ticks = (delta_tick + 1)
.range_inclusive(start_state.server_tick)
.into_iter()
.map(|tick| net_tick(tick));
let fill_packets = fill_ticks.map(|msg| {

View file

@ -1,5 +1,5 @@
use std::collections::BTreeMap;
use tf_demo_parser::demo::message::stringtable::{UpdateStringTableMessage};
use tf_demo_parser::demo::message::stringtable::UpdateStringTableMessage;
use tf_demo_parser::demo::message::Message;
use tf_demo_parser::demo::packet::stringtable::StringTableEntry;

View file

@ -20,7 +20,10 @@ impl Args {
EditOptions {
unlock_pov: self.unlock_pov,
cut: if let (Some(from), Some(to)) = (self.from, self.to) {
Some(TickRange { from: from.into(), to: to.into() })
Some(TickRange {
from: from.into(),
to: to.into(),
})
} else {
None
},
@ -30,6 +33,7 @@ impl Args {
}
fn main() {
env_logger::init();
let args: Args = Args::parse();
let options = args.get_options();
let file = fs::read(&args.path).unwrap();

View file

@ -1,17 +1,18 @@
mod mutate;
mod pov;
mod clean;
mod cond;
mod cut;
pub mod missing_preserve;
mod mutate;
mod options;
mod pov;
use wasm_bindgen::prelude::*;
use tf_demo_parser::{Demo, DemoParser};
use tf_demo_parser::demo::header::Header;
use tf_demo_parser::demo::parser::{RawPacketStream, DemoHandler, Encode};
use tf_demo_parser::demo::packet::PacketType;
use bitbuffer::{BitRead, BitWriteStream, LittleEndian};
use tf_demo_parser::demo::header::Header;
use tf_demo_parser::demo::message::packetentities::EntityId;
use tf_demo_parser::demo::packet::PacketType;
use tf_demo_parser::demo::parser::{DemoHandler, Encode, RawPacketStream};
use tf_demo_parser::{Demo, DemoParser};
use wasm_bindgen::prelude::*;
use bitbuffer::BitWrite;
use tf_demo_parser::demo::data::DemoTick;
@ -20,7 +21,7 @@ use crate::clean::clean_demo;
use crate::cond::strip_cond;
use crate::cut::cut;
use crate::mutate::{MutatorList, PacketMutator};
pub use crate::options::{EditOptions, TickRange, CondOptions};
pub use crate::options::{CondOptions, EditOptions, TickRange};
use crate::pov::unlock_pov;
extern crate web_sys;
@ -92,7 +93,9 @@ fn no_cut(input: &[u8], options: EditOptions) -> Vec<u8> {
while let Some(mut packet) = packets.next(&handler.state_handler).unwrap() {
mutators.mutate_packet(&mut packet, &handler.state_handler);
if packet.packet_type() != PacketType::ConsoleCmd && packet.packet_type() != PacketType::UserCmd {
if packet.packet_type() != PacketType::ConsoleCmd
&& packet.packet_type() != PacketType::UserCmd
{
packet
.encode(&mut out_stream, &handler.state_handler)
.unwrap();
@ -106,6 +109,8 @@ fn no_cut(input: &[u8], options: EditOptions) -> Vec<u8> {
fn find_stv(demo: &Demo) -> Option<EntityId> {
let parser = DemoParser::new(demo.get_stream());
let (_, data) = parser.parse().expect("failed to parse demo");
data.users.values().find(|user| user.steam_id == "BOT")
data.users
.values()
.find(|user| user.steam_id == "BOT")
.map(|user| user.entity_id)
}

View file

@ -0,0 +1,71 @@
use crate::mutate::MessageMutator;
use log::{info, warn};
use std::cell::RefCell;
use std::collections::{BTreeMap, BTreeSet};
use tf_demo_parser::demo::message::packetentities::{EntityId, PacketEntity, UpdateType};
use tf_demo_parser::demo::message::Message;
use tf_demo_parser::demo::packet::datatable::{ClassId, ServerClass};
use tf_demo_parser::ParserState;
#[derive(Default)]
pub struct RemoveInvalidPreserveEntity {
known_entities: RefCell<BTreeSet<EntityId>>,
deferred_delete: RefCell<Vec<EntityId>>,
}
impl RemoveInvalidPreserveEntity {
pub fn new() -> RemoveInvalidPreserveEntity {
RemoveInvalidPreserveEntity::default()
}
}
impl MessageMutator for RemoveInvalidPreserveEntity {
fn mutate_message(&self, message: &mut Message, _state: &ParserState) {
if let Message::PacketEntities(ent_message) = message {
let deferred_deletes = self.deferred_delete.take();
for entity in ent_message.entities.iter() {
match entity.update_type {
UpdateType::Enter => {
self.known_entities.borrow_mut().insert(entity.entity_index);
}
UpdateType::Preserve => {
if !self.known_entities.borrow().contains(&entity.entity_index) {
warn!("preserving missing entity {}", entity.entity_index);
}
}
UpdateType::Delete => {
self.known_entities.borrow_mut().remove(&entity.entity_index);
},
_ => {}
};
}
ent_message.removed_entities.retain(|id| {
if self.known_entities.borrow().contains(&id) {
// just not deleting makes the demo play, but with some ERROR entities
// having a Delete or Leave makes it crash further in the demo
// warn!("inserting delete for {}", id);
// only entity_index and update_type is used
// ent_message.entities.push(PacketEntity {
// entity_index: *id,
// server_class: 0.into(),
// props: vec![],
// in_pvs: false,
// update_type: UpdateType::Leave,
// serial_number: 0,
// delay: None,
// delta: None,
// baseline_index: 0,
// });
// self.deferred_delete.borrow_mut().push(*id);
false
} else {
true
}
});
ent_message.entities.sort_by(|a, b| a.entity_index.cmp(&b.entity_index));
ent_message.removed_entities.extend(deferred_deletes);
ent_message.removed_entities.sort();
}
}
}

View file

@ -27,7 +27,7 @@ impl<T: MessageMutator> PacketMutator for PacketMessageMutator<T> {
.messages
.iter_mut()
.for_each(|msg| self.mutator.mutate_message(msg, state));
},
}
_ => {}
}
}
@ -114,4 +114,3 @@ impl PacketMutator for MutatorList {
}
}
}

View file

@ -1,7 +1,7 @@
use crate::{clean_demo, strip_cond, unlock_pov, MutatorList};
use serde::{Deserialize, Serialize};
use tf_demo_parser::demo::data::DemoTick;
use tf_demo_parser::demo::message::packetentities::EntityId;
use crate::{clean_demo, MutatorList, strip_cond, unlock_pov};
use serde::{Serialize, Deserialize};
use tf_demo_parser::demo::message::Message;
#[derive(Debug, Serialize, Deserialize, Default)]

View file

@ -1,10 +1,10 @@
use crate::mutate::{MessageMutator, MutatorList};
use std::cell::Cell;
use tf_demo_parser::demo::message::Message;
use tf_demo_parser::demo::message::packetentities::{EntityId, PacketEntity, UpdateType};
use tf_demo_parser::demo::message::usermessage::{UserMessage};
use tf_demo_parser::demo::message::usermessage::UserMessage;
use tf_demo_parser::demo::message::Message;
use tf_demo_parser::demo::packet::Packet;
use tf_demo_parser::ParserState;
use crate::mutate::{MessageMutator, MutatorList};
struct AddStvEntity {
added: Cell<bool>,
@ -25,7 +25,11 @@ impl MessageMutator for AddStvEntity {
if !self.added.get() {
if let Message::PacketEntities(ent_message) = message {
if ent_message.base_line == 0 {
let player_entity = ent_message.entities.iter().find(|ent| ent.entity_index >= 1 && ent.entity_index < 255).expect("Failed to find a player entity");
let player_entity = ent_message
.entities
.iter()
.find(|ent| ent.entity_index >= 1 && ent.entity_index < 255)
.expect("Failed to find a player entity");
if player_entity.entity_index == self.entity_index {
// already stv?
self.added.set(true);
@ -42,9 +46,11 @@ impl MessageMutator for AddStvEntity {
serial_number: 1234567,
delay: None,
delta: None,
baseline_index: 0
baseline_index: 0,
});
ent_message.entities.sort_by(|a, b| a.entity_index.cmp(&b.entity_index));
ent_message
.entities
.sort_by(|a, b| a.entity_index.cmp(&b.entity_index));
self.added.set(true);
}
}
@ -58,9 +64,7 @@ pub fn unlock_pov(mutators: &mut MutatorList, spectator_id: EntityId) {
info.player_slot = u32::from(spectator_id) as u8 - 1;
}
});
mutators.push_message_filter(|message: &Message| {
!matches!(message, Message::SetView(_))
});
mutators.push_message_filter(|message: &Message| !matches!(message, Message::SetView(_)));
mutators.push_message_filter(|message: &Message| {
!matches!(message, Message::UserMessage(UserMessage::VGuiMenu(_)))
});