1use bytes::Bytes;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use uuid::Uuid;
5
6pub struct PluginContext {
7 pub plugin_id: String,
8 pub version: String,
9 pub config: HashMap<String, String>,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub enum PluginEvent {
14 PlayerJoin {
15 uuid: Uuid,
16 username: String,
17 },
18 PlayerLeave {
19 uuid: Uuid,
20 },
21 PlayerChat {
22 uuid: Uuid,
23 message: String,
24 },
25 PlayerMove {
26 uuid: Uuid,
27 x: f64,
28 y: f64,
29 z: f64,
30 on_ground: bool,
31 },
32 ServerMessage {
33 message: String,
34 },
35 Custom {
36 event_type: String,
37 data: serde_json::Value,
38 },
39}
40
41pub trait Plugin: Send + Sync {
42 fn name(&self) -> &str;
43 fn version(&self) -> &str;
44 fn author(&self) -> &str;
45 fn description(&self) -> &str;
46
47 fn on_load(&mut self, context: &PluginContext) -> anyhow::Result<()>;
48 fn on_unload(&mut self) -> anyhow::Result<()>;
49 fn on_enable(&mut self) -> anyhow::Result<()>;
50 fn on_disable(&mut self) -> anyhow::Result<()>;
51
52 fn handle_event(&mut self, event: &PluginEvent) -> anyhow::Result<Option<PluginResponse>>;
53
54 fn register_packet_hooks(&mut self) -> Vec<PacketEvent> {
55 Vec::new()
56 }
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub enum PluginResponse {
61 None,
62 Message(String),
63 KickPlayer { uuid: Uuid, reason: String },
64 Broadcast(String),
65 Custom(serde_json::Value),
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct PluginMetadata {
70 pub name: String,
71 pub version: String,
72 pub author: String,
73 pub description: String,
74 pub min_proxy_version: String,
75 pub dependencies: Vec<String>,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum PacketDirection {
80 Clientbound,
81 Serverbound,
82}
83
84#[derive(Debug, Clone)]
85pub struct PacketFilter {
86 pub protocol_version: Option<u32>,
87 pub packet_id: Option<i32>,
88 pub direction: PacketDirection,
89}
90
91impl PacketFilter {
92 pub fn new(direction: PacketDirection) -> Self {
93 Self {
94 protocol_version: None,
95 packet_id: None,
96 direction,
97 }
98 }
99
100 pub fn with_protocol_version(mut self, version: u32) -> Self {
101 self.protocol_version = Some(version);
102 self
103 }
104
105 pub fn with_packet_id(mut self, id: i32) -> Self {
106 self.packet_id = Some(id);
107 self
108 }
109}
110
111#[derive(Debug, Clone)]
112pub struct PacketData {
113 pub protocol_version: u32,
114 pub packet_id: i32,
115 pub direction: PacketDirection,
116 pub data: Bytes,
117 pub player_uuid: Option<Uuid>,
118}
119
120#[derive(Debug, Clone)]
121pub enum PacketHookResult {
122 Forward,
123
124 Drop,
125
126 Modify(Bytes),
127
128 Replace { packet_id: i32, data: Bytes },
129}
130
131pub type PacketHookFn = Box<dyn Fn(&PacketData) -> anyhow::Result<PacketHookResult> + Send + Sync>;
132
133pub struct PacketEvent {
134 filter: PacketFilter,
135 hook: PacketHookFn,
136}
137
138impl PacketEvent {
139 pub fn hook(filter: PacketFilter, hook: PacketHookFn) -> Self {
140 Self { filter, hook }
141 }
142
143 pub fn hook_to_clientbound<F>(
144 protocol_version: Option<u32>,
145 packet_id: Option<i32>,
146 hook: F,
147 ) -> Self
148 where
149 F: Fn(&PacketData) -> anyhow::Result<PacketHookResult> + Send + Sync + 'static,
150 {
151 let filter = PacketFilter {
152 protocol_version,
153 packet_id,
154 direction: PacketDirection::Clientbound,
155 };
156 Self {
157 filter,
158 hook: Box::new(hook),
159 }
160 }
161
162 pub fn hook_to_serverbound<F>(
164 protocol_version: Option<u32>,
165 packet_id: Option<i32>,
166 hook: F,
167 ) -> Self
168 where
169 F: Fn(&PacketData) -> anyhow::Result<PacketHookResult> + Send + Sync + 'static,
170 {
171 let filter = PacketFilter {
172 protocol_version,
173 packet_id,
174 direction: PacketDirection::Serverbound,
175 };
176 Self {
177 filter,
178 hook: Box::new(hook),
179 }
180 }
181
182 pub fn matches(&self, packet: &PacketData) -> bool {
183 if packet.direction != self.filter.direction {
184 return false;
185 }
186 if let Some(version) = self.filter.protocol_version {
187 if packet.protocol_version != version {
188 return false;
189 }
190 }
191 if let Some(id) = self.filter.packet_id {
192 if packet.packet_id != id {
193 return false;
194 }
195 }
196 true
197 }
198
199 pub fn execute(&self, packet: &PacketData) -> anyhow::Result<PacketHookResult> {
200 (self.hook)(packet)
201 }
202
203 pub fn filter(&self) -> &PacketFilter {
204 &self.filter
205 }
206}