mirror of
https://codeberg.org/demostf/edit.git
synced 2026-10-01 07:34:05 +02:00
player count fix wip
This commit is contained in:
parent
405c286b42
commit
04790ad6f4
9 changed files with 403 additions and 335 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -9,3 +9,4 @@ out.dem
|
|||
result
|
||||
dist
|
||||
node_modules
|
||||
*.txt
|
||||
595
wasm/Cargo.lock
generated
595
wasm/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -17,9 +17,9 @@ default = ["console_error_panic_hook"]
|
|||
cli = ["clap", "env_logger", "typed-builder"]
|
||||
|
||||
[dependencies]
|
||||
bitbuffer = "0.11.1"
|
||||
tf-demo-parser = { version = "0.6" }
|
||||
#tf-demo-parser = { version = "0.4", path = "../tf-demo-parser" }
|
||||
bitbuffer = "0.11.3"
|
||||
#tf-demo-parser = { version = "0.6" }
|
||||
tf-demo-parser = { version = "0.7", path = "../../tf-demo-parser", features = ["write"] }
|
||||
wasm-bindgen = { version = "0.2.45" }
|
||||
serde-wasm-bindgen = "0.6.5"
|
||||
web-sys = { version = "0.3", features = ["console"] }
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ impl ActiveEntities {
|
|||
for entity in self.entities.values_mut() {
|
||||
match state.instance_baselines[0].get(entity.entity_index) {
|
||||
Some(baseline_entity) if baseline_entity.server_class == entity.server_class => {
|
||||
entity.update_type = UpdateType::Preserve;
|
||||
entity.update_type = UpdateType::Delta;
|
||||
}
|
||||
Some(_baseline_entity) => {
|
||||
// encode the baseline if the baseline server class differs
|
||||
|
|
|
|||
|
|
@ -15,13 +15,16 @@ struct Args {
|
|||
to: Option<u32>,
|
||||
#[arg(long)]
|
||||
remove_invalid_deletes: bool,
|
||||
#[arg(long)]
|
||||
fix_player_count: bool,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
fn get_options(&self) -> EditOptions {
|
||||
let builder = EditOptions::builder()
|
||||
.unlock_pov(self.unlock_pov)
|
||||
.remove_invalid_deletes(self.remove_invalid_deletes);
|
||||
.remove_invalid_deletes(self.remove_invalid_deletes)
|
||||
.fix_player_count(self.fix_player_count);
|
||||
if let (Some(from), Some(to)) = (self.from, self.to) {
|
||||
builder.cut(TickRange {
|
||||
from: from.into(),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ pub mod missing_preserve;
|
|||
mod mutate;
|
||||
mod options;
|
||||
mod pov;
|
||||
mod player_count;
|
||||
|
||||
use bitbuffer::{BitRead, BitWriteStream, LittleEndian};
|
||||
use tf_demo_parser::demo::header::Header;
|
||||
|
|
@ -88,19 +89,23 @@ fn no_cut(input: &[u8], options: EditOptions) -> Vec<u8> {
|
|||
let mut handler = DemoHandler::default();
|
||||
handler.handle_header(&header);
|
||||
|
||||
let mut output_handler = DemoHandler::default();
|
||||
output_handler.handle_header(&header);
|
||||
|
||||
let mutators = options.as_mutator(spectator_id);
|
||||
|
||||
while let Some(mut packet) = packets.next(&handler.state_handler).unwrap() {
|
||||
handler.handle_packet(packet.clone()).expect("failed to handle source packet");
|
||||
mutators.mutate_packet(&mut packet, &handler.state_handler);
|
||||
output_handler.handle_packet(packet.clone()).expect("failed to handle mutated packet");
|
||||
|
||||
if packet.packet_type() != PacketType::ConsoleCmd
|
||||
&& packet.packet_type() != PacketType::UserCmd
|
||||
{
|
||||
packet
|
||||
.encode(&mut out_stream, &handler.state_handler)
|
||||
.encode(&mut out_stream, &output_handler.state_handler)
|
||||
.unwrap();
|
||||
}
|
||||
handler.handle_packet(packet).unwrap();
|
||||
}
|
||||
}
|
||||
out_buffer
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ impl MessageMutator for RemoveInvalidPreserveEntity {
|
|||
UpdateType::Enter => {
|
||||
self.known_entities.borrow_mut().insert(entity.entity_index);
|
||||
}
|
||||
UpdateType::Preserve => {
|
||||
UpdateType::Delta => {
|
||||
if !self.known_entities.borrow().contains(&entity.entity_index) {
|
||||
warn!("preserving missing entity {}", entity.entity_index);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
|
|||
use tf_demo_parser::demo::data::DemoTick;
|
||||
use tf_demo_parser::demo::message::packetentities::EntityId;
|
||||
use tf_demo_parser::demo::message::Message;
|
||||
use crate::player_count::fix_player_count;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
#[non_exhaustive]
|
||||
|
|
@ -20,6 +21,9 @@ pub struct EditOptions {
|
|||
#[serde(default)]
|
||||
#[cfg_attr(feature = "cli", builder(default))]
|
||||
pub remove_invalid_deletes: bool,
|
||||
#[serde(default)]
|
||||
#[cfg_attr(feature = "cli", builder(default))]
|
||||
pub fix_player_count: bool,
|
||||
}
|
||||
|
||||
impl EditOptions {
|
||||
|
|
@ -51,6 +55,10 @@ impl EditOptions {
|
|||
removed_invalid_deletes(&mut mutators);
|
||||
}
|
||||
|
||||
if self.fix_player_count {
|
||||
fix_player_count(&mut mutators);
|
||||
}
|
||||
|
||||
mutators
|
||||
}
|
||||
}
|
||||
|
|
|
|||
120
wasm/src/player_count.rs
Normal file
120
wasm/src/player_count.rs
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
use crate::mutate::{MutatorList, PacketMutator};
|
||||
use tf_demo_parser::demo::packet::Packet;
|
||||
use tf_demo_parser::ParserState;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PlayerCount {}
|
||||
|
||||
/// property arrays that got renamed and new items
|
||||
const PLAYER_ARRAY_PROPS_RENAMED: &[(&str, u16, u16)] = &[
|
||||
("m_aBonusPlayerRoll_33", 33, 101),
|
||||
("m_ConditionData_128", 128, 131),
|
||||
];
|
||||
|
||||
/// property arrays that just got new items
|
||||
const PLAYER_ARRAY_PROPS: &[(&str, u16)] = &[
|
||||
("m_iPing", 101),
|
||||
("m_iScore", 101),
|
||||
("m_iDeaths", 101),
|
||||
("m_bConnected", 101),
|
||||
("m_iTeam", 101),
|
||||
("m_bAlive", 101),
|
||||
("m_iHealth", 101),
|
||||
("m_iAccountID", 101),
|
||||
("m_bValid", 101),
|
||||
("m_iUserID", 101),
|
||||
("m_bPlayerReady", 101),
|
||||
("m_ePlayerWantsRematch", 101),
|
||||
("m_bPlayerIsPackMember", 101),
|
||||
("m_bPlayerDominated", 101),
|
||||
("m_bPlayerDominatingMe", 101),
|
||||
("m_iTotalScore", 101),
|
||||
("m_iMaxHealth", 101),
|
||||
("m_iMaxBuffedHealth", 101),
|
||||
("m_iPlayerClass", 101),
|
||||
("m_bArenaSpectator", 101),
|
||||
("m_iActiveDominations", 101),
|
||||
("m_flNextRespawnTime", 101),
|
||||
("m_iChargeLevel", 101),
|
||||
("m_iDamage", 101),
|
||||
("m_iDamageAssist", 101),
|
||||
("m_iDamageBoss", 101),
|
||||
("m_iHealing", 101),
|
||||
("m_iHealingAssist", 101),
|
||||
("m_iDamageBlocked", 101),
|
||||
("m_iCurrencyCollected", 101),
|
||||
("m_iBonusPoints", 101),
|
||||
("m_iPlayerLevel", 101),
|
||||
("m_iUpgradeRefundCredits", 101),
|
||||
("m_iBuybackCredits", 101),
|
||||
("m_iPlayerClassWhenKilled", 101),
|
||||
("m_iConnectionState", 101),
|
||||
("m_flConnectTime", 101),
|
||||
("m_iStreaks", 407),
|
||||
];
|
||||
|
||||
// property values that got changed
|
||||
const PLAYER_PROPS_VALUES: &[(&str, &str, u16, u16)] = &[
|
||||
("DT_ObjectDispenser", r#""healing_array""#, 33, 101),
|
||||
("DT_Team", r#""player_array""#, 33, 101),
|
||||
("DT_TFTeam", r#""team_object_array""#, 198, 606),
|
||||
];
|
||||
|
||||
impl PacketMutator for PlayerCount {
|
||||
fn mutate_packet(&self, packet: &mut Packet, _state: &ParserState) {
|
||||
if let Packet::DataTables(data_tables) = packet {
|
||||
for table in &mut data_tables.tables {
|
||||
let table_name = table.name.as_str();
|
||||
if let Some(new_length) = PLAYER_ARRAY_PROPS.iter().copied().find_map(|(name, new_length)| (name == table_name).then_some(new_length)) {
|
||||
let base = table.props.last().unwrap().clone();
|
||||
let old_length = table.props.len() as u16;
|
||||
for i in old_length ..= new_length {
|
||||
let mut prop = base.clone();
|
||||
prop.name = format!("{i:03}").into();
|
||||
table.props.push(prop);
|
||||
}
|
||||
} else if let Some((old_length, new_length)) = PLAYER_ARRAY_PROPS_RENAMED.iter().copied().find_map(|(name, old_length, new_length)| table_name.ends_with(name).then_some((old_length, new_length))) {
|
||||
if table_name.starts_with("_ST_") {
|
||||
let base = table.props.last().unwrap().clone();
|
||||
for i in old_length.. new_length { // non-inclusive range, because for some reasons these arrays are one short
|
||||
let mut prop = base.clone();
|
||||
prop.name = format!("{i:03}").into();
|
||||
table.props.push(prop);
|
||||
}
|
||||
} else if table_name.starts_with("_LPT_") {
|
||||
table.props[0].name = format!("lengthprop{new_length}").into();
|
||||
}
|
||||
let name_prefix = table_name.rsplit_once('_').unwrap().0;
|
||||
table.name = format!("{name_prefix}_{}", new_length).into();
|
||||
} else if let Some((prop_name, _, new_length)) = PLAYER_PROPS_VALUES.iter().copied().find_map(|(name, prop_name, old_length, new_length)| table_name.eq(name).then_some((prop_name, old_length, new_length))) {
|
||||
for prop in &mut table.props {
|
||||
if prop.name == prop_name {
|
||||
prop.element_count = new_length.into();
|
||||
}
|
||||
}
|
||||
}
|
||||
for prop in &mut table.props {
|
||||
if let Some(target_name) = &mut prop.table_name {
|
||||
if let Some((_, new_length)) = PLAYER_ARRAY_PROPS_RENAMED.iter().copied().find_map(|(name, old_length, new_length)| target_name.ends_with(name).then_some((old_length, new_length))) {
|
||||
let name_prefix = target_name.rsplit_once('_').unwrap().0;
|
||||
*target_name = format!("{name_prefix}_{}", new_length).into();
|
||||
}
|
||||
}
|
||||
}
|
||||
// let table_name = table.name.as_str();
|
||||
// for prop in &mut table.props {
|
||||
// println!(
|
||||
// "{}.{}: {}",
|
||||
// table_name,
|
||||
// prop.name,
|
||||
// prop.element_count.unwrap_or_default()
|
||||
// );
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fix_player_count(mutators: &mut MutatorList) {
|
||||
mutators.push_packet_mutator(PlayerCount::default())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue