mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 18:24:05 +02:00
some wip
This commit is contained in:
commit
4ac2a3cfc6
20 changed files with 907 additions and 0 deletions
416
src/demo/gamevent.rs
Normal file
416
src/demo/gamevent.rs
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
pub struct GameEventDefinition {
|
||||
id: u32,
|
||||
name: String,
|
||||
entries: Vec<GameEventEntry>,
|
||||
}
|
||||
|
||||
pub struct GameEventEntry {
|
||||
name: String,
|
||||
kind: GameEventValueType,
|
||||
}
|
||||
|
||||
pub enum GameEventValueType {
|
||||
String,
|
||||
Float,
|
||||
Long,
|
||||
Short,
|
||||
Byte,
|
||||
Boolean,
|
||||
Local,
|
||||
}
|
||||
|
||||
pub struct GameEvent {
|
||||
kind: GameEventType,
|
||||
values: HashMap<String, GameEventValue>,
|
||||
}
|
||||
|
||||
pub enum GameEventValue {
|
||||
String(String),
|
||||
Float(f32),
|
||||
Long(u32),
|
||||
Short(u16),
|
||||
Byte(u8),
|
||||
Boolean(bool),
|
||||
Local,
|
||||
}
|
||||
|
||||
pub enum GameEventType {
|
||||
ServerSpawnEvent,
|
||||
ServerChangelevelFailedEvent,
|
||||
ServerShutdownEvent,
|
||||
ServerCvarEvent,
|
||||
ServerMessageEvent,
|
||||
ServerAddBanEvent,
|
||||
ServerRemoveBanEvent,
|
||||
PlayerConnectEvent,
|
||||
PlayerConnectClientEvent,
|
||||
PlayerInfoEvent,
|
||||
PlayerDisconnectEvent,
|
||||
PlayerActivateEvent,
|
||||
PlayerSayEvent,
|
||||
ClientDisconnectEvent,
|
||||
ClientBeginConnectEvent,
|
||||
ClientConnectedEvent,
|
||||
ClientFullConnectEvent,
|
||||
HostQuitEvent,
|
||||
TeamInfoEvent,
|
||||
TeamScoreEvent,
|
||||
TeamPlayBroadcastAudioEvent,
|
||||
PlayerTeamEvent,
|
||||
PlayerClassEvent,
|
||||
PlayerDeathEvent,
|
||||
PlayerHurtEvent,
|
||||
PlayerChatEvent,
|
||||
PlayerScoreEvent,
|
||||
PlayerSpawnEvent,
|
||||
PlayerShootEvent,
|
||||
PlayerUseEvent,
|
||||
PlayerChangeNameEvent,
|
||||
PlayerHintMessageEvent,
|
||||
BasePlayerTeleportedEvent,
|
||||
GameInitEvent,
|
||||
GameNewMapEvent,
|
||||
GameStartEvent,
|
||||
GameEndEvent,
|
||||
RoundStartEvent,
|
||||
RoundEndEvent,
|
||||
GameMessageEvent,
|
||||
BreakBreakableEvent,
|
||||
BreakPropEvent,
|
||||
EntityKilledEvent,
|
||||
BonusUpdatedEvent,
|
||||
AchievementEventEvent,
|
||||
AchievementIncrementEvent,
|
||||
PhysgunPickupEvent,
|
||||
FlareIgniteNpcEvent,
|
||||
HelicopterGrenadePuntMissEvent,
|
||||
UserDataDownloadedEvent,
|
||||
RagdollDissolvedEvent,
|
||||
HLTVChangedModeEvent,
|
||||
HLTVChangedTargetEvent,
|
||||
VoteEndedEvent,
|
||||
VoteStartedEvent,
|
||||
VoteChangedEvent,
|
||||
VotePassedEvent,
|
||||
VoteFailedEvent,
|
||||
VoteCastEvent,
|
||||
VoteOptionsEvent,
|
||||
ReplaySavedEvent,
|
||||
EnteredPerformanceModeEvent,
|
||||
BrowseReplaysEvent,
|
||||
ReplayYoutubeStatsEvent,
|
||||
InventoryUpdatedEvent,
|
||||
CartUpdatedEvent,
|
||||
StorePricesheetUpdatedEvent,
|
||||
GcConnectedEvent,
|
||||
ItemSchemaInitializedEvent,
|
||||
IntroFinishEvent,
|
||||
IntroNextCameraEvent,
|
||||
MmLobbyChatEvent,
|
||||
MmLobbyMemberJoinEvent,
|
||||
MmLobbyMemberLeaveEvent,
|
||||
PlayerChangeClassEvent,
|
||||
TfMapTimeRemainingEvent,
|
||||
TfGameOverEvent,
|
||||
CtfFlagCapturedEvent,
|
||||
ControlPointInitializedEvent,
|
||||
ControlPointUpdateImagesEvent,
|
||||
ControlPointUpdateLayoutEvent,
|
||||
ControlPointUpdateCappingEvent,
|
||||
ControlPointUpdateOwnerEvent,
|
||||
ControlPointStartTouchEvent,
|
||||
ControlPointEndTouchEvent,
|
||||
ControlPointPulseElementEvent,
|
||||
ControlPointFakeCaptureEvent,
|
||||
ControlPointFakeCaptureMultEvent,
|
||||
TeamPlayRoundSelectedEvent,
|
||||
TeamPlayRoundStartEvent,
|
||||
TeamPlayRoundActiveEvent,
|
||||
TeamPlayWaitingBeginsEvent,
|
||||
TeamPlayWaitingEndsEvent,
|
||||
TeamPlayWaitingAboutToEndEvent,
|
||||
TeamPlayRestartRoundEvent,
|
||||
TeamPlayReadyRestartEvent,
|
||||
TeamPlayRoundRestartSecondsEvent,
|
||||
TeamPlayTeamReadyEvent,
|
||||
TeamPlayRoundWinEvent,
|
||||
TeamPlayUpdateTimerEvent,
|
||||
TeamPlayRoundStalemateEvent,
|
||||
TeamPlayOvertimeBeginEvent,
|
||||
TeamPlayOvertimeEndEvent,
|
||||
TeamPlaySuddenDeathBeginEvent,
|
||||
TeamPlaySuddenDeathEndEvent,
|
||||
TeamPlayGameOverEvent,
|
||||
TeamPlayMapTimeRemainingEvent,
|
||||
TeamPlayTimerFlashEvent,
|
||||
TeamPlayTimerTimeAddedEvent,
|
||||
TeamPlayPointStartCaptureEvent,
|
||||
TeamPlayPointCapturedEvent,
|
||||
TeamPlayPointLockedEvent,
|
||||
TeamPlayPointUnlockedEvent,
|
||||
TeamPlayCaptureBrokenEvent,
|
||||
TeamPlayCaptureBlockedEvent,
|
||||
TeamPlayFlagEventEvent,
|
||||
TeamPlayWinPanelEvent,
|
||||
TeamPlayTeambalancedPlayerEvent,
|
||||
TeamPlaySetupFinishedEvent,
|
||||
TeamPlayAlertEvent,
|
||||
TrainingCompleteEvent,
|
||||
ShowFreezePanelEvent,
|
||||
HideFreezePanelEvent,
|
||||
FreezeCamStartedEvent,
|
||||
LocalPlayerChangeTeamEvent,
|
||||
LocalPlayerScoreChangedEvent,
|
||||
LocalPlayerChangeClassEvent,
|
||||
LocalPlayerRespawnEvent,
|
||||
BuildingInfoChangedEvent,
|
||||
LocalPlayerChangeDisguiseEvent,
|
||||
PlayerAccountChangedEvent,
|
||||
SpyPdaResetEvent,
|
||||
FlagStatusUpdateEvent,
|
||||
PlayerStatsUpdatedEvent,
|
||||
PlayingCommentaryEvent,
|
||||
PlayerChargedeployedEvent,
|
||||
PlayerBuiltObjectEvent,
|
||||
PlayerUpgradedObjectEvent,
|
||||
PlayerCarryObjectEvent,
|
||||
PlayerDropObjectEvent,
|
||||
ObjectRemovedEvent,
|
||||
ObjectDestroyedEvent,
|
||||
ObjectDetonatedEvent,
|
||||
AchievementEarnedEvent,
|
||||
SpecTargetUpdatedEvent,
|
||||
TournamentStateUpdateEvent,
|
||||
TournamentEnableCountdownEvent,
|
||||
PlayerCalledForMedicEvent,
|
||||
PlayerAskedForBallEvent,
|
||||
LocalPlayerBecameObserverEvent,
|
||||
PlayerIgnitedInvEvent,
|
||||
PlayerIgnitedEvent,
|
||||
PlayerExtinguishedEvent,
|
||||
PlayerTeleportedEvent,
|
||||
PlayerHealedMedicCallEvent,
|
||||
LocalPlayerChargeReadyEvent,
|
||||
LocalPlayerWinddownEvent,
|
||||
PlayerInvulnedEvent,
|
||||
EscortSpeedEvent,
|
||||
EscortProgressEvent,
|
||||
EscortRecedeEvent,
|
||||
GameUIActivatedEvent,
|
||||
GameUIHiddenEvent,
|
||||
PlayerEscortScoreEvent,
|
||||
PlayerHealOnHitEvent,
|
||||
PlayerStealsandvichEvent,
|
||||
ShowClassLayoutEvent,
|
||||
ShowVsPanelEvent,
|
||||
PlayerDamagedEvent,
|
||||
ArenaPlayerNotificationEvent,
|
||||
ArenaMatchMaxStreakEvent,
|
||||
ArenaRoundStartEvent,
|
||||
ArenaWinPanelEvent,
|
||||
PveWinPanelEvent,
|
||||
AirDashEvent,
|
||||
LandedEvent,
|
||||
PlayerDamageDodgedEvent,
|
||||
PlayerStunnedEvent,
|
||||
ScoutGrandSlamEvent,
|
||||
ScoutSlamdollLandedEvent,
|
||||
ArrowImpactEvent,
|
||||
PlayerJaratedEvent,
|
||||
PlayerJaratedFadeEvent,
|
||||
PlayerShieldBlockedEvent,
|
||||
PlayerPinnedEvent,
|
||||
PlayerHealedByMedicEvent,
|
||||
PlayerSappedObjectEvent,
|
||||
ItemFoundEvent,
|
||||
ShowAnnotationEvent,
|
||||
HideAnnotationEvent,
|
||||
PostInventoryApplicationEvent,
|
||||
ControlPointUnlockUpdatedEvent,
|
||||
DeployBuffBannerEvent,
|
||||
PlayerBuffEvent,
|
||||
MedicDeathEvent,
|
||||
OvertimeNagEvent,
|
||||
TeamsChangedEvent,
|
||||
HalloweenPumpkinGrabEvent,
|
||||
RocketJumpEvent,
|
||||
RocketJumpLandedEvent,
|
||||
StickyJumpEvent,
|
||||
StickyJumpLandedEvent,
|
||||
MedicDefendedEvent,
|
||||
LocalPlayerHealedEvent,
|
||||
PlayerDestroyedPipeBombEvent,
|
||||
ObjectDeflectedEvent,
|
||||
PlayerMvpEvent,
|
||||
RaidSpawnMobEvent,
|
||||
RaidSpawnSquadEvent,
|
||||
NavBlockedEvent,
|
||||
PathTrackPassedEvent,
|
||||
NumCappersChangedEvent,
|
||||
PlayerRegenerateEvent,
|
||||
UpdateStatusItemEvent,
|
||||
StatsResetRoundEvent,
|
||||
ScoreStatsAccumulatedUpdateEvent,
|
||||
ScoreStatsAccumulatedResetEvent,
|
||||
AchievementEarnedLocalEvent,
|
||||
PlayerHealedEvent,
|
||||
BuildingHealedEvent,
|
||||
ItemPickupEvent,
|
||||
DuelStatusEvent,
|
||||
FishNoticeEvent,
|
||||
FishNoticeArmEvent,
|
||||
ThrowableHitEvent,
|
||||
PumpkinLordSummonedEvent,
|
||||
PumpkinLordKilledEvent,
|
||||
MerasmusSummonedEvent,
|
||||
MerasmusKilledEvent,
|
||||
MerasmusEscapeWarningEvent,
|
||||
MerasmusEscapedEvent,
|
||||
EyeballBossSummonedEvent,
|
||||
EyeballBossStunnedEvent,
|
||||
EyeballBossKilledEvent,
|
||||
EyeballBossKillerEvent,
|
||||
EyeballBossEscapeImminentEvent,
|
||||
EyeballBossEscapedEvent,
|
||||
NpcHurtEvent,
|
||||
ControlPointTimerUpdatedEvent,
|
||||
PlayerHighfiveStartEvent,
|
||||
PlayerHighfiveCancelEvent,
|
||||
PlayerHighfiveSuccessEvent,
|
||||
PlayerBonusPointsEvent,
|
||||
PlayerUpgradedEvent,
|
||||
PlayerBuybackEvent,
|
||||
PlayerUsedPowerUpBottleEvent,
|
||||
ChristmasGiftGrabEvent,
|
||||
PlayerKilledAchievementZoneEvent,
|
||||
PartyUpdatedEvent,
|
||||
LobbyUpdatedEvent,
|
||||
MvmMissionUpdateEvent,
|
||||
RecalculateHolidaysEvent,
|
||||
PlayerCurrencyChangedEvent,
|
||||
DoomsdayRocketOpenEvent,
|
||||
RemoveNemesisRelationshipsEvent,
|
||||
MvmCreditBonusWaveEvent,
|
||||
MvmCreditBonusAllEvent,
|
||||
MvmCreditBonusAllAdvancedEvent,
|
||||
MvmQuickSentryUpgradeEvent,
|
||||
MvmTankDestroyedByPlayersEvent,
|
||||
MvmKillRobotDeliveringBombEvent,
|
||||
MvmPickupCurrencyEvent,
|
||||
MvmBombCarrierKilledEvent,
|
||||
MvmSentryBusterDetonateEvent,
|
||||
MvmScoutMarkedForDeathEvent,
|
||||
MvmMedicPowerupSharedEvent,
|
||||
MvmBeginWaveEvent,
|
||||
MvmWaveCompleteEvent,
|
||||
MvmMissionCompleteEvent,
|
||||
MvmBombResetByPlayerEvent,
|
||||
MvmBombAlarmTriggeredEvent,
|
||||
MvmBombDeployResetByPlayerEvent,
|
||||
MvmWaveFailedEvent,
|
||||
MvmResetStatsEvent,
|
||||
DamageResistedEvent,
|
||||
RevivePlayerNotifyEvent,
|
||||
RevivePlayerStoppedEvent,
|
||||
RevivePlayerCompleteEvent,
|
||||
PlayerTurnedToGhostEvent,
|
||||
MedigunShieldBlockedDamageEvent,
|
||||
MvmAdvWaveCompleteNoGatesEvent,
|
||||
MvmSniperHeadshotCurrencyEvent,
|
||||
MvmMannhattanPitEvent,
|
||||
FlagCarriedInDetectionZoneEvent,
|
||||
MvmAdvWaveKilledStunRadioEvent,
|
||||
PlayerDirecthitStunEvent,
|
||||
MvmSentryBusterKilledEvent,
|
||||
UpgradesFileChangedEvent,
|
||||
RdTeamPointsChangedEvent,
|
||||
RdRulesStateChangedEvent,
|
||||
RdRobotKilledEvent,
|
||||
RdRobotImpactEvent,
|
||||
TeamPlayPreRoundTimeLeftEvent,
|
||||
ParachuteDeployEvent,
|
||||
ParachuteHolsterEvent,
|
||||
KillRefillsMeterEvent,
|
||||
RpsTauntEventEvent,
|
||||
CongaKillEvent,
|
||||
PlayerInitialSpawnEvent,
|
||||
CompetitiveVictoryEvent,
|
||||
CompetitiveStatsUpdateEvent,
|
||||
MiniGameWinEvent,
|
||||
SentryOnGoActiveEvent,
|
||||
DuckXpLevelUpEvent,
|
||||
QuestLogOpenedEvent,
|
||||
SchemaUpdatedEvent,
|
||||
LocalPlayerPickupWeaponEvent,
|
||||
RdPlayerScorePointsEvent,
|
||||
DemomanDetStickiesEvent,
|
||||
QuestObjectiveCompletedEvent,
|
||||
PlayerScoreChangedEvent,
|
||||
KilledCappingPlayerEvent,
|
||||
EnvironmentalDeathEvent,
|
||||
ProjectileDirectHitEvent,
|
||||
PassGetEvent,
|
||||
PassScoreEvent,
|
||||
PassFreeEvent,
|
||||
PassPassCaughtEvent,
|
||||
PassBallStolenEvent,
|
||||
PassBallBlockedEvent,
|
||||
DamagePreventedEvent,
|
||||
HalloweenBossKilledEvent,
|
||||
EscapedLootIslandEvent,
|
||||
TaggedPlayerAsItEvent,
|
||||
MerasmusStunnedEvent,
|
||||
MerasmusPropFoundEvent,
|
||||
HalloweenSkeletonKilledEvent,
|
||||
EscapeHellEvent,
|
||||
CrossSpectralBridgeEvent,
|
||||
MiniGameWonEvent,
|
||||
RespawnGhostEvent,
|
||||
KillInHellEvent,
|
||||
HalloweenDuckCollectedEvent,
|
||||
SpecialScoreEvent,
|
||||
TeamLeaderKilledEvent,
|
||||
HalloweenSoulCollectedEvent,
|
||||
RecalculateTruceEvent,
|
||||
DeadringerCheatDeathEvent,
|
||||
CrossbowHealEvent,
|
||||
DamageMitigatedEvent,
|
||||
PayloadPushedEvent,
|
||||
PlayerAbandonedMatchEvent,
|
||||
ClDrawlineEvent,
|
||||
RestartTimerTimeEvent,
|
||||
WinLimitChangedEvent,
|
||||
WinPanelShowScoresEvent,
|
||||
TopStreamsRequestFinishedEvent,
|
||||
CompetitiveStateChangedEvent,
|
||||
GlobalWarDataUpdatedEvent,
|
||||
StopWatchChangedEvent,
|
||||
DsStopEvent,
|
||||
DsScreenshotEvent,
|
||||
ShowMatchSummaryEvent,
|
||||
ExperienceChangedEvent,
|
||||
BeginXpLerpEvent,
|
||||
MatchmakerStatsUpdatedEvent,
|
||||
RematchVotePeriodOverEvent,
|
||||
RematchFailedToCreateEvent,
|
||||
PlayerRematchChangeEvent,
|
||||
PingUpdatedEvent,
|
||||
PlayerNextMapVoteChangeEvent,
|
||||
VoteMapsChangedEvent,
|
||||
HLTVStatusEvent,
|
||||
HLTVCameramanEvent,
|
||||
HLTVRankCameraEvent,
|
||||
HLTVRankEntityEvent,
|
||||
HLTVFixedEvent,
|
||||
HLTVChaseEvent,
|
||||
HLTVMessageEvent,
|
||||
HLTVTitleEvent,
|
||||
HLTVChatEvent,
|
||||
ReplayStartRecordEvent,
|
||||
ReplaySessionInfoEvent,
|
||||
ReplayEndRecordEvent,
|
||||
ReplayReplaysAvailableEvent,
|
||||
ReplayServerErrorEvent,
|
||||
}
|
||||
62
src/demo/header.rs
Normal file
62
src/demo/header.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
use crate::{ParseError, Parse, Result, Stream, ParserState};
|
||||
//use crate::test::test_parse;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Header {
|
||||
pub demo_type: String,
|
||||
pub version: u32,
|
||||
pub protocol: u32,
|
||||
pub server: String,
|
||||
pub nick: String,
|
||||
pub map: String,
|
||||
pub game: String,
|
||||
pub duration: f32,
|
||||
pub ticks: u32,
|
||||
pub frames: u32,
|
||||
pub sigon: u32,
|
||||
}
|
||||
|
||||
impl<'a> Parse<'a> for Header {
|
||||
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Header> {
|
||||
Ok(Header {
|
||||
demo_type: stream.read_string(Some(8))?,
|
||||
version: stream.read(32)?,
|
||||
protocol: stream.read(32)?,
|
||||
server: stream.read_string(Some(260))?,
|
||||
nick: stream.read_string(Some(260))?,
|
||||
map: stream.read_string(Some(260))?,
|
||||
game: stream.read_string(Some(260))?,
|
||||
duration: stream.read_float()?,
|
||||
ticks: stream.read(32)?,
|
||||
frames: stream.read(32)?,
|
||||
sigon: stream.read(32)?,
|
||||
})
|
||||
}
|
||||
|
||||
fn skip(stream: &mut Stream) -> Result<()> {
|
||||
stream
|
||||
.skip(8 * 8 + (32 * 2) + (260 * 8 * 4) + (32 * 4))
|
||||
.map_err(ParseError::from)
|
||||
}
|
||||
}
|
||||
|
||||
//#[test]
|
||||
//fn test_header() {
|
||||
// test_parse(
|
||||
// "data/small.dem",
|
||||
// Header {
|
||||
// demo_type: "HL2DEMO".to_owned(),
|
||||
// version: 3,
|
||||
// protocol: 24,
|
||||
// server: "localhost:27015".to_owned(),
|
||||
// nick: "Icewind | demos.tf".to_owned(),
|
||||
// map: "cp_gullywash".to_owned(),
|
||||
// game: "tf".to_owned(),
|
||||
// duration: 1.7249999,
|
||||
// ticks: 115,
|
||||
// frames: 111,
|
||||
// sigon: 218908,
|
||||
// },
|
||||
// 0,
|
||||
// );
|
||||
//}
|
||||
40
src/demo/mod.rs
Normal file
40
src/demo/mod.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use bitstream_reader::{BitBuffer, BitStream, LittleEndian, NonPadded};
|
||||
use rentals::OwnedBuffer;
|
||||
|
||||
pub mod gamevent;
|
||||
pub mod header;
|
||||
pub mod sendprop;
|
||||
pub mod vector;
|
||||
pub mod parser;
|
||||
pub mod packet;
|
||||
|
||||
pub type Buffer<'a> = BitBuffer<'a, LittleEndian, NonPadded>;
|
||||
pub type Stream<'a> = BitStream<'a, LittleEndian, NonPadded>;
|
||||
|
||||
rental! {
|
||||
mod rentals {
|
||||
use super::*;
|
||||
|
||||
#[rental_mut(covariant)]
|
||||
pub struct OwnedBuffer {
|
||||
source_vec: Vec<u8>,
|
||||
stream: Buffer<'source_vec>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Demo {
|
||||
data: OwnedBuffer,
|
||||
}
|
||||
|
||||
impl Demo {
|
||||
pub fn new(vec: Vec<u8>) -> Self {
|
||||
let data = OwnedBuffer::new(vec, |bytes| BitBuffer::new(bytes, LittleEndian));
|
||||
Demo { data }
|
||||
}
|
||||
|
||||
/// Get a new stream with the data of the demo
|
||||
pub fn get_stream(&self) -> Stream {
|
||||
BitStream::new(self.data.suffix().clone(), None, None)
|
||||
}
|
||||
}
|
||||
23
src/demo/packet/consolecmd.rs
Normal file
23
src/demo/packet/consolecmd.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||
|
||||
pub struct ConsoleCmdPacket {
|
||||
tick: u32,
|
||||
command: String,
|
||||
}
|
||||
|
||||
impl<'a> Parse<'a> for ConsoleCmdPacket {
|
||||
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||
let tick = stream.read(32)?;
|
||||
let len = stream.read(32)?;
|
||||
Ok(ConsoleCmdPacket {
|
||||
tick,
|
||||
command: stream.read_string(Some(len))?,
|
||||
})
|
||||
}
|
||||
|
||||
fn skip(stream: &mut Stream) -> Result<()> {
|
||||
let _ = stream.skip(32)?;
|
||||
let len = stream.read(32)?;
|
||||
stream.skip(len).map_err(ParseError::from)
|
||||
}
|
||||
}
|
||||
46
src/demo/packet/mod.rs
Normal file
46
src/demo/packet/mod.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||
use num_traits::FromPrimitive;
|
||||
use self::stop::Stop;
|
||||
|
||||
mod stop;
|
||||
mod synctick;
|
||||
mod consolecmd;
|
||||
mod usercmd;
|
||||
mod stringtable;
|
||||
|
||||
pub enum Packet {
|
||||
Stop(Stop)
|
||||
}
|
||||
|
||||
#[derive(Primitive)]
|
||||
pub enum PacketType {
|
||||
Sigon = 1,
|
||||
Packet = 2,
|
||||
SyncTick = 3,
|
||||
ConsoleCmd = 4,
|
||||
UserCmd = 5,
|
||||
DataTables = 6,
|
||||
Stop = 7,
|
||||
StringTables = 8,
|
||||
}
|
||||
|
||||
impl Packet {
|
||||
fn read_type(stream: &mut Stream) -> Result<PacketType> {
|
||||
let raw = stream.read(8)?;
|
||||
let packet_type: Option<PacketType> = PacketType::from_u8(raw);
|
||||
packet_type.ok_or(ParseError::InvalidPacketType(raw))
|
||||
}
|
||||
}
|
||||
|
||||
//impl Parse for Packet {
|
||||
// fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||
// let packet_type = Packet::read_type(stream);
|
||||
// match packet_type {
|
||||
// Sigon => {}
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// fn skip(stream: &mut Stream) -> Result<()> {
|
||||
// Ok(())
|
||||
// }
|
||||
//}
|
||||
13
src/demo/packet/stop.rs
Normal file
13
src/demo/packet/stop.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
use crate::{Parse, ParserState, Result, Stream};
|
||||
|
||||
pub struct Stop;
|
||||
|
||||
impl<'a> Parse<'a> for Stop {
|
||||
fn parse(_stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||
Ok(Stop)
|
||||
}
|
||||
|
||||
fn skip(_stream: &mut Stream) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
91
src/demo/packet/stringtable.rs
Normal file
91
src/demo/packet/stringtable.rs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||
|
||||
pub struct StringTable<'a> {
|
||||
name: String,
|
||||
entries: Vec<StringTableEntry<'a>>,
|
||||
max_entries: u32,
|
||||
fixed_userdata_size: Option<u32>,
|
||||
fixed_userdata_size_bits: Option<u32>,
|
||||
client_entries: Option<Vec<StringTableEntry<'a>>>,
|
||||
compressed: bool,
|
||||
}
|
||||
|
||||
impl<'a> StringTable<'a> {
|
||||
fn parse(stream: &mut Stream<'a>) -> Result<Self> {
|
||||
let name = stream.read_string(None)?;
|
||||
let entry_count: u32 = stream.read(16)?;
|
||||
let mut entries = Vec::with_capacity(entry_count as usize);
|
||||
for _ in 0..entry_count {
|
||||
entries.push(StringTableEntry::parse(stream)?);
|
||||
}
|
||||
|
||||
let client_entries = if stream.read_bool()? {
|
||||
let count = stream.read(16)?;
|
||||
let mut vec = Vec::with_capacity(count);
|
||||
for _ in 0..count {
|
||||
vec.push(StringTableEntry::parse(stream)?);
|
||||
}
|
||||
Some(vec)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(StringTable {
|
||||
name,
|
||||
entries,
|
||||
max_entries: entry_count,
|
||||
fixed_userdata_size: None,
|
||||
fixed_userdata_size_bits: None,
|
||||
client_entries,
|
||||
compressed: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StringTableEntry<'a> {
|
||||
text: String,
|
||||
extra_data: Option<Stream<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> StringTableEntry<'a> {
|
||||
fn parse(stream: &mut Stream<'a>) -> Result<Self> {
|
||||
let text = stream.read_string(None)?;
|
||||
let extra_data = if stream.read_bool()? {
|
||||
let byte_len: usize = stream.read(16)?;
|
||||
Some(stream.read_bits(byte_len * 8)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok(StringTableEntry {
|
||||
text,
|
||||
extra_data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StringTablePacket<'a> {
|
||||
tick: u32,
|
||||
tables: Vec<StringTable<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Parse<'a> for StringTablePacket<'a> {
|
||||
fn parse(stream: &mut Stream<'a>, _state: &ParserState<'a>) -> Result<Self> {
|
||||
let tick = stream.read(32)?;
|
||||
let length: usize = stream.read(32)?;
|
||||
let count: u32 = stream.read(8)?;
|
||||
let mut tables = Vec::with_capacity(count as usize);
|
||||
for _ in 0..count {
|
||||
tables.push(StringTable::parse(stream)?);
|
||||
}
|
||||
Ok(StringTablePacket {
|
||||
tick,
|
||||
tables,
|
||||
})
|
||||
}
|
||||
|
||||
fn skip(stream: &mut Stream) -> Result<()> {
|
||||
let _ = stream.skip(32)?;
|
||||
let length = stream.read(32)?;
|
||||
stream.skip(length).map_err(ParseError::from)
|
||||
}
|
||||
}
|
||||
17
src/demo/packet/synctick.rs
Normal file
17
src/demo/packet/synctick.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||
|
||||
pub struct SyncTickPacket {
|
||||
tick: u32
|
||||
}
|
||||
|
||||
impl<'a> Parse<'a> for SyncTickPacket {
|
||||
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||
Ok(SyncTickPacket {
|
||||
tick: stream.read(32)?
|
||||
})
|
||||
}
|
||||
|
||||
fn skip(stream: &mut Stream) -> Result<()> {
|
||||
stream.skip(32).map_err(ParseError::from)
|
||||
}
|
||||
}
|
||||
26
src/demo/packet/usercmd.rs
Normal file
26
src/demo/packet/usercmd.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use crate::{Parse, ParseError, ParserState, Result, Stream};
|
||||
|
||||
pub struct UserCmdPacket {
|
||||
tick: u32,
|
||||
command: String,
|
||||
sequence_out: u32
|
||||
}
|
||||
|
||||
impl<'a> Parse<'a> for UserCmdPacket {
|
||||
fn parse(stream: &mut Stream, _state: &ParserState) -> Result<Self> {
|
||||
let tick = stream.read(32)?;
|
||||
let sequence_out = stream.read(32)?;
|
||||
let len = stream.read(32)?;
|
||||
Ok(UserCmdPacket {
|
||||
tick,
|
||||
sequence_out,
|
||||
command: stream.read_string(Some(len))?,
|
||||
})
|
||||
}
|
||||
|
||||
fn skip(stream: &mut Stream) -> Result<()> {
|
||||
let _ = stream.skip(64)?;
|
||||
let len = stream.read(32)?;
|
||||
stream.skip(len).map_err(ParseError::from)
|
||||
}
|
||||
}
|
||||
59
src/demo/parser/mod.rs
Normal file
59
src/demo/parser/mod.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use bitstream_reader::ReadError;
|
||||
pub use crate::demo::parser::state::ParserState;
|
||||
use crate::Stream;
|
||||
|
||||
mod state;
|
||||
|
||||
/// Errors that can occur during parsing
|
||||
#[derive(Debug)]
|
||||
pub enum ParseError {
|
||||
/// Error while reading bits from stream
|
||||
ReadError(ReadError),
|
||||
/// Packet identifier is invalid
|
||||
InvalidPacketType(u8),
|
||||
}
|
||||
|
||||
impl From<ReadError> for ParseError {
|
||||
fn from(err: ReadError) -> ParseError {
|
||||
ParseError::ReadError(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, ParseError>;
|
||||
|
||||
pub trait Parse<'a>: Sized {
|
||||
fn parse(stream: &mut Stream<'a>, state: &ParserState<'a>) -> Result<Self>;
|
||||
fn skip(stream: &mut Stream) -> Result<()>;
|
||||
}
|
||||
|
||||
|
||||
pub struct DemoParser<'a> {
|
||||
stream: Stream<'a>,
|
||||
state: ParserState<'a>,
|
||||
}
|
||||
|
||||
impl<'a> DemoParser<'a> {
|
||||
pub fn new(stream: Stream<'a>) -> Self {
|
||||
DemoParser {
|
||||
state: ParserState::new(&stream),
|
||||
stream,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read<T: Parse<'a>>(&mut self) -> Result<T> {
|
||||
T::parse(&mut self.stream, &self.state)
|
||||
}
|
||||
|
||||
pub fn skip<T: Parse<'a>>(&mut self) -> Result<()> {
|
||||
T::skip(&mut self.stream)
|
||||
}
|
||||
|
||||
pub fn stream_pos(&self) -> usize {
|
||||
self.stream.pos()
|
||||
}
|
||||
|
||||
pub fn set_stream_pos(&mut self, pos: usize) -> Result<()> {
|
||||
self.stream.set_pos(pos)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
26
src/demo/parser/state.rs
Normal file
26
src/demo/parser/state.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use crate::demo::gamevent::GameEventDefinition;
|
||||
use crate::demo::sendprop::SendProp;
|
||||
use std::collections::HashMap;
|
||||
use crate::Stream;
|
||||
|
||||
pub struct ParserState<'a> {
|
||||
pub version: u32,
|
||||
pub static_baselines: HashMap<u32, StaticBaseline<'a>>,
|
||||
pub event_definitions: HashMap<u32, GameEventDefinition>,
|
||||
}
|
||||
|
||||
pub struct StaticBaseline<'a> {
|
||||
class_id: u32,
|
||||
raw: Stream<'a>,
|
||||
parsed: Option<Vec<SendProp>>,
|
||||
}
|
||||
|
||||
impl<'a> ParserState<'a> {
|
||||
pub fn new(_stream: &Stream<'a>) -> Self {
|
||||
ParserState {
|
||||
version: 0,
|
||||
static_baselines: HashMap::new(),
|
||||
event_definitions: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/demo/sendprop.rs
Normal file
17
src/demo/sendprop.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
use super::vector::{Vector, VectorXY};
|
||||
|
||||
pub struct SendPropDefinition {}
|
||||
|
||||
pub enum SendPropType {
|
||||
Vector(Vector),
|
||||
VectorXY(VectorXY),
|
||||
Integer(i32),
|
||||
Float(f32),
|
||||
String(String),
|
||||
Array(Vec<SendPropType>),
|
||||
}
|
||||
|
||||
pub struct SendProp {
|
||||
definition: SendPropDefinition,
|
||||
value: SendPropType,
|
||||
}
|
||||
10
src/demo/vector.rs
Normal file
10
src/demo/vector.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
pub struct Vector {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
}
|
||||
|
||||
pub struct VectorXY {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue