1
0
Fork 0
mirror of https://codeberg.org/demostf/parser.git synced 2026-06-03 10:14:06 +02:00

heal target

This commit is contained in:
Robin Appelman 2025-06-28 20:57:52 +02:00
commit 5a7d4e12aa
4 changed files with 73 additions and 327 deletions

View file

@ -11,7 +11,7 @@ use crate::demo::vector::Vector;
use num_enum::TryFromPrimitive; use num_enum::TryFromPrimitive;
use parse_display::Display; use parse_display::Display;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap}; use std::collections::BTreeMap;
use std::ops::Rem; use std::ops::Rem;
#[derive(Default, Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, Hash, Display)] #[derive(Default, Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, Hash, Display)]
@ -106,6 +106,7 @@ pub enum PlayerClassData {
Medic { Medic {
charge: u8, charge: u8,
medigun: MedigunType, medigun: MedigunType,
target: Option<EntityId>,
}, },
Spy { Spy {
disguise_team: Team, disguise_team: Team,
@ -120,6 +121,7 @@ impl PlayerClassData {
Class::Medic => PlayerClassData::Medic { Class::Medic => PlayerClassData::Medic {
charge: 0, charge: 0,
medigun: MedigunType::Uber, medigun: MedigunType::Uber,
target: None,
}, },
Class::Spy => PlayerClassData::Spy { Class::Spy => PlayerClassData::Spy {
disguise_team: Team::Other, disguise_team: Team::Other,
@ -360,9 +362,18 @@ impl Building {
pub fn construction_progress(&self) -> f32 { pub fn construction_progress(&self) -> f32 {
match self { match self {
Building::Sentry(Sentry { construction_progress, .. }) Building::Sentry(Sentry {
| Building::Dispenser(Dispenser { construction_progress, .. }) construction_progress,
| Building::Teleporter(Teleporter { construction_progress, .. }) => *construction_progress, ..
})
| Building::Dispenser(Dispenser {
construction_progress,
..
})
| Building::Teleporter(Teleporter {
construction_progress,
..
}) => *construction_progress,
} }
} }
} }
@ -553,7 +564,6 @@ pub struct GameState {
pub tick: DemoTick, pub tick: DemoTick,
pub server_classes: Vec<ServerClass>, pub server_classes: Vec<ServerClass>,
pub interval_per_tick: f32, pub interval_per_tick: f32,
pub outer_map: HashMap<Handle, EntityId>,
pub events: Vec<(DemoTick, GameEvent)>, pub events: Vec<(DemoTick, GameEvent)>,
pub objectives: BTreeMap<EntityId, Objective>, pub objectives: BTreeMap<EntityId, Objective>,
} }

View file

@ -3,7 +3,8 @@ pub use crate::demo::data::game_state::{
Building, BuildingClass, Dispenser, GameState, Kill, PlayerState, Sentry, Teleporter, World, Building, BuildingClass, Dispenser, GameState, Kill, PlayerState, Sentry, Teleporter, World,
}; };
use crate::demo::data::game_state::{ use crate::demo::data::game_state::{
Cart, Handle, MedigunType, Objective, PipeType, PlayerClassData, Projectile, ProjectileType, Cart, Handle, MedigunType, Objective, PipeType, Player, PlayerClassData, Projectile,
ProjectileType,
}; };
use crate::demo::data::DemoTick; use crate::demo::data::DemoTick;
use crate::demo::gameevent_gen::ObjectDestroyedEvent; use crate::demo::gameevent_gen::ObjectDestroyedEvent;
@ -20,6 +21,7 @@ use crate::demo::parser::MessageHandler;
use crate::demo::sendprop::{SendProp, SendPropIdentifier, SendPropValue}; use crate::demo::sendprop::{SendProp, SendPropIdentifier, SendPropValue};
use crate::demo::vector::{Vector, VectorXY}; use crate::demo::vector::{Vector, VectorXY};
use crate::{MessageType, ParserState, ReadResult, Stream}; use crate::{MessageType, ParserState, ReadResult, Stream};
use std::collections::HashMap;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::str::FromStr; use std::str::FromStr;
@ -30,6 +32,8 @@ pub struct GameStateAnalyser {
pub state: GameState, pub state: GameState,
tick: DemoTick, tick: DemoTick,
class_names: Vec<ServerClassName>, // indexed by ClassId class_names: Vec<ServerClassName>, // indexed by ClassId
outer_map: HashMap<Handle, EntityId>,
outer_map_rev: HashMap<EntityId, Handle>,
} }
impl MessageHandler for GameStateAnalyser { impl MessageHandler for GameStateAnalyser {
@ -139,15 +143,18 @@ impl GameStateAnalyser {
pub fn handle_entity(&mut self, entity: &PacketEntity, parser_state: &ParserState) { pub fn handle_entity(&mut self, entity: &PacketEntity, parser_state: &ParserState) {
const OUTER: SendPropIdentifier = const OUTER: SendPropIdentifier =
SendPropIdentifier::new("DT_AttributeContainer", "m_hOuter"); SendPropIdentifier::new("DT_AttributeContainer", "m_hOuter");
const OUTER2: SendPropIdentifier =
SendPropIdentifier::new("DT_AttributeManager", "m_hOuter");
let Some(class_name) = self.class_names.get(usize::from(entity.server_class)) else { let Some(class_name) = self.class_names.get(usize::from(entity.server_class)) else {
return; return;
}; };
for prop in &entity.props { for prop in &entity.props {
if prop.identifier == OUTER { if prop.identifier == OUTER || prop.identifier == OUTER2 {
let outer = Handle::try_from(&prop.value).unwrap_or_default(); let outer = Handle::try_from(&prop.value).unwrap_or_default();
self.state.outer_map.insert(outer, entity.entity_index); self.outer_map.insert(outer, entity.entity_index);
self.outer_map_rev.insert(entity.entity_index, outer);
} }
} }
@ -365,6 +372,8 @@ impl GameStateAnalyser {
pub fn handle_medigun_entity(&mut self, entity: &PacketEntity, _parser_state: &ParserState) { pub fn handle_medigun_entity(&mut self, entity: &PacketEntity, _parser_state: &ParserState) {
const OUTER: SendPropIdentifier = const OUTER: SendPropIdentifier =
SendPropIdentifier::new("DT_AttributeContainer", "m_hOuter"); SendPropIdentifier::new("DT_AttributeContainer", "m_hOuter");
const TARGET: SendPropIdentifier =
SendPropIdentifier::new("DT_WeaponMedigun", "m_hHealingTarget");
if entity.update_type == UpdateType::Enter { if entity.update_type == UpdateType::Enter {
let mut ty = MedigunType::Uber; let mut ty = MedigunType::Uber;
@ -391,6 +400,23 @@ impl GameStateAnalyser {
} }
} }
} }
if let Some(target_handle) = entity.get_own_prop_value_by_identifier::<Handle>(TARGET) {
let target_id = self
.get_player_by_handle(target_handle)
.map(|target| target.entity);
let medic = self
.outer_map_rev
.get(&entity.entity_index)
.copied()
.and_then(|self_handle| self.get_player_by_weapon_handle(self_handle));
if let Some(medic) = medic {
if let PlayerClassData::Medic { target, .. } = &mut medic.class_data {
*target = target_id;
}
}
}
} }
pub fn handle_world_entity(&mut self, entity: &PacketEntity, parser_state: &ParserState) { pub fn handle_world_entity(&mut self, entity: &PacketEntity, parser_state: &ParserState) {
@ -558,7 +584,7 @@ impl GameStateAnalyser {
fn handle_building( fn handle_building(
&mut self, &mut self,
entity: &PacketEntity, entity: &PacketEntity,
parser_state: &ParserState, _parser_state: &ParserState,
class: BuildingClass, class: BuildingClass,
) { ) {
let building = self let building = self
@ -621,13 +647,21 @@ impl GameStateAnalyser {
construction_progress, construction_progress,
.. ..
}) => { }) => {
// picked up
if entity.update_type == UpdateType::Leave {
*health = 0;
}
for prop in &entity.props { for prop in &entity.props {
match prop.identifier { match prop.identifier {
LOCAL_ORIGIN => { LOCAL_ORIGIN => {
*position = Vector::try_from(&prop.value).unwrap_or_default() *position = Vector::try_from(&prop.value).unwrap_or_default()
} }
TEAM => *team = Team::new(i64::try_from(&prop.value).unwrap_or_default()), TEAM => *team = Team::new(i64::try_from(&prop.value).unwrap_or_default()),
ANGLE => *angle = f32::try_from(&prop.value).unwrap_or_default(), ANGLE => {
*angle = Vector::try_from(&prop.value)
.map(|v| v.y)
.unwrap_or_default()
}
SAPPED => *sapped = i64::try_from(&prop.value).unwrap_or_default() > 0, SAPPED => *sapped = i64::try_from(&prop.value).unwrap_or_default() > 0,
BUILDING => *building = i64::try_from(&prop.value).unwrap_or_default() > 0, BUILDING => *building = i64::try_from(&prop.value).unwrap_or_default() > 0,
LEVEL => *level = i64::try_from(&prop.value).unwrap_or_default() as u8, LEVEL => *level = i64::try_from(&prop.value).unwrap_or_default() as u8,
@ -795,4 +829,19 @@ impl GameStateAnalyser {
Ok(()) Ok(())
} }
fn get_player_by_weapon_handle(&mut self, handle: Handle) -> Option<&mut Player> {
self.state
.players
.iter_mut()
.find(|player| player.weapons.contains(&handle))
}
fn get_player_by_handle(&mut self, handle: Handle) -> Option<&mut Player> {
let entity_id = self.outer_map.get(&handle)?;
self.state
.players
.iter_mut()
.find(|player| player.entity == *entity_id)
}
} }

View file

@ -158,7 +158,8 @@ expression: state
"class_data": { "class_data": {
"Medic": { "Medic": {
"charge": 0, "charge": 0,
"medigun": "uber" "medigun": "uber",
"target": 8
} }
}, },
"simulation_time": 80, "simulation_time": 80,
@ -358,7 +359,8 @@ expression: state
"class_data": { "class_data": {
"Medic": { "Medic": {
"charge": 0, "charge": 0,
"medigun": "uber" "medigun": "uber",
"target": null
} }
}, },
"simulation_time": 87, "simulation_time": 87,
@ -5430,317 +5432,6 @@ expression: state
} }
], ],
"interval_per_tick": 0.015, "interval_per_tick": 0.015,
"outer_map": {
"8816": 624,
"14916": 580,
"14930": 594,
"23335": 807,
"25225": 649,
"29296": 624,
"29415": 743,
"31301": 581,
"31344": 624,
"37474": 610,
"37689": 825,
"59974": 582,
"68415": 831,
"84620": 652,
"86617": 601,
"90693": 581,
"96506": 250,
"101004": 652,
"103052": 652,
"111244": 652,
"116986": 250,
"123540": 660,
"143747": 387,
"156283": 635,
"162054": 262,
"186746": 378,
"189092": 676,
"194959": 399,
"195200": 640,
"197220": 612,
"203392": 640,
"207461": 613,
"209739": 843,
"211527": 583,
"240229": 613,
"240290": 674,
"260770": 674,
"266893": 653,
"268979": 691,
"287373": 653,
"289421": 653,
"291485": 669,
"293502": 638,
"295548": 636,
"297207": 247,
"297613": 653,
"303740": 636,
"309884": 636,
"313955": 611,
"315516": 124,
"316089": 697,
"328513": 833,
"330275": 547,
"332415": 639,
"334185": 361,
"336483": 611,
"346339": 227,
"350455": 247,
"350847": 639,
"366716": 124,
"369272": 632,
"379127": 247,
"381314": 386,
"381569": 641,
"383337": 361,
"385251": 227,
"391808": 640,
"393881": 665,
"404259": 803,
"420490": 650,
"422253": 365,
"424791": 855,
"455021": 365,
"457369": 665,
"461161": 361,
"479617": 385,
"483955": 627,
"494179": 611,
"506519": 663,
"522851": 611,
"529034": 650,
"531043": 611,
"531082": 650,
"539226": 602,
"543105": 385,
"545153": 385,
"555678": 670,
"574110": 670,
"576230": 742,
"582013": 381,
"617118": 670,
"656010": 650,
"672604": 860,
"676501": 661,
"680512": 576,
"684608": 576,
"684632": 600,
"692800": 576,
"696929": 609,
"702829": 365,
"705108": 596,
"719441": 593,
"723537": 593,
"727684": 644,
"733773": 589,
"733777": 593,
"735893": 661,
"750416": 848,
"754308": 644,
"754512": 848,
"766773": 821,
"780652": 364,
"785045": 661,
"805694": 830,
"820045": 845,
"827756": 364,
"828249": 857,
"838502": 870,
"844448": 672,
"850482": 562,
"856736": 672,
"856743": 679,
"879210": 618,
"883367": 679,
"887039": 255,
"901764": 644,
"924499": 851,
"928121": 377,
"932455": 615,
"934494": 606,
"942686": 606,
"942717": 637,
"958841": 377,
"969290": 586,
"971605": 853,
"977472": 576,
"983669": 629,
"983780": 740,
"989813": 629,
"991808": 576,
"993927": 647,
"1005945": 377,
"1008234": 618,
"1018110": 254,
"1026306": 258,
"1041021": 637,
"1041070": 686,
"1044728": 248,
"1057390": 622,
"1086047": 607,
"1088352": 864,
"1092206": 622,
"1096287": 607,
"1106168": 248,
"1127242": 842,
"1129022": 574,
"1131110": 614,
"1131308": 812,
"1131318": 822,
"1136892": 252,
"1141364": 628,
"1170045": 637,
"1180031": 383,
"1200380": 252,
"1200734": 606,
"1202425": 249,
"1206923": 651,
"1208908": 588,
"1218923": 363,
"1229397": 597,
"1233547": 651,
"1233595": 699,
"1241739": 651,
"1243381": 245,
"1251691": 363,
"1258069": 597,
"1270337": 577,
"1278549": 597,
"1278574": 622,
"1292651": 363,
"1292891": 603,
"1295007": 671,
"1296987": 603,
"1309323": 651,
"1311391": 671,
"1315401": 585,
"1325670": 614,
"1327691": 587,
"1335939": 643,
"1340008": 616,
"1352249": 569,
"1354129": 401,
"1360547": 675,
"1364817": 849,
"1366619": 603,
"1372816": 656,
"1378918": 614,
"1389348": 804,
"1403555": 675,
"1405584": 656,
"1423621": 261,
"1426152": 744,
"1464986": 666,
"1466984": 616,
"1472769": 257,
"1476987": 379,
"1477224": 616,
"1485416": 616,
"1487507": 659,
"1501862": 678,
"1507579": 251,
"1534630": 678,
"1542528": 384,
"1552635": 251,
"1557147": 667,
"1561243": 667,
"1571196": 380,
"1571478": 662,
"1571496": 680,
"1583683": 579,
"1587451": 251,
"1595620": 228,
"1596072": 680,
"1598107": 667,
"1598121": 681,
"1622589": 573,
"1632840": 584,
"1636736": 384,
"1640708": 260,
"1641307": 859,
"1643075": 579,
"1673864": 648,
"1678159": 847,
"1692506": 858,
"1694062": 366,
"1694275": 579,
"1710670": 590,
"1714299": 123,
"1714766": 590,
"1716477": 253,
"1729085": 573,
"1737086": 382,
"1755640": 504,
"1757830": 646,
"1757852": 668,
"1770328": 856,
"1782333": 573,
"1786675": 819,
"1800574": 382,
"1827450": 634,
"1852037": 645,
"1852226": 834,
"1854095": 655,
"1862000": 368,
"1866383": 655,
"1868431": 655,
"1878689": 673,
"1882509": 397,
"1882687": 575,
"1882731": 619,
"1888898": 642,
"1893016": 664,
"1895049": 649,
"1897112": 664,
"1899173": 677,
"1905215": 575,
"1907282": 594,
"1907312": 624,
"1909366": 630,
"1909409": 673,
"1915503": 623,
"1917551": 623,
"1925744": 624,
"1927810": 642,
"1936017": 657,
"1940133": 677,
"1940157": 701,
"1952113": 369,
"1952361": 617,
"1958250": 362,
"1958257": 369,
"1958552": 664,
"1968709": 581,
"1980662": 246,
"1985169": 657,
"1987177": 617,
"1987209": 649,
"1989257": 649,
"1991014": 358,
"1991237": 581,
"1997431": 631,
"2017860": 580,
"2026117": 645,
"2036553": 841,
"2042466": 610,
"2046583": 631,
"2054724": 580,
"2058820": 580,
"2062978": 642,
"2064640": 256,
"2069111": 631,
"2073170": 594,
"2077059": 387,
"2079332": 612,
"2081024": 256,
"2081413": 645,
"2085251": 387,
"2087543": 631,
"2089591": 631
},
"events": [], "events": [],
"objectives": {} "objectives": {}
} }

View file

@ -1770,10 +1770,6 @@ expression: state
} }
], ],
"interval_per_tick": 0.015, "interval_per_tick": 0.015,
"outer_map": {
"1645192": 648,
"1688201": 649
},
"events": [], "events": [],
"objectives": {} "objectives": {}
} }