1use std::{fmt, io::Read};
4
5use mcproto_codec::error::{CodecError, CodecKind};
6
7use crate::{
8 Boolean, Double, Float, Int, Position, PrefixedArray, PrefixedOptional, PrefixedString,
9 ProtocolEnum, TypeCodec, TypeStructCodec, VarInt,
10 basic::{decode_prefixed_string, encode_prefixed_string},
11};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
15#[protocol_enum(repr = VarInt)]
16pub enum DebugSubscriptionType {
17 DedicatedServerTickTime = 0,
19 Bee = 1,
21 VillagerBrain = 2,
23 Breeze = 3,
25 GoalSelector = 4,
27 EntityPath = 5,
29 EntityBlockIntersection = 6,
31 BeeHive = 7,
33 PointOfInterest = 8,
35 RedstoneWireOrientation = 9,
37 VillageSection = 10,
39 Raid = 11,
41 Structure = 12,
43 GameEventListener = 13,
45 NeighborUpdate = 14,
47 GameEvent = 15,
49}
50
51#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
53#[type_struct_codec(kind = DebugSubscriptionData)]
54pub struct BeeDebugData {
55 pub hive_position: PrefixedOptional<Position>,
57 pub flower_position: PrefixedOptional<Position>,
59 pub travel_ticks: VarInt,
61 pub blacklisted_hives: PrefixedArray<Position>,
63}
64
65#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
67#[type_struct_codec(kind = DebugSubscriptionData)]
68pub struct VillagerBrainDebugData {
69 pub name: PrefixedString,
71 pub profession: PrefixedString,
73 pub xp: Int,
75 pub health: Float,
77 pub max_health: Float,
79 pub inventory: PrefixedString,
81 pub wants_golem: Boolean,
83 pub anger_level: Int,
85 pub activities: PrefixedArray<PrefixedString>,
87 pub behaviors: PrefixedArray<PrefixedString>,
89 pub memories: PrefixedArray<PrefixedString>,
91 pub gossips: PrefixedArray<PrefixedString>,
93 pub pois: PrefixedArray<Position>,
95 pub potential_pois: PrefixedArray<Position>,
97}
98
99#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
101#[type_struct_codec(kind = DebugSubscriptionData)]
102pub struct BreezeDebugData {
103 pub attack_target: PrefixedOptional<VarInt>,
105 pub jump_target: PrefixedOptional<Position>,
107}
108
109#[repr(transparent)]
111#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
112pub struct DebugGoalName(String);
113
114impl DebugGoalName {
115 pub const MAX_UTF16_CODE_UNITS: usize = 255;
117 pub const MAX_BYTES: usize = Self::MAX_UTF16_CODE_UNITS * 3;
119
120 pub fn new(value: impl Into<String>) -> Result<Self, DebugGoalNameTooLong> {
122 let value = value.into();
123 let actual_code_units = value.encode_utf16().count();
124 if actual_code_units > Self::MAX_UTF16_CODE_UNITS {
125 return Err(DebugGoalNameTooLong { actual_code_units });
126 }
127 Ok(Self(value))
128 }
129
130 #[must_use]
132 pub fn as_str(&self) -> &str {
133 &self.0
134 }
135
136 #[must_use]
138 pub fn into_inner(self) -> String {
139 self.0
140 }
141}
142
143impl AsRef<str> for DebugGoalName {
144 fn as_ref(&self) -> &str {
145 self.as_str()
146 }
147}
148
149impl fmt::Display for DebugGoalName {
150 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
151 formatter.write_str(self.as_str())
152 }
153}
154
155impl TryFrom<String> for DebugGoalName {
156 type Error = DebugGoalNameTooLong;
157
158 fn try_from(value: String) -> Result<Self, Self::Error> {
159 Self::new(value)
160 }
161}
162
163impl TryFrom<&str> for DebugGoalName {
164 type Error = DebugGoalNameTooLong;
165
166 fn try_from(value: &str) -> Result<Self, Self::Error> {
167 Self::new(value)
168 }
169}
170
171impl From<DebugGoalName> for String {
172 fn from(value: DebugGoalName) -> Self {
173 value.into_inner()
174 }
175}
176
177impl TypeCodec for DebugGoalName {
178 fn encode(&self, writer: &mut impl std::io::Write) -> Result<(), CodecError> {
179 encode_prefixed_string(
180 &self.0,
181 writer,
182 CodecKind::String,
183 Self::MAX_BYTES,
184 Self::MAX_UTF16_CODE_UNITS,
185 )
186 }
187
188 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
189 decode_prefixed_string(
190 reader,
191 CodecKind::String,
192 Self::MAX_BYTES,
193 Self::MAX_UTF16_CODE_UNITS,
194 )
195 .map(|(value, _)| Self(value))
196 }
197}
198
199#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
201pub struct DebugGoalNameTooLong {
202 pub actual_code_units: usize,
204}
205
206impl fmt::Display for DebugGoalNameTooLong {
207 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
208 write!(
209 formatter,
210 "debug goal name contains {} UTF-16 code units; maximum is {}",
211 self.actual_code_units,
212 DebugGoalName::MAX_UTF16_CODE_UNITS
213 )
214 }
215}
216
217impl std::error::Error for DebugGoalNameTooLong {}
218
219#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
221#[type_struct_codec(kind = DebugSubscriptionData)]
222pub struct GoalSelectorDebugData {
223 pub priority: VarInt,
225 pub is_running: Boolean,
227 pub name: DebugGoalName,
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
233#[protocol_enum(repr = VarInt)]
234pub enum DebugPathNodeType {
235 Blocked = 0,
236 Open = 1,
237 Walkable = 2,
238 WalkableDoor = 3,
239 Trapdoor = 4,
240 PowderSnow = 5,
241 DangerPowderSnow = 6,
242 Fence = 7,
243 Lava = 8,
244 Water = 9,
245 WaterBorder = 10,
246 Rail = 11,
247 UnpassableRail = 12,
248 DangerFire = 13,
249 DamageFire = 14,
250 DangerOther = 15,
251 DamageOther = 16,
252 DoorOpen = 17,
253 DoorWoodClosed = 18,
254 DoorIronClosed = 19,
255 Breach = 20,
256 Leaves = 21,
257 StickyHoney = 22,
258 Cocoa = 23,
259 DamageCautious = 24,
260 DangerTrapdoor = 25,
261}
262
263#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
265#[type_struct_codec(kind = DebugPathNode)]
266pub struct DebugPathNode {
267 pub x: Int,
268 pub y: Int,
269 pub z: Int,
270 pub walked_distance: Float,
271 pub cost_malus: Float,
272 pub closed: Boolean,
273 pub node_type: DebugPathNodeType,
274 pub f: Float,
276}
277
278#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
280#[type_struct_codec(kind = DebugSubscriptionData)]
281pub struct EntityPathDebugData {
282 pub reached: Boolean,
283 pub next_block_index: Int,
284 pub block_position: Position,
285 pub nodes: PrefixedArray<DebugPathNode>,
286 pub target_nodes: PrefixedArray<DebugPathNode>,
287 pub open_set: PrefixedArray<DebugPathNode>,
288 pub closed_set: PrefixedArray<DebugPathNode>,
289 pub max_node_distance: Float,
290}
291
292#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ProtocolEnum)]
294#[protocol_enum(repr = VarInt)]
295pub enum EntityBlockIntersectionState {
296 InBlock = 0,
297 InFluid = 1,
298 InAir = 2,
299}
300
301#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
303#[type_struct_codec(kind = DebugSubscriptionData)]
304pub struct EntityBlockIntersectionDebugData {
305 pub state: EntityBlockIntersectionState,
306}
307
308#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
310#[type_struct_codec(kind = DebugSubscriptionData)]
311pub struct BeeHiveDebugData {
312 pub block_type: VarInt,
314 pub occupant_count: VarInt,
315 pub honey_level: VarInt,
316 pub sedated: Boolean,
317}
318
319#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
321#[type_struct_codec(kind = DebugSubscriptionData)]
322pub struct PointOfInterestDebugData {
323 pub position: Position,
324 pub poi_type: VarInt,
326 pub free_ticket_count: VarInt,
327}
328
329#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
331#[type_struct_codec(kind = DebugSubscriptionData)]
332pub struct RedstoneWireOrientationDebugData {
333 pub id: VarInt,
334}
335
336#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
338#[type_struct_codec(kind = DebugSubscriptionData)]
339pub struct RaidDebugData {
340 pub positions: PrefixedArray<Position>,
341}
342
343#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
345#[type_struct_codec(kind = DebugStructureInfo)]
346pub struct DebugStructurePiece {
347 pub bounding_box_min: Position,
348 pub bounding_box_max: Position,
349 pub is_start: Boolean,
350}
351
352#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
354#[type_struct_codec(kind = DebugStructureInfo)]
355pub struct DebugStructureInfo {
356 pub bounding_box_min: Position,
357 pub bounding_box_max: Position,
358 pub pieces: PrefixedArray<DebugStructurePiece>,
359}
360
361#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
363#[type_struct_codec(kind = DebugSubscriptionData)]
364pub struct StructureDebugData {
365 pub structures: PrefixedArray<DebugStructureInfo>,
366}
367
368#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
370#[type_struct_codec(kind = DebugSubscriptionData)]
371pub struct GameEventListenerDebugData {
372 pub listener_radius: VarInt,
373}
374
375#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
377#[type_struct_codec(kind = DebugSubscriptionData)]
378pub struct NeighborUpdateDebugData {
379 pub position: Position,
380}
381
382#[derive(Debug, Clone, PartialEq, TypeStructCodec)]
384#[type_struct_codec(kind = DebugSubscriptionData)]
385pub struct GameEventDebugData {
386 pub event: VarInt,
388 pub x: Double,
389 pub y: Double,
390 pub z: Double,
391}
392
393#[derive(Debug, Clone, PartialEq)]
399pub enum DebugSubscriptionData {
400 DedicatedServerTickTime,
401 Bee(BeeDebugData),
402 VillagerBrain(VillagerBrainDebugData),
403 Breeze(BreezeDebugData),
404 GoalSelector(GoalSelectorDebugData),
405 EntityPath(EntityPathDebugData),
406 EntityBlockIntersection(EntityBlockIntersectionDebugData),
407 BeeHive(BeeHiveDebugData),
408 PointOfInterest(PointOfInterestDebugData),
409 RedstoneWireOrientation(RedstoneWireOrientationDebugData),
410 VillageSection,
411 Raid(RaidDebugData),
412 Structure(StructureDebugData),
413 GameEventListener(GameEventListenerDebugData),
414 NeighborUpdate(NeighborUpdateDebugData),
415 GameEvent(GameEventDebugData),
416}
417
418impl DebugSubscriptionData {
419 #[must_use]
421 pub const fn subscription_type(&self) -> DebugSubscriptionType {
422 match self {
423 Self::DedicatedServerTickTime => DebugSubscriptionType::DedicatedServerTickTime,
424 Self::Bee(_) => DebugSubscriptionType::Bee,
425 Self::VillagerBrain(_) => DebugSubscriptionType::VillagerBrain,
426 Self::Breeze(_) => DebugSubscriptionType::Breeze,
427 Self::GoalSelector(_) => DebugSubscriptionType::GoalSelector,
428 Self::EntityPath(_) => DebugSubscriptionType::EntityPath,
429 Self::EntityBlockIntersection(_) => DebugSubscriptionType::EntityBlockIntersection,
430 Self::BeeHive(_) => DebugSubscriptionType::BeeHive,
431 Self::PointOfInterest(_) => DebugSubscriptionType::PointOfInterest,
432 Self::RedstoneWireOrientation(_) => DebugSubscriptionType::RedstoneWireOrientation,
433 Self::VillageSection => DebugSubscriptionType::VillageSection,
434 Self::Raid(_) => DebugSubscriptionType::Raid,
435 Self::Structure(_) => DebugSubscriptionType::Structure,
436 Self::GameEventListener(_) => DebugSubscriptionType::GameEventListener,
437 Self::NeighborUpdate(_) => DebugSubscriptionType::NeighborUpdate,
438 Self::GameEvent(_) => DebugSubscriptionType::GameEvent,
439 }
440 }
441
442 pub(crate) fn encode_payload(
443 &self,
444 writer: &mut impl std::io::Write,
445 ) -> Result<(), CodecError> {
446 match self {
447 Self::DedicatedServerTickTime | Self::VillageSection => Ok(()),
448 Self::Bee(value) => value.encode(writer),
449 Self::VillagerBrain(value) => value.encode(writer),
450 Self::Breeze(value) => value.encode(writer),
451 Self::GoalSelector(value) => value.encode(writer),
452 Self::EntityPath(value) => value.encode(writer),
453 Self::EntityBlockIntersection(value) => value.encode(writer),
454 Self::BeeHive(value) => value.encode(writer),
455 Self::PointOfInterest(value) => value.encode(writer),
456 Self::RedstoneWireOrientation(value) => value.encode(writer),
457 Self::Raid(value) => value.encode(writer),
458 Self::Structure(value) => value.encode(writer),
459 Self::GameEventListener(value) => value.encode(writer),
460 Self::NeighborUpdate(value) => value.encode(writer),
461 Self::GameEvent(value) => value.encode(writer),
462 }
463 }
464
465 pub(crate) fn decode_payload(
466 subscription_type: DebugSubscriptionType,
467 reader: &mut impl Read,
468 ) -> Result<Self, CodecError> {
469 match subscription_type {
470 DebugSubscriptionType::DedicatedServerTickTime => Ok(Self::DedicatedServerTickTime),
471 DebugSubscriptionType::Bee => BeeDebugData::decode(reader).map(Self::Bee),
472 DebugSubscriptionType::VillagerBrain => {
473 VillagerBrainDebugData::decode(reader).map(Self::VillagerBrain)
474 }
475 DebugSubscriptionType::Breeze => BreezeDebugData::decode(reader).map(Self::Breeze),
476 DebugSubscriptionType::GoalSelector => {
477 GoalSelectorDebugData::decode(reader).map(Self::GoalSelector)
478 }
479 DebugSubscriptionType::EntityPath => {
480 EntityPathDebugData::decode(reader).map(Self::EntityPath)
481 }
482 DebugSubscriptionType::EntityBlockIntersection => {
483 EntityBlockIntersectionDebugData::decode(reader).map(Self::EntityBlockIntersection)
484 }
485 DebugSubscriptionType::BeeHive => BeeHiveDebugData::decode(reader).map(Self::BeeHive),
486 DebugSubscriptionType::PointOfInterest => {
487 PointOfInterestDebugData::decode(reader).map(Self::PointOfInterest)
488 }
489 DebugSubscriptionType::RedstoneWireOrientation => {
490 RedstoneWireOrientationDebugData::decode(reader).map(Self::RedstoneWireOrientation)
491 }
492 DebugSubscriptionType::VillageSection => Ok(Self::VillageSection),
493 DebugSubscriptionType::Raid => RaidDebugData::decode(reader).map(Self::Raid),
494 DebugSubscriptionType::Structure => {
495 StructureDebugData::decode(reader).map(Self::Structure)
496 }
497 DebugSubscriptionType::GameEventListener => {
498 GameEventListenerDebugData::decode(reader).map(Self::GameEventListener)
499 }
500 DebugSubscriptionType::NeighborUpdate => {
501 NeighborUpdateDebugData::decode(reader).map(Self::NeighborUpdate)
502 }
503 DebugSubscriptionType::GameEvent => {
504 GameEventDebugData::decode(reader).map(Self::GameEvent)
505 }
506 }
507 }
508}