11pub use crate :: demo:: data:: game_state:: {
22 Building , BuildingClass , Dispenser , GameState , Kill , PlayerState , Sentry , Teleporter , World ,
33} ;
4+ use crate :: demo:: data:: game_state:: { Handle , PipeType , Projectile , ProjectileType } ;
45use crate :: demo:: data:: DemoTick ;
56use crate :: demo:: gameevent_gen:: ObjectDestroyedEvent ;
67use crate :: demo:: gamevent:: GameEvent ;
@@ -44,6 +45,10 @@ impl MessageHandler for GameStateAnalyser {
4445 for entity in & message. entities {
4546 self . handle_entity ( entity, parser_state) ;
4647 }
48+ for id in & message. removed_entities {
49+ self . state . projectile_destroy ( * id) ;
50+ self . state . remove_building ( * id) ;
51+ }
4752 }
4853 Message :: ServerInfo ( message) => {
4954 self . state . interval_per_tick = message. interval_per_tick
@@ -124,19 +129,32 @@ impl GameStateAnalyser {
124129 }
125130
126131 pub fn handle_entity ( & mut self , entity : & PacketEntity , parser_state : & ParserState ) {
127- let class_name: & str = self
128- . class_names
129- . get ( usize:: from ( entity. server_class ) )
130- . map ( |class_name| class_name. as_str ( ) )
131- . unwrap_or ( "" ) ;
132- match class_name {
132+ const OUTER : SendPropIdentifier =
133+ SendPropIdentifier :: new ( "DT_AttributeContainer" , "m_hOuter" ) ;
134+
135+ let Some ( class_name) = self . class_names . get ( usize:: from ( entity. server_class ) ) else {
136+ return ;
137+ } ;
138+
139+ for prop in & entity. props {
140+ if prop. identifier == OUTER {
141+ let outer = i64:: try_from ( & prop. value ) . unwrap_or_default ( ) ;
142+ self . state
143+ . outer_map
144+ . insert ( Handle ( outer) , entity. entity_index ) ;
145+ }
146+ }
147+
148+ match class_name. as_str ( ) {
133149 "CTFPlayer" => self . handle_player_entity ( entity, parser_state) ,
134150 "CTFPlayerResource" => self . handle_player_resource ( entity, parser_state) ,
135151 "CWorld" => self . handle_world_entity ( entity, parser_state) ,
136152 "CObjectSentrygun" => self . handle_sentry_entity ( entity, parser_state) ,
137153 "CObjectDispenser" => self . handle_dispenser_entity ( entity, parser_state) ,
138154 "CObjectTeleporter" => self . handle_teleporter_entity ( entity, parser_state) ,
139- _ if class_name. starts_with ( "CTFProjectile_" ) => {
155+ _ if class_name. starts_with ( "CTFProjectile_" )
156+ || class_name. as_str ( ) == "CTFGrenadePipebombProjectile" =>
157+ {
140158 self . handle_projectile_entity ( entity, parser_state)
141159 }
142160 _ => { }
@@ -213,6 +231,10 @@ impl GameStateAnalyser {
213231 const PROP_BB_MAX : SendPropIdentifier =
214232 SendPropIdentifier :: new ( "DT_CollisionProperty" , "m_vecMaxsPreScaled" ) ;
215233
234+ const WEAPON_0 : SendPropIdentifier = SendPropIdentifier :: new ( "m_hMyWeapons" , "000" ) ;
235+ const WEAPON_1 : SendPropIdentifier = SendPropIdentifier :: new ( "m_hMyWeapons" , "001" ) ;
236+ const WEAPON_2 : SendPropIdentifier = SendPropIdentifier :: new ( "m_hMyWeapons" , "002" ) ;
237+
216238 player. in_pvs = entity. in_pvs ;
217239
218240 for prop in entity. props ( parser_state) {
@@ -247,6 +269,18 @@ impl GameStateAnalyser {
247269 let max = Vector :: try_from ( & prop. value ) . unwrap_or_default ( ) ;
248270 player. bounds . max = max;
249271 }
272+ WEAPON_0 => {
273+ let handle = Handle ( i64:: try_from ( & prop. value ) . unwrap_or_default ( ) ) ;
274+ player. weapons [ 0 ] = handle;
275+ }
276+ WEAPON_1 => {
277+ let handle = Handle ( i64:: try_from ( & prop. value ) . unwrap_or_default ( ) ) ;
278+ player. weapons [ 1 ] = handle;
279+ }
280+ WEAPON_2 => {
281+ let handle = Handle ( i64:: try_from ( & prop. value ) . unwrap_or_default ( ) ) ;
282+ player. weapons [ 2 ] = handle;
283+ }
250284 _ => { }
251285 }
252286 }
@@ -501,6 +535,10 @@ impl GameStateAnalyser {
501535 }
502536
503537 pub fn handle_projectile_entity ( & mut self , entity : & PacketEntity , parser_state : & ParserState ) {
538+ let Some ( class_name) = self . class_names . get ( usize:: from ( entity. server_class ) ) else {
539+ return ;
540+ } ;
541+
504542 const ROCKET_ORIGIN : SendPropIdentifier =
505543 SendPropIdentifier :: new ( "DT_TFBaseRocket" , "m_vecOrigin" ) ; // rockets, arrows, more?
506544 const GRENADE_ORIGIN : SendPropIdentifier =
@@ -509,34 +547,62 @@ impl GameStateAnalyser {
509547 const TEAM : SendPropIdentifier = SendPropIdentifier :: new ( "DT_BaseEntity" , "m_iTeamNum" ) ;
510548 const INITIAL_SPEED : SendPropIdentifier =
511549 SendPropIdentifier :: new ( "DT_TFBaseRocket" , "m_vInitialVelocity" ) ;
550+ const LAUNCHER : SendPropIdentifier =
551+ SendPropIdentifier :: new ( "DT_BaseProjectile" , "m_hOriginalLauncher" ) ;
552+ const PIPE_TYPE : SendPropIdentifier =
553+ SendPropIdentifier :: new ( "DT_TFProjectile_Pipebomb" , "m_iType" ) ;
554+ const ROCKET_ROTATION : SendPropIdentifier =
555+ SendPropIdentifier :: new ( "DT_TFBaseRocket" , "m_angRotation" ) ;
556+ const GRENADE_ROTATION : SendPropIdentifier =
557+ SendPropIdentifier :: new ( "DT_TFWeaponBaseGrenadeProj" , "m_angRotation" ) ;
512558
513- if entity. in_pvs {
514- let projectile = self
515- . state
516- . get_or_create_projectile ( entity . entity_index , entity . server_class ) ;
559+ if entity. update_type == UpdateType :: Delete {
560+ self . state . projectile_destroy ( entity . entity_index ) ;
561+ return ;
562+ }
517563
518- // todo: bounds for grenades
519- // todo: track owner
564+ let projectile = self
565+ . state
566+ . projectiles
567+ . entry ( entity. entity_index )
568+ . or_insert_with ( || {
569+ Projectile :: new ( entity. entity_index , entity. server_class , class_name)
570+ } ) ;
520571
521- for prop in entity. props ( parser_state) {
522- match prop. identifier {
523- ROCKET_ORIGIN | GRENADE_ORIGIN => {
524- let pos = Vector :: try_from ( & prop. value ) . unwrap_or_default ( ) ;
525- projectile. position = pos
526- }
527- TEAM => {
528- let team = Team :: new ( i64:: try_from ( & prop. value ) . unwrap_or_default ( ) ) ;
529- projectile. team = team;
530- }
531- INITIAL_SPEED => {
532- let speed = Vector :: try_from ( & prop. value ) . unwrap_or_default ( ) ;
533- projectile. speed = speed;
572+ // todo: bounds for grenades
573+
574+ for prop in entity. props ( parser_state) {
575+ match prop. identifier {
576+ ROCKET_ORIGIN | GRENADE_ORIGIN => {
577+ let pos = Vector :: try_from ( & prop. value ) . unwrap_or_default ( ) ;
578+ projectile. position = pos
579+ }
580+ TEAM => {
581+ let team = Team :: new ( i64:: try_from ( & prop. value ) . unwrap_or_default ( ) ) ;
582+ projectile. team = team;
583+ }
584+ INITIAL_SPEED => {
585+ let speed = Vector :: try_from ( & prop. value ) . unwrap_or_default ( ) ;
586+ projectile. initial_speed = speed;
587+ }
588+ LAUNCHER => {
589+ let launcher = Handle ( i64:: try_from ( & prop. value ) . unwrap_or_default ( ) ) ;
590+ projectile. launcher = launcher;
591+ }
592+ PIPE_TYPE => {
593+ let pipe_type = PipeType :: new ( i64:: try_from ( & prop. value ) . unwrap_or_default ( ) ) ;
594+ if let Some ( class_name) = self . class_names . get ( usize:: from ( entity. server_class ) )
595+ {
596+ let ty = ProjectileType :: new ( class_name, Some ( pipe_type) ) ;
597+ projectile. ty = ty;
534598 }
535- _ => { }
536599 }
600+ ROCKET_ROTATION | GRENADE_ROTATION => {
601+ let rotation = Vector :: try_from ( & prop. value ) . unwrap_or_default ( ) ;
602+ projectile. rotation = rotation;
603+ }
604+ _ => { }
537605 }
538- } else {
539- self . state . projectile_destroy ( entity. entity_index ) ;
540606 }
541607 }
542608
0 commit comments