1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
mod update_arena;
pub(crate) mod vehicle_methods;
use nom::number::complete::le_i32;
use update_arena::UpdateArena;
pub use vehicle_methods::*;
use crate::{packet_parser::prelude::*, BattleContext};
#[derive(Debug, Clone, EventPrinter, Serialize)]
pub struct EntityMethodEvent {
#[event_debug(as_player)]
pub entity_id: i32,
pub size: i32,
pub method_id: i32,
#[event_debug(custom_debug)]
pub event: EntityMethod,
}
impl PacketParser for EntityMethodEvent {
fn parse(packet: &Packet, context: &Context) -> Result<BattleEvent, PacketError> {
let data = packet.payload();
let (remaining, entity_id) = le_i32(data)?;
let (remaining, method_id) = le_i32(remaining)?;
let (method_data, size) = le_i32(remaining)?;
if let Some(method_name) = context.find_method(entity_id, method_id) {
let entity_method_event = EntityMethodEvent {
entity_id,
size,
method_id,
event: EntityMethod::new(method_name, method_data, context.get_version()).map_err(
|root_cause| PacketError::EntityMethodError {
method_data: hex::encode_upper(data),
method_name: method_name.into(),
method_id,
root_cause,
},
)?,
};
Ok(BattleEvent::EntityMethod(entity_method_event))
} else {
let entity_method_event = EntityMethodEvent {
entity_id,
size,
method_id,
event: EntityMethod::Unknown(method_id),
};
Ok(BattleEvent::EntityMethod(entity_method_event))
}
}
}
impl EntityMethodEvent {
pub fn is_unknown(&self) -> bool {
matches!(self.event, EntityMethod::Unknown(_))
}
}
impl From<EntityMethodEvent> for EntityMethod {
fn from(val: EntityMethodEvent) -> Self {
val.event
}
}
#[derive(Debug, Clone, Serialize)]
#[non_exhaustive]
pub enum EntityMethod {
DamageFromShot(ShowDamageFromShot),
ShotFired(ShowShooting),
HealthChanged(OnHealthChanged),
Explosion(ShowDamageFromExplosion),
StaticCollision(OnStaticCollision),
Tracer(ShowTracer),
Arena(UpdateArena),
Unknown(i32),
}
impl EntityMethod {
pub fn new(name: &str, data: &[u8], version: [u16; 4]) -> std::result::Result<Self, String> {
use EntityMethod::*;
match name {
"showShooting" => Ok(ShotFired(EntityMethod::parse_method(data, version)?)),
"onHealthChanged" => Ok(HealthChanged(EntityMethod::parse_method(data, version)?)),
"showDamageFromExplosion" => Ok(Explosion(EntityMethod::parse_method(data, version)?)),
"onStaticCollision" => Ok(StaticCollision(EntityMethod::parse_method(data, version)?)),
"showDamageFromShot" => Ok(DamageFromShot(EntityMethod::parse_method(data, version)?)),
"showTracer" => Ok(Tracer(EntityMethod::parse_method(data, version)?)),
_ => {
Ok(Unknown(-1))
}
}
}
fn parse_method<'de, T: Deserialize<'de> + Version>(
data: &'de [u8], version: [u16; 4],
) -> std::result::Result<T, String> {
from_slice(data, version).map_err(|err| err.to_string())
}
}
impl EventPrinter for EntityMethod {
fn to_debug_string(&self, context: &BattleContext) -> String
where
Self: std::fmt::Debug,
{
match self {
EntityMethod::DamageFromShot(event) => format!("{:?}", event),
EntityMethod::ShotFired(event) => format!("{:?}", event),
EntityMethod::HealthChanged(event) => format!("{:?}", event.to_debug_string(context)),
EntityMethod::Explosion(event) => format!("{:?}", event.to_debug_string(context)),
EntityMethod::Tracer(event) => format!("{:?}", event.to_debug_string(context)),
EntityMethod::StaticCollision(event) => format!("{:?}", event),
EntityMethod::Arena(event) => format!("{:?}", event),
EntityMethod::Unknown(method_id) => format!("Unknown method: {}", method_id),
}
}
}