mirror of
https://codeberg.org/demostf/parser.git
synced 2026-06-03 18:24:05 +02:00
game event writing
This commit is contained in:
parent
5573ec5db2
commit
a55217cc55
11 changed files with 1021 additions and 844 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -12,7 +12,6 @@ use std::cmp::Ordering;
|
|||
pub struct GameEventDefinition {
|
||||
pub id: GameEventTypeId,
|
||||
pub event_type: GameEventType,
|
||||
pub name: String,
|
||||
pub entries: Vec<GameEventEntry>,
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +35,7 @@ impl Ord for GameEventDefinition {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct GameEventEntry {
|
||||
pub name: String,
|
||||
pub kind: GameEventValueType,
|
||||
|
|
@ -55,7 +54,7 @@ pub enum GameEventValueType {
|
|||
Local = 7,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum GameEventValue {
|
||||
String(String),
|
||||
Float(f32),
|
||||
|
|
@ -155,7 +154,7 @@ impl EventValue for () {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct RawGameEvent {
|
||||
pub event_type: GameEventType,
|
||||
pub values: Vec<GameEventValue>,
|
||||
|
|
|
|||
|
|
@ -75,14 +75,14 @@ impl BitWrite<LittleEndian> for BSPDecalMessage {
|
|||
|
||||
#[test]
|
||||
fn test_decal_roundtrip() {
|
||||
crate::test_roundtrip_encode(BSPDecalMessage {
|
||||
crate::test_roundtrip_write(BSPDecalMessage {
|
||||
position: Vector::default(),
|
||||
texture_index: 0,
|
||||
ent_index: 0,
|
||||
model_index: 0,
|
||||
low_priority: false,
|
||||
});
|
||||
crate::test_roundtrip_encode(BSPDecalMessage {
|
||||
crate::test_roundtrip_write(BSPDecalMessage {
|
||||
position: Vector {
|
||||
x: 1.0,
|
||||
y: 0.5,
|
||||
|
|
|
|||
|
|
@ -59,12 +59,12 @@ impl BitWrite<LittleEndian> for ClassInfoMessage {
|
|||
|
||||
#[test]
|
||||
fn test_say_text2_roundtrip() {
|
||||
crate::test_roundtrip_encode(ClassInfoMessage {
|
||||
crate::test_roundtrip_write(ClassInfoMessage {
|
||||
count: 8,
|
||||
create: true,
|
||||
entries: Vec::new(),
|
||||
});
|
||||
crate::test_roundtrip_encode(ClassInfoMessage {
|
||||
crate::test_roundtrip_write(ClassInfoMessage {
|
||||
count: 3,
|
||||
create: false,
|
||||
entries: vec![
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
|
||||
use bitbuffer::{BitRead, BitWrite, BitWriteSized, BitWriteStream, LittleEndian};
|
||||
use parse_display::Display;
|
||||
|
||||
use crate::demo::gameevent_gen::GameEventType;
|
||||
|
|
@ -8,8 +8,9 @@ use crate::demo::gamevent::{
|
|||
use crate::demo::parser::{Encode, ParseBitSkip};
|
||||
use crate::{GameEventError, Parse, ParseError, ParserState, ReadResult, Result, Stream};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct GameEventMessage {
|
||||
pub event_type_id: GameEventTypeId,
|
||||
pub event: GameEvent,
|
||||
}
|
||||
|
||||
|
|
@ -17,11 +18,12 @@ impl Parse<'_> for GameEventMessage {
|
|||
fn parse(stream: &mut Stream, state: &ParserState) -> Result<Self> {
|
||||
let length: u16 = stream.read_sized(11)?;
|
||||
let mut data = stream.read_bits(length as usize)?;
|
||||
let event_type: GameEventTypeId = data.read()?;
|
||||
let event_type_id: GameEventTypeId = data.read()?;
|
||||
|
||||
// game event definitions haven't been sent yet, ignore
|
||||
if state.event_definitions.is_empty() {
|
||||
return Ok(GameEventMessage {
|
||||
event_type_id,
|
||||
event: GameEvent::Unknown(RawGameEvent {
|
||||
event_type: GameEventType::Unknown,
|
||||
values: Vec::new(),
|
||||
|
|
@ -29,15 +31,18 @@ impl Parse<'_> for GameEventMessage {
|
|||
});
|
||||
}
|
||||
|
||||
let event = match state.event_definitions.get(usize::from(event_type)) {
|
||||
let event = match state.event_definitions.get(usize::from(event_type_id)) {
|
||||
Some(definition) => GameEvent::read(&mut data, definition)?,
|
||||
None => {
|
||||
return Err(ParseError::MalformedGameEvent(GameEventError::UnknownType(
|
||||
event_type,
|
||||
event_type_id,
|
||||
)));
|
||||
}
|
||||
};
|
||||
Ok(GameEventMessage { event })
|
||||
Ok(GameEventMessage {
|
||||
event_type_id,
|
||||
event,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -47,10 +52,61 @@ impl Encode for GameEventMessage {
|
|||
stream: &mut BitWriteStream<LittleEndian>,
|
||||
_state: &ParserState,
|
||||
) -> Result<()> {
|
||||
Ok(stream.reserve_length(11, |_stream| Ok(()))?)
|
||||
Ok(stream.reserve_length(11, |stream| {
|
||||
self.event_type_id.write(stream)?;
|
||||
self.event.write(stream)
|
||||
})?)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_game_event_roundtrip() {
|
||||
use crate::demo::gameevent_gen::{GameInitEvent, ServerShutdownEvent};
|
||||
|
||||
let definitions = vec![
|
||||
GameEventDefinition {
|
||||
id: GameEventTypeId(0),
|
||||
event_type: GameEventType::ServerShutdown,
|
||||
entries: vec![GameEventEntry {
|
||||
name: "reason".to_string(),
|
||||
kind: GameEventValueType::String,
|
||||
}],
|
||||
},
|
||||
GameEventDefinition {
|
||||
id: GameEventTypeId(1),
|
||||
event_type: GameEventType::ServerChangeLevelFailed,
|
||||
entries: vec![GameEventEntry {
|
||||
name: "level_name".to_string(),
|
||||
kind: GameEventValueType::String,
|
||||
}],
|
||||
},
|
||||
GameEventDefinition {
|
||||
id: GameEventTypeId(2),
|
||||
event_type: GameEventType::GameInit,
|
||||
entries: vec![],
|
||||
},
|
||||
];
|
||||
let mut state = ParserState::new(|_| false, false);
|
||||
state.event_definitions = definitions;
|
||||
|
||||
crate::test_roundtrip_encode(
|
||||
GameEventMessage {
|
||||
event_type_id: GameEventTypeId(0),
|
||||
event: GameEvent::ServerShutdown(ServerShutdownEvent {
|
||||
reason: "asd".into(),
|
||||
}),
|
||||
},
|
||||
&state,
|
||||
);
|
||||
crate::test_roundtrip_encode(
|
||||
GameEventMessage {
|
||||
event_type_id: GameEventTypeId(2),
|
||||
event: GameEvent::GameInit(GameInitEvent {}),
|
||||
},
|
||||
&state,
|
||||
);
|
||||
}
|
||||
|
||||
impl ParseBitSkip<'_> for GameEventMessage {
|
||||
fn parse_skip(stream: &mut Stream) -> Result<()> {
|
||||
let length: u16 = stream.read_sized(11)?;
|
||||
|
|
@ -73,7 +129,7 @@ impl From<GameEventTypeId> for u16 {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct GameEventListMessage {
|
||||
pub event_list: Vec<GameEventDefinition>,
|
||||
}
|
||||
|
|
@ -97,7 +153,6 @@ impl BitRead<'_, LittleEndian> for GameEventDefinition {
|
|||
Ok(GameEventDefinition {
|
||||
id: event_type,
|
||||
event_type: GameEventType::from_type_name(name.as_str()),
|
||||
name,
|
||||
entries,
|
||||
})
|
||||
}
|
||||
|
|
@ -107,7 +162,6 @@ impl BitWrite<LittleEndian> for GameEventDefinition {
|
|||
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
|
||||
self.id.write(stream)?;
|
||||
self.event_type.as_str().write(stream)?;
|
||||
self.name.write(stream)?;
|
||||
|
||||
for entry in self.entries.iter() {
|
||||
entry.kind.write(stream)?;
|
||||
|
|
@ -119,6 +173,18 @@ impl BitWrite<LittleEndian> for GameEventDefinition {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_event_definition_roundtrip() {
|
||||
crate::test_roundtrip_write(GameEventDefinition {
|
||||
id: GameEventTypeId(0),
|
||||
event_type: GameEventType::ServerChangeLevelFailed,
|
||||
entries: vec![GameEventEntry {
|
||||
name: "level_name".to_string(),
|
||||
kind: GameEventValueType::String,
|
||||
}],
|
||||
});
|
||||
}
|
||||
|
||||
impl BitRead<'_, LittleEndian> for GameEventListMessage {
|
||||
fn read(stream: &mut Stream) -> ReadResult<Self> {
|
||||
let count: u16 = stream.read_sized(9)?;
|
||||
|
|
@ -132,7 +198,7 @@ impl BitRead<'_, LittleEndian> for GameEventListMessage {
|
|||
|
||||
impl BitWrite<LittleEndian> for GameEventListMessage {
|
||||
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
|
||||
(self.event_list.len() as u16).write(stream)?;
|
||||
(self.event_list.len() as u16).write_sized(stream, 9)?;
|
||||
stream.reserve_length(20, |stream| {
|
||||
for event in self.event_list.iter() {
|
||||
event.write(stream)?;
|
||||
|
|
@ -143,3 +209,81 @@ impl BitWrite<LittleEndian> for GameEventListMessage {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_event_list_roundtrip() {
|
||||
crate::test_roundtrip_write(GameEventListMessage { event_list: vec![] });
|
||||
crate::test_roundtrip_write(GameEventListMessage {
|
||||
event_list: vec![GameEventDefinition {
|
||||
id: GameEventTypeId(0),
|
||||
event_type: GameEventType::ServerChangeLevelFailed,
|
||||
entries: vec![GameEventEntry {
|
||||
name: "level_name".to_string(),
|
||||
kind: GameEventValueType::String,
|
||||
}],
|
||||
}],
|
||||
});
|
||||
crate::test_roundtrip_write(GameEventListMessage {
|
||||
event_list: vec![
|
||||
GameEventDefinition {
|
||||
id: GameEventTypeId(0),
|
||||
event_type: GameEventType::ServerSpawn,
|
||||
entries: vec![
|
||||
GameEventEntry {
|
||||
name: "hostname".to_string(),
|
||||
kind: GameEventValueType::String,
|
||||
},
|
||||
GameEventEntry {
|
||||
name: "address".to_string(),
|
||||
kind: GameEventValueType::String,
|
||||
},
|
||||
GameEventEntry {
|
||||
name: "ip".to_string(),
|
||||
kind: GameEventValueType::Long,
|
||||
},
|
||||
GameEventEntry {
|
||||
name: "port".to_string(),
|
||||
kind: GameEventValueType::Short,
|
||||
},
|
||||
GameEventEntry {
|
||||
name: "game".to_string(),
|
||||
kind: GameEventValueType::String,
|
||||
},
|
||||
GameEventEntry {
|
||||
name: "map_name".to_string(),
|
||||
kind: GameEventValueType::String,
|
||||
},
|
||||
GameEventEntry {
|
||||
name: "max_players".to_string(),
|
||||
kind: GameEventValueType::Long,
|
||||
},
|
||||
GameEventEntry {
|
||||
name: "os".to_string(),
|
||||
kind: GameEventValueType::String,
|
||||
},
|
||||
GameEventEntry {
|
||||
name: "dedicated".to_string(),
|
||||
kind: GameEventValueType::Boolean,
|
||||
},
|
||||
GameEventEntry {
|
||||
name: "password".to_string(),
|
||||
kind: GameEventValueType::Boolean,
|
||||
},
|
||||
],
|
||||
},
|
||||
GameEventDefinition {
|
||||
id: GameEventTypeId(1),
|
||||
event_type: GameEventType::ServerChangeLevelFailed,
|
||||
entries: vec![GameEventEntry {
|
||||
name: "level_name".to_string(),
|
||||
kind: GameEventValueType::String,
|
||||
}],
|
||||
},
|
||||
GameEventDefinition {
|
||||
id: GameEventTypeId(2),
|
||||
event_type: GameEventType::GameInit,
|
||||
entries: vec![],
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,8 +140,8 @@ impl<'a> BitWrite<LittleEndian> for UserMessage<'a> {
|
|||
|
||||
#[test]
|
||||
fn test_user_message_roundtrip() {
|
||||
crate::test_roundtrip_encode(UserMessage::Train(TrainMessage { data: 12 }));
|
||||
crate::test_roundtrip_encode(UserMessage::SayText2(Box::new(SayText2Message {
|
||||
crate::test_roundtrip_write(UserMessage::Train(TrainMessage { data: 12 }));
|
||||
crate::test_roundtrip_write(UserMessage::SayText2(Box::new(SayText2Message {
|
||||
client: 3,
|
||||
raw: 1,
|
||||
kind: ChatMessageKind::ChatTeamDead,
|
||||
|
|
@ -297,7 +297,7 @@ impl BitWrite<LittleEndian> for SayText2Message {
|
|||
|
||||
#[test]
|
||||
fn test_say_text2_roundtrip() {
|
||||
crate::test_roundtrip_encode(SayText2Message {
|
||||
crate::test_roundtrip_write(SayText2Message {
|
||||
client: 3,
|
||||
raw: 1,
|
||||
kind: ChatMessageKind::ChatTeamDead,
|
||||
|
|
|
|||
|
|
@ -45,12 +45,12 @@ impl BitWrite<LittleEndian> for VoiceInitMessage {
|
|||
|
||||
#[test]
|
||||
fn test_voice_init_roundtrip() {
|
||||
crate::test_roundtrip_encode(VoiceInitMessage {
|
||||
crate::test_roundtrip_write(VoiceInitMessage {
|
||||
codec: "foo".into(),
|
||||
quality: 0,
|
||||
sampling_rate: 0,
|
||||
});
|
||||
crate::test_roundtrip_encode(VoiceInitMessage {
|
||||
crate::test_roundtrip_write(VoiceInitMessage {
|
||||
codec: "foo".into(),
|
||||
quality: 255,
|
||||
sampling_rate: 12,
|
||||
|
|
@ -119,13 +119,13 @@ fn test_parse_sounds_roundtrip() {
|
|||
use bitbuffer::BitReadBuffer;
|
||||
let inner = BitReadBuffer::new(&[1, 2, 3, 4, 5, 6], LittleEndian);
|
||||
|
||||
crate::test_roundtrip_encode(ParseSoundsMessage {
|
||||
crate::test_roundtrip_write(ParseSoundsMessage {
|
||||
reliable: false,
|
||||
num: 0,
|
||||
length: inner.bit_len() as u16,
|
||||
data: inner.clone().into(),
|
||||
});
|
||||
crate::test_roundtrip_encode(ParseSoundsMessage {
|
||||
crate::test_roundtrip_write(ParseSoundsMessage {
|
||||
reliable: true,
|
||||
num: 1,
|
||||
length: inner.bit_len() as u16,
|
||||
|
|
|
|||
|
|
@ -61,12 +61,12 @@ impl<E: Endianness> BitWrite<E> for ViewAngles {
|
|||
|
||||
#[test]
|
||||
fn test_view_angles_roundtrip() {
|
||||
crate::test_roundtrip_encode(ViewAngles {
|
||||
crate::test_roundtrip_write(ViewAngles {
|
||||
origin: (Vector::default(), Vector::default()),
|
||||
angles: (Vector::default(), Vector::default()),
|
||||
local_angles: (Vector::default(), Vector::default()),
|
||||
});
|
||||
crate::test_roundtrip_encode(ViewAngles {
|
||||
crate::test_roundtrip_write(ViewAngles {
|
||||
origin: (
|
||||
Vector {
|
||||
x: 1.0,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue