mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 10:14:06 +02:00
player condition handling
This commit is contained in:
parent
fb51874315
commit
809d2504f5
7 changed files with 499 additions and 4 deletions
141
src/demo/data/cond.rs
Normal file
141
src/demo/data/cond.rs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
use num_enum::TryFromPrimitive;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, TryFromPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum PlayerCondition {
|
||||
Aiming = 0,
|
||||
Zoomed = 1,
|
||||
Disguising = 2,
|
||||
Disguised = 3,
|
||||
Stealthed = 4,
|
||||
Invulnerable = 5,
|
||||
Teleported = 6,
|
||||
Taunting = 7,
|
||||
InvulnerableWearingOff = 8,
|
||||
StealthedBlink = 9,
|
||||
SelectedToTeleport = 10,
|
||||
CritBoosted = 11,
|
||||
TmpDamageBonus = 12,
|
||||
FeignDeath = 13,
|
||||
Phase = 14,
|
||||
Stunned = 15,
|
||||
OffensiveBuff = 16,
|
||||
ShieldCharge = 17,
|
||||
DemoBuff = 18,
|
||||
EnergyBuff = 19,
|
||||
RadiusHeal = 20,
|
||||
HealthBuff = 21,
|
||||
Burning = 22,
|
||||
HealthOverHealed = 23,
|
||||
Urine = 24,
|
||||
Bleeding = 25,
|
||||
DefensiveBuff = 26,
|
||||
MadMilk = 27,
|
||||
MegaHeal = 28,
|
||||
RegenOnDamageBuff = 29,
|
||||
MarkedForDeath = 30,
|
||||
NoHealingDamageBuff = 31,
|
||||
SpeedBoost = 32,
|
||||
CritBoostedPumpkin = 33,
|
||||
CritBoostedUserBuff = 34,
|
||||
CritBoostedDemoCharge = 35,
|
||||
SodaPopperHype = 36,
|
||||
CritBoostedFirstBlood = 37,
|
||||
CritBoostedBonusTime = 38,
|
||||
CritBoostedCtfCapture = 39,
|
||||
CritBoostedOnKill = 40,
|
||||
CannotSwitchFromMelee = 41,
|
||||
DefenseBuffNoCritBlock = 42,
|
||||
Reprogrammed = 43,
|
||||
CritBoostedRageBuff = 44,
|
||||
DefenseBuffHigh = 45,
|
||||
SniperChargeRageBuff = 46,
|
||||
DisguiseWearingOff = 47,
|
||||
MarkedForDeathSilent = 48,
|
||||
DisguisedAsDispenser = 49,
|
||||
Sapped = 50,
|
||||
InvulnerableHideUnlessDamaged = 51,
|
||||
InvulnerableUserBuff = 52,
|
||||
HalloweenBombHead = 53,
|
||||
HalloweenThriller = 54,
|
||||
RadiusHealOnDamage = 55,
|
||||
CritBoostedCardEffect = 56,
|
||||
InvulnerableCardEffect = 57,
|
||||
MedigunUberBulletResist = 58,
|
||||
MedigunUberBlastResist = 59,
|
||||
MedigunUberFireResist = 60,
|
||||
MedigunSmallBulletResist = 61,
|
||||
MedigunSmallBlastResist = 62,
|
||||
MedigunSmallFireResist = 63,
|
||||
StealthedUserBuff = 64,
|
||||
MedigunDebuff = 65,
|
||||
StealthedUserBuffFading = 66,
|
||||
BulletImmune = 67,
|
||||
BlastImmune = 68,
|
||||
FireImmune = 69,
|
||||
PreventDeath = 70,
|
||||
MvmBotStunRadiowave = 71,
|
||||
HalloweenSpeedBoost = 72,
|
||||
HalloweenQuickHeal = 73,
|
||||
HalloweenGiant = 74,
|
||||
HalloweenTiny = 75,
|
||||
HalloweenInHell = 76,
|
||||
HalloweenGhostMode = 77,
|
||||
MiniCritBoostedOnKill = 78,
|
||||
ObscuredSmoke = 79,
|
||||
ParachuteActive = 80,
|
||||
BlastJumping = 81,
|
||||
HalloweenKart = 82,
|
||||
HalloweenKartDash = 83,
|
||||
BalloonHead = 84,
|
||||
MeleeOnly = 85,
|
||||
SwimmingCurse = 86,
|
||||
FreezeInput = 87,
|
||||
HalloweenKartCage = 88,
|
||||
RuneStrength = 90,
|
||||
RuneHaste = 91,
|
||||
RuneRegen = 92,
|
||||
RuneResist = 93,
|
||||
RuneVampire = 94,
|
||||
RuneReflect = 95,
|
||||
RunePrecision = 96,
|
||||
RuneAgility = 97,
|
||||
GrapplingHook = 98,
|
||||
GrapplingHookSafeFall = 99,
|
||||
GrapplingHookLatched = 100,
|
||||
GrapplingHookBleeding = 101,
|
||||
AfterburnImmune = 102,
|
||||
RuneKnockout = 103,
|
||||
RuneImbalance = 104,
|
||||
CritBoostedRuneTemp = 105,
|
||||
PasstimeInterception = 106,
|
||||
SwimmingNoEffects = 107,
|
||||
PURGATORY = 108,
|
||||
RuneKing = 109,
|
||||
RunePlague = 110,
|
||||
RuneSupernova = 111,
|
||||
PLAGUE = 112,
|
||||
KingBuffed = 113,
|
||||
TeamGlows = 114,
|
||||
KnockedIntoAir = 115,
|
||||
CompetitiveWinner = 116,
|
||||
CompetitiveLoser = 117,
|
||||
HealingDebuff = 118,
|
||||
PasstimePenaltyDebuff = 119,
|
||||
GrappledToPlayer = 120,
|
||||
GrappledByPlayer = 121,
|
||||
ParachuteDeployed = 122,
|
||||
GAS = 123,
|
||||
BurningPyro = 124,
|
||||
RocketPack = 125,
|
||||
LostFooting = 126,
|
||||
AirCurrent = 127,
|
||||
HalloweenHellHeal = 128,
|
||||
PowerUpModeDominant = 129,
|
||||
ImmuneToPushback = 130,
|
||||
}
|
||||
|
||||
impl PlayerCondition {
|
||||
pub const MAX: PlayerCondition = PlayerCondition::ImmuneToPushback;
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
pub use super::cond::PlayerCondition;
|
||||
use crate::demo::data::DemoTick;
|
||||
use crate::demo::gameevent_gen::PlayerDeathEvent;
|
||||
use crate::demo::gamevent::GameEvent;
|
||||
|
|
@ -8,6 +9,7 @@ use crate::demo::vector::Vector;
|
|||
use parse_display::Display;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::ops::Rem;
|
||||
|
||||
#[derive(Default, Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq, Hash, Display)]
|
||||
pub struct Handle(pub i64);
|
||||
|
|
@ -73,6 +75,7 @@ pub struct Player {
|
|||
pub in_pvs: bool,
|
||||
pub bounds: Box,
|
||||
pub weapons: [Handle; 3],
|
||||
pub(crate) conditions: [u8; 20],
|
||||
}
|
||||
|
||||
pub const PLAYER_BOX_DEFAULT: Box = Box {
|
||||
|
|
@ -108,6 +111,31 @@ impl Player {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn conditions(&self) -> impl Iterator<Item = PlayerCondition> + '_ {
|
||||
(1..=(PlayerCondition::MAX as u8)).filter_map(|cond_int| {
|
||||
let byte = cond_int / 8;
|
||||
let bit = cond_int.rem(8);
|
||||
let cond_byte = *self.conditions.get(byte as usize)?;
|
||||
if (cond_byte >> bit as usize) == 1 {
|
||||
PlayerCondition::try_from(cond_byte).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn has_condition(&self, condition: PlayerCondition) -> bool {
|
||||
let cond_int = condition as u8;
|
||||
let byte = cond_int / 8;
|
||||
let bit = cond_int.rem(8);
|
||||
let cond_byte = self
|
||||
.conditions
|
||||
.get(byte as usize)
|
||||
.copied()
|
||||
.unwrap_or_default();
|
||||
cond_byte >> bit as usize == 1
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
mod cond;
|
||||
pub mod game_state;
|
||||
pub mod userinfo;
|
||||
|
||||
|
|
|
|||
|
|
@ -318,9 +318,10 @@ fn get_entity_for_update(
|
|||
update_type: UpdateType,
|
||||
delta: Option<ServerTick>,
|
||||
) -> Result<PacketEntity> {
|
||||
let class_id = *state
|
||||
let class_id = state
|
||||
.entity_classes
|
||||
.get(&entity_index)
|
||||
.copied()
|
||||
.ok_or(ParseError::UnknownEntity(entity_index))?;
|
||||
|
||||
Ok(PacketEntity {
|
||||
|
|
@ -354,13 +355,14 @@ impl Parse<'_> for PacketEntitiesMessage {
|
|||
|
||||
for _ in 0..updated_entries {
|
||||
let diff: u32 = read_bit_var(&mut data)?;
|
||||
last_index = last_index.saturating_add(diff as i32).saturating_add(1);
|
||||
if last_index >= 2048 {
|
||||
let index = last_index.saturating_add(diff as i32).saturating_add(1);
|
||||
if index >= 2048 {
|
||||
return Err(ParseError::InvalidDemo("invalid entity index"));
|
||||
}
|
||||
let entity_index = EntityId::from(last_index as u32);
|
||||
let entity_index = EntityId::from(index as u32);
|
||||
|
||||
let update_type = data.read()?;
|
||||
|
||||
if update_type == UpdateType::Enter {
|
||||
let mut entity =
|
||||
Self::read_enter(&mut data, entity_index, state, base_line, delta)?;
|
||||
|
|
@ -392,6 +394,8 @@ impl Parse<'_> for PacketEntitiesMessage {
|
|||
baseline_index: BaselineIndex::First,
|
||||
});
|
||||
}
|
||||
|
||||
last_index = index;
|
||||
}
|
||||
|
||||
if delta.is_some() {
|
||||
|
|
|
|||
|
|
@ -235,6 +235,16 @@ impl GameStateAnalyser {
|
|||
SendPropIdentifier::new("DT_BaseEntity", "m_flSimulationTime");
|
||||
const PROP_BB_MAX: SendPropIdentifier =
|
||||
SendPropIdentifier::new("DT_CollisionProperty", "m_vecMaxsPreScaled");
|
||||
const PLAYER_COND: SendPropIdentifier =
|
||||
SendPropIdentifier::new("DT_TFPlayerShared", "m_nPlayerCond");
|
||||
const PLAYER_COND_EX1: SendPropIdentifier =
|
||||
SendPropIdentifier::new("DT_TFPlayerShared", "m_nPlayerCondEx");
|
||||
const PLAYER_COND_EX2: SendPropIdentifier =
|
||||
SendPropIdentifier::new("DT_TFPlayerShared", "m_nPlayerCondEx2");
|
||||
const PLAYER_COND_EX3: SendPropIdentifier =
|
||||
SendPropIdentifier::new("DT_TFPlayerShared", "m_nPlayerCondEx3");
|
||||
const PLAYER_COND_EX4: SendPropIdentifier =
|
||||
SendPropIdentifier::new("DT_TFPlayerShared", "m_nPlayerCondEx4");
|
||||
|
||||
const WEAPON_0: SendPropIdentifier = SendPropIdentifier::new("m_hMyWeapons", "000");
|
||||
const WEAPON_1: SendPropIdentifier = SendPropIdentifier::new("m_hMyWeapons", "001");
|
||||
|
|
@ -286,6 +296,31 @@ impl GameStateAnalyser {
|
|||
let handle = Handle(i64::try_from(&prop.value).unwrap_or_default());
|
||||
player.weapons[2] = handle;
|
||||
}
|
||||
PLAYER_COND => {
|
||||
player.conditions[0..4].copy_from_slice(
|
||||
&i64::try_from(&prop.value).unwrap_or_default().to_le_bytes()[0..4],
|
||||
);
|
||||
}
|
||||
PLAYER_COND_EX1 => {
|
||||
player.conditions[4..8].copy_from_slice(
|
||||
&i64::try_from(&prop.value).unwrap_or_default().to_le_bytes()[0..4],
|
||||
);
|
||||
}
|
||||
PLAYER_COND_EX2 => {
|
||||
player.conditions[8..12].copy_from_slice(
|
||||
&i64::try_from(&prop.value).unwrap_or_default().to_le_bytes()[0..4],
|
||||
);
|
||||
}
|
||||
PLAYER_COND_EX3 => {
|
||||
player.conditions[12..16].copy_from_slice(
|
||||
&i64::try_from(&prop.value).unwrap_or_default().to_le_bytes()[0..4],
|
||||
);
|
||||
}
|
||||
PLAYER_COND_EX4 => {
|
||||
player.conditions[16..20].copy_from_slice(
|
||||
&i64::try_from(&prop.value).unwrap_or_default().to_le_bytes()[0..4],
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue