1use std::cmp::max;
2use std::collections::HashMap;
3use crate::extension::parsers::stuffdata::StuffData;
4use crate::protocol::hpacket::HPacket;
5use crate::protocol::vars::legacy::{LegacyId, LegacyLength, LegacyDouble, LegacyStringId};
6use crate::protocol::vars::packetvariable::PacketVariable;
7
8#[derive(Clone, Debug, Default, PacketVariable, PartialEq, Eq)]
11pub struct FurnitureProductItem {
12 pub product_code: String,
13 pub furniture_class_name: String
14}
15
16#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
17pub struct OutgoingIngredient {
18 pub count: i32,
19 pub furniture_class_name: String
20}
21
22#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
23pub struct ExtendedProfileData {
24 pub user_id: LegacyId,
25 pub user_name: String,
26 pub figure: String,
27 pub motto: String,
28 pub creation_date: String,
29 pub achievement_score: i32,
30 pub friend_count: i32, pub is_friend: bool,
32 pub is_friend_request_sent: bool,
33 pub is_online: bool,
34 pub guilds: Vec<HabboGroupEntryData>,
35 pub last_access_since_in_seconds: i32,
36 pub open_profile_window: bool,
37 pub _unused1: Option<bool>,
38 pub account_level: Option<i32>,
39 pub _unused2: Option<i32>,
40 pub star_gem_count: Option<i32>,
41 pub _unused3: Option<bool>,
42 pub _unused4: Option<bool>
43}
44
45#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
46pub struct HabboGroupEntryData {
47 pub group_id: LegacyId,
48 pub group_name: String,
49 pub badge_code: String,
50 pub primary_color: String,
51 pub secondary_color: String,
52 pub favourite: bool,
53 pub owner_id: LegacyId,
54 pub has_forum: bool
55}
56
57#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
58pub struct MemberData {
59 pub role: i32,
60 pub user_id: LegacyId,
61 pub user_name: String,
62 pub figure: String,
63 pub member_since: String
64}
65
66#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
67pub struct GuildCreationData {
68 pub cost_in_credits: i32,
69 pub owned_rooms: Vec<RoomEntryData>,
70 pub badge_settings: Vec<GuildBadgeSettings>
71}
72
73#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
74pub struct RoomEntryData {
75 pub room_id: LegacyId,
76 pub room_name: String,
77 pub has_controllers: bool
78}
79
80#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
81pub struct GuildBadgeSettings {
82 pub part_id: i32,
83 pub color_id: i32,
84 pub position: i32
85}
86
87#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
88pub struct GuildEditData {
89 pub owned_rooms: Vec<RoomEntryData>,
90 pub is_owner: bool,
91 pub group_id: LegacyId,
92 pub group_name: String,
93 pub group_desc: String,
94 pub base_room_id: LegacyId,
95 pub primary_color_id: i32, pub secondary_color_id: i32, pub guild_type: i32,
98 pub guild_rights_level: i32,
99 pub locked: bool,
100 pub url: String,
101 pub badge_settings: Vec<GuildBadgeSettings>,
102 pub badge_code: String,
103 pub membership_count: i32
104}
105
106#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
107pub struct BadgePartData {
108 pub id: i32, pub file_name: String,
110 pub mask_file_name: String,
111}
112
113#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
114pub struct GuildColorData {
115 pub id: i32, pub color: String
117}
118
119#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
120pub struct GuildMemberData {
121 pub group_id: LegacyId,
122 pub group_name: String,
123 pub base_room_id: LegacyId,
124 pub badge_code: String,
125 pub total_entries: i32, pub entries: Vec<MemberData>,
127 pub allowed_to_manage: bool,
128 pub page_size: i32,
129 pub page_index: i32,
130 pub search_type: i32,
131 pub user_name_filter: String
132}
133
134#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
135pub struct HabboGroupDetailsData {
136 pub group_id: LegacyId,
137 pub is_guild: bool,
138 pub group_type: i32,
139 pub group_name: String,
140 pub description: String,
141 pub badge_code: String,
142 pub room_id: LegacyId,
143 pub room_name: String,
144 pub status: i32,
145 pub total_members: i32, pub favourite: bool,
147 pub creation_date: String,
148 pub is_owner: bool,
149 pub is_admin: bool,
150 pub open_details: bool,
151 pub members_can_decorate: bool,
152 pub pending_member_count: i32, pub has_board: bool
154}
155
156#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
157pub struct PetData {
158 pub id: LegacyId,
159 pub name: String,
160 pub figure_data: PetFigureData,
161 pub level: i32
162}
163
164#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
165pub struct PetFigureData {
166 pub type_id: i32, pub palette_id: i32, pub color: String,
169 pub breed_id: i32, pub custom_parts: Vec<(i32, i32, i32)>
171}
172
173#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
174pub struct RelationshipStatusInfoData {
175 pub relationship_status_type: i32,
176 pub friend_count: i32,
177 pub random_friend_id: LegacyId,
178 pub random_friend_name: String,
179 pub random_friend_figure: String
180}
181
182#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
183pub struct ScrKickbackData {
184 pub current_hc_streak: i32,
185 pub first_subscription_date: String,
186 pub kickback_percentage: f64,
187 pub total_credits_missed: i32,
188 pub total_credits_rewarded: i32,
189 pub total_credits_spent: i32,
190 pub credit_reward_for_streak_bonus: i32,
191 pub credit_reward_for_monthly_spent: i32,
192 pub time_until_payday: i32
193}
194
195#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
196pub struct RoomQueueSet {
197 pub name: String,
198 pub target: i32, pub queue: HashMap<String, i32> }
201
202#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
203pub struct BaseForumData {
204 pub group_id: LegacyId,
205 pub name: String,
206 pub description: String,
207 pub icon: String,
208 pub total_threads: i32,
209 pub leaderboard_score: i32,
210 pub total_messages: i32,
211 pub unread_messages: i32,
212 pub last_message_id: i32, pub last_message_author_id: LegacyId,
214 pub last_message_author_name: String,
215 pub last_message_time_as_seconds_ago: i32
216}
217
218#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
219pub struct ExtendedForumData {
220 pub base: BaseForumData,
221 pub read_permissions: i32,
222 pub post_message_permissions: i32,
223 pub post_thread_permissions: i32,
224 pub moderate_permissions: i32,
225 pub read_permission_error: String,
226 pub post_message_permission_error: String,
227 pub post_thread_permission_error: String,
228 pub moderate_permission_error: String,
229 pub report_permissions_error: String,
230 pub can_change_settings: bool,
231 pub is_staff: bool
232}
233
234#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
235pub struct ThreadData {
236 pub thread_id: LegacyId,
237 pub thread_author_id: LegacyId,
238 pub thread_author_name: String,
239 pub header: String,
240 pub is_sticky: bool,
241 pub is_locked: bool,
242 pub creation_time_as_seconds_ago: i32,
243 pub n_messages: i32,
244 pub n_unread_messages: i32,
245 pub last_message_id: LegacyId,
246 pub last_message_author_id: LegacyId,
247 pub last_message_author_name: String,
248 pub last_message_time_as_seconds_ago: i32,
249 pub state: i8,
250 pub admin_id: LegacyId,
251 pub admin_name: String,
252 pub admin_operation_time_as_seconds_ago: i32
253}
254
255#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
256pub struct MessageData {
257 pub message_id: LegacyId,
258 pub message_index: i32,
259 pub author_id: LegacyId,
260 pub author_name: String,
261 pub author_figure: String,
262 pub creation_time_as_seconds_ago: i32,
263 pub message_text: String,
264 pub state: i8,
265 pub admin_id: LegacyId,
266 pub admin_name: String,
267 pub admin_operation_time_as_seconds_ago: i32,
268 pub author_post_count: i32
269}
270
271#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
272pub struct AchievementResolutionData {
273 pub achievement_id: LegacyId,
274 pub level: i32,
275 pub badge_id: String,
276 pub required_level: i32,
277 pub state: i32
278}
279
280#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
281pub struct CategoriesWithVisitorCountData {
282 pub categories: Vec<CategoriesWithVisitorCountDataEntry>
283}
284
285#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
286pub struct CategoriesWithVisitorCountDataEntry {
287 pub category_id: i32, pub current_user_count: i32,
289 pub max_user_count: i32
290}
291
292#[derive(Clone, Debug, Default, PartialEq)]
293pub struct GuestRoomData {
294 pub flat_id: LegacyId,
295 pub room_name: String,
296 pub owner_id: LegacyId,
297 pub owner_name: String,
298 pub door_mode: i32,
299 pub user_count: i32,
300 pub max_user_count: i32,
301 pub description: String,
302 pub trade_mode: i32,
303 pub score: i32,
304 pub ranking: i32,
305 pub category_id: i32, pub tags: Vec<String>,
307 pub official_room_pic_ref: Option<String>,
308 pub habbo_group_id: Option<LegacyId>,
309 pub group_name: Option<String>,
310 pub group_badge_code: Option<String>,
311 pub room_ad_name: Option<String>,
312 pub room_ad_description: Option<String>,
313 pub room_ad_expires_in_min: Option<i32>,
314 pub show_owner: bool,
315 pub allow_pets: bool,
316 pub display_room_entry_ad: bool
317}
318
319impl PacketVariable for GuestRoomData {
320 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
321 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
322 let (flat_id, room_name, owner_id, owner_name, door_mode, user_count, max_user_count,
323 description, trade_mode, score, ranking, category_id, tags) = packet.read();
324
325 let multi_use: i32 = packet.read();
326
327 let official_room_pic_ref =
328 if (multi_use & 1) > 0 { Some(packet.read()) }
329 else { None };
330
331 let (habbo_group_id, group_name, group_badge_code) =
332 if (multi_use & 2) > 0 { packet.read() }
333 else { (None, None, None) };
334
335 let (room_ad_name, room_ad_description, room_ad_expires_in_min) =
336 if (multi_use & 4) > 0 { packet.read() }
337 else { (None, None, None) };
338
339 let show_owner = (multi_use & 8) > 0;
340 let allow_pets = (multi_use & 16) > 0;
341 let display_room_entry_ad = (multi_use & 32) > 0;
342
343 ( Self { flat_id, room_name, owner_id, owner_name, door_mode, user_count, max_user_count,
344 description, trade_mode, score, ranking, category_id, tags, official_room_pic_ref,
345 habbo_group_id, group_name, group_badge_code, room_ad_name, room_ad_description,
346 room_ad_expires_in_min, show_owner, allow_pets, display_room_entry_ad },
347 packet.read_index - 6
348 )
349 }
350
351 fn to_packet(&self) -> Vec<u8> {
352 let mut packet = HPacket::from_header_id(0);
353 packet.append((self.flat_id, self.room_name.clone(), self.owner_id,
354 self.owner_name.clone(), self.door_mode, self.user_count,
355 self.max_user_count, self.description.clone(), self.trade_mode,
356 self.score, self.ranking, self.category_id, self.tags.clone()));
357
358 let mut multi_use = 0;
359 if self.official_room_pic_ref.is_some() {
360 multi_use |= 1;
361 }
362 if self.habbo_group_id.is_some() && self.group_name.is_some() && self.group_badge_code.is_some() {
363 multi_use |= 2;
364 }
365 if self.room_ad_name.is_some() && self.room_ad_description.is_some() && self.room_ad_expires_in_min.is_some() {
366 multi_use |= 4;
367 }
368 if self.show_owner {
369 multi_use |= 8;
370 }
371 if self.allow_pets {
372 multi_use |= 16;
373 }
374 if self.display_room_entry_ad {
375 multi_use |= 32;
376 }
377
378 packet.append(multi_use);
379 if self.official_room_pic_ref.is_some() {
380 packet.append(self.official_room_pic_ref.clone());
381 }
382 if self.habbo_group_id.is_some() && self.group_name.is_some() && self.group_badge_code.is_some() {
383 packet.append((self.habbo_group_id, self.group_name.clone(), self.group_badge_code.clone()));
384 }
385 if self.room_ad_name.is_some() && self.room_ad_description.is_some() && self.room_ad_expires_in_min.is_some() {
386 packet.append((self.room_ad_name.clone(), self.room_ad_description.clone(), self.room_ad_expires_in_min));
387 }
388
389 packet.get_bytes()[6..].to_vec()
390 }
391}
392
393#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
394pub struct RoomModerationSettings {
395 pub who_can_mute: i32,
396 pub who_can_kick: i32,
397 pub who_can_ban: i32
398}
399
400#[derive(Clone, Debug, Default, PartialEq)]
401pub struct GuestRoomSearchResultData {
402 pub search_type: i32,
403 pub search_param: String,
404 pub rooms: Vec<GuestRoomData>,
405 pub ad: Option<OfficialRoomEntryData>
406}
407
408impl PacketVariable for GuestRoomSearchResultData {
409 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
410 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
411
412 let (search_type, search_param, rooms, has_ad) = packet.read();
413 let ad = if has_ad { packet.read() } else { None };
414
415 (GuestRoomSearchResultData { search_type, search_param, rooms, ad }, packet.read_index - 6)
416 }
417
418 fn to_packet(&self) -> Vec<u8> {
419 let mut packet = HPacket::from_header_id(0);
420
421 packet.append((self.search_type, self.search_param.clone(), self.rooms.clone(),
422 self.ad.is_some(), self.ad.clone()));
423
424 packet.get_bytes()[6..].to_vec()
425 }
426}
427
428#[derive(Clone, Debug, Default, PartialEq)]
429pub struct OfficialRoomEntryData {
430 pub index: i32,
431 pub popup_caption: String,
432 pub popup_desc: String,
433 pub show_details: bool,
434 pub pic_text: String,
435 pub pic_ref: String,
436 pub folder_id: i32, pub user_count: i32,
438 pub entry_type: i32,
439 pub tag: Option<String>,
440 pub guest_room_data: Option<GuestRoomData>,
441 pub open: Option<bool>
442}
443
444impl PacketVariable for OfficialRoomEntryData {
445 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
446 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
447
448 let (index, popup_caption, popup_desc, show_details, pic_text,
449 pic_ref, folder_id, user_count, entry_type) = packet.read();
450
451 let (mut tag, mut guest_room_data, mut open) = (None, None, None);
452 if entry_type == 1 {
453 tag = packet.read();
454 } else if entry_type == 2 {
455 guest_room_data = packet.read();
456 } else {
457 open = packet.read();
458 }
459
460 (
461 OfficialRoomEntryData { index, popup_caption, popup_desc, show_details, pic_text,
462 pic_ref, folder_id, user_count, entry_type, tag, guest_room_data, open },
463 packet.read_index - 6
464 )
465 }
466
467 fn to_packet(&self) -> Vec<u8> {
468 let mut packet = HPacket::from_header_id(0);
469
470 packet.append((self.index, self.popup_caption.clone(), self.popup_desc.clone(),
471 self.show_details, self.pic_text.clone(), self.pic_ref.clone(),
472 self.folder_id, self.user_count, self.entry_type));
473 if self.entry_type == 1 {
474 packet.append(self.tag.clone());
475 } else if self.entry_type == 2 {
476 packet.append(self.guest_room_data.clone());
477 } else {
478 packet.append(self.open);
479 }
480
481 packet.get_bytes()[6..].to_vec()
482 }
483}
484
485#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
486pub struct OfficialRoomsData {
487 pub entries: Vec<OfficialRoomEntryData>
488}
489
490#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
491pub struct PromotedRoomsData {
492 pub entries: Vec<PromotedRoomCategoryData>
493}
494
495#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
496pub struct PromotedRoomCategoryData {
497 pub code: String,
498 pub leader_figure: String,
499 pub rooms: Vec<GuestRoomData>
500}
501
502#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
503pub struct PopularRoomTagsData {
504 pub tags: Vec<PopularTagData>
505}
506
507#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
508pub struct PopularTagData {
509 pub tag_name: String,
510 pub user_count: i32
511}
512
513#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
514pub struct RoomEventData {
515 pub ad_id: LegacyId,
516 pub owner_avatar_id: LegacyId,
517 pub owner_avatar_name: String,
518 pub flat_id: LegacyId,
519 pub event_type: i32,
520 pub event_name: String,
521 pub event_description: String,
522 pub creation_time: i32,
523 pub expiration_date: i32,
524 pub category_id: i32 }
526
527#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
528pub struct EventCategory {
529 pub category_id: i32, pub category_name: String,
531 pub visible: bool
532}
533
534#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
535pub struct FlatCategory {
536 pub node_id: i32, pub node_name: String,
538 pub visible: bool,
539 pub automatic: bool,
540 pub automatic_category_key: String,
541 pub global_category_key: String,
542 pub staff_only: bool
543}
544
545#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
546pub struct RoomDimmerPresetsMessageData {
547 pub id: LegacyId,
548 pub dimmer_type: i32,
549 pub color: String,
550 pub light: i32
551}
552
553#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
554pub struct YoutubeDisplayPlaylist {
555 pub playlist_id: String,
556 pub title: String,
557 pub description: String
558}
559
560#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
561pub struct CfhChatlogData {
562 pub call_id: LegacyId,
563 pub caller_user_id: LegacyId,
564 pub reported_user_id: LegacyId,
565 pub chat_record_id: LegacyId,
566 pub chat_record: ChatRecordData
567}
568
569#[derive(Clone, Debug, Default, PartialEq)]
570pub struct ChatRecordData {
571 pub record_type: i8,
572 pub context: HashMap<String, ChatRecordDataValue>,
573 pub chat_log: Vec<ChatlineData>
574}
575
576#[derive(Clone, Debug, PartialEq)]
577pub enum ChatRecordDataValue {
578 String(String),
579 Int(i32),
580 Bool(bool)
581}
582
583impl PacketVariable for ChatRecordData {
584 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
585 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
586
587 let record_type = packet.read();
588 let mut context = HashMap::new();
589 let length: i16 = packet.read();
590 for _ in 0..length {
591 let key = packet.read();
592 let val = match packet.read::<i8>() {
593 0 => ChatRecordDataValue::Bool(packet.read()),
594 1 => ChatRecordDataValue::Int(packet.read()),
595 2 => ChatRecordDataValue::String(packet.read()),
596 _ => panic!("Unknown data type")
597 };
598 context.insert(key, val);
599 }
600 let chat_log = packet.read();
601
602 (ChatRecordData { record_type, context, chat_log }, packet.read_index - 6)
603 }
604
605 fn to_packet(&self) -> Vec<u8> {
606 let mut packet = HPacket::from_header_id(0);
607
608 packet.append(self.record_type);
609 packet.append(self.context.len() as i16);
610 for (key, val) in self.context.clone() {
611 packet.append(key);
612 match val {
613 ChatRecordDataValue::Bool(b) => packet.append(b),
614 ChatRecordDataValue::Int(i) => packet.append(i),
615 ChatRecordDataValue::String(s) => packet.append(s.clone())
616 };
617 }
618 packet.append(self.chat_log.clone());
619
620 packet.get_bytes()[6..].to_vec()
621 }
622}
623
624#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
625pub struct ChatlineData {
626 pub timestamp: String,
627 pub chatter_id: LegacyId,
628 pub chatter_name: String,
629 pub msg: String,
630 pub has_highlighting: bool
631}
632
633#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
634pub struct IssueMessageData {
635 pub issue_id: LegacyId,
636 pub state: i32,
637 pub category_id: LegacyId,
638 pub reported_category_id: i32, pub issue_age_in_milliseconds: i32,
640 pub priority: i32,
641 pub grouping_id: i32, pub reporter_user_id: LegacyId,
643 pub reporter_user_name: String,
644 pub reported_user_id: LegacyId,
645 pub reported_user_name: String,
646 pub picker_user_id: LegacyId,
647 pub picker_user_name: String,
648 pub message: String,
649 pub chat_record_id: LegacyId,
650 pub patterns: Vec<PatternMatchData>
651}
652
653#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
654pub struct PatternMatchData {
655 pub pattern: String,
656 pub start_index: i32,
657 pub end_index: i32
658}
659
660#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
661pub struct ModeratorInitData {
662 pub issues: Vec<IssueMessageData>,
663 pub message_templates: Vec<String>,
664 pub _unused: Vec<String>,
665 pub cfh_permission: bool,
666 pub chatlogs_permission: bool,
667 pub alert_permission: bool,
668 pub kick_permission: bool,
669 pub ban_permission: bool,
670 pub room_alert_permission: bool,
671 pub room_kick_permission: bool,
672 pub room_message_templates: Vec<String>
673}
674
675#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
676pub struct RoomModerationData {
677 pub flat_id: LegacyId,
678 pub user_count: i32,
679 pub owner_in_room: bool,
680 pub owner_id: LegacyId,
681 pub owner_name: String,
682 pub room: RoomData
683}
684
685#[derive(Clone, Debug, Default, PartialEq)]
686pub struct RoomData {
687 pub exists: bool,
688 pub name: Option<String>,
689 pub desc: Option<String>,
690 pub tags: Option<Vec<String>>
691}
692
693impl PacketVariable for RoomData {
694 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
695 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
696
697 let exists = packet.read();
698 (RoomData {
699 exists,
700 name: if exists { packet.read() } else { None },
701 desc: if exists { packet.read() } else { None },
702 tags: if exists { packet.read() } else { None },
703 }, packet.read_index - 6)
704 }
705
706 fn to_packet(&self) -> Vec<u8> {
707 let mut packet = HPacket::from_header_id(0);
708
709 packet.append(self.exists);
710 if self.exists {
711 packet.append((self.name.clone(), self.desc.clone(), self.tags.clone()));
712 }
713
714 packet.get_bytes()[6..].to_vec()
715 }
716}
717
718#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
719pub struct ModeratorUserInfoData {
720 pub user_id: LegacyId,
721 pub user_name: String,
722 pub figure: String,
723 pub registration_age_in_minutes: i32,
724 pub minutes_since_last_login: i32,
725 pub online: bool,
726 pub cfh_count: i32,
727 pub abusive_cfh_count: i32,
728 pub caution_count: i32,
729 pub ban_count: i32,
730 pub trading_lock_count: i32,
731 pub trading_expiry_date: String,
732 pub last_purchase_date: String,
733 pub identity_id: LegacyId,
734 pub identity_related_ban_count: i32,
735 pub primary_email_address: String,
736 pub user_classification: String,
737 pub last_sanction_time: Option<String>,
738 pub sanction_age_hours: Option<i32>
739}
740
741#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
742pub struct RoomVisitsData {
743 pub user_id: LegacyId,
744 pub user_name: String,
745 pub rooms: Vec<RoomVisitData>
746}
747
748#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
749pub struct RoomVisitData {
750 pub room_id: LegacyId,
751 pub room_name: String,
752 pub enter_hour: i32,
753 pub enter_minute: i32
754}
755
756#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
757pub struct UserChatlogData {
758 pub user_id: LegacyId,
759 pub user_name: String,
760 pub rooms: Vec<ChatRecordData>
761}
762
763#[derive(Clone, Debug, Default, PartialEq)]
764pub struct PollQuestion {
765 pub question_id: LegacyId,
766 pub sort_order: i32,
767 pub question_type: i32,
768 pub question_text: String,
769 pub question_category: i32,
770 pub question_answer_type: i32,
771 pub question_answer_count: LegacyLength,
772 pub question_choices: Vec<PollChoice>,
773 pub children: Vec<PollQuestion>
774}
775
776impl PacketVariable for PollQuestion {
777 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
778 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
779
780 let (question_id, sort_order, question_type, question_text, question_category,
781 question_answer_type) = packet.read();
782 let question_answer_count: LegacyLength = packet.read();
783 let mut question_choices = Vec::new();
784 let children = Vec::new();
785 if question_type == 1 || question_type == 2 {
786 for _ in 0..*question_answer_count {
787 question_choices.push(packet.read())
788 }
789 }
790
791 (PollQuestion {
792 question_id, sort_order, question_type, question_text, question_category,
793 question_answer_type, question_answer_count, question_choices, children
794 }, packet.read_index - 6)
795 }
796
797 fn to_packet(&self) -> Vec<u8> {
798 let mut packet = HPacket::from_header_id(0);
799
800 packet.append((
801 self.question_id, self.sort_order, self.question_type, self.question_text.clone(),
802 self.question_category, self.question_answer_type, self.question_answer_count
803 ));
804 if self.question_type == 1 || self.question_type == 2 {
805 for choice in self.question_choices.iter() {
806 packet.append(choice.clone());
807 }
808 }
809
810 packet.get_bytes()[6..].to_vec()
811 }
812}
813
814#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
815pub struct PollChoice {
816 pub value: String,
817 pub choice_text: String,
818 pub choice_type: i32
819}
820
821#[derive(Clone, Debug, Default, PartialEq)]
822pub struct QuestionData {
823 pub id: LegacyId,
824 pub number: i32,
825 pub question_type: i32,
826 pub content: String,
827 pub selection_min: i32,
828 pub selection_values: Vec<String>,
829 pub selections: Vec<String>
830}
831
832impl PacketVariable for QuestionData {
833 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
834 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
835
836 let (id, number, question_type, content) = packet.read();
837
838 let mut selection_values = Vec::new();
839 let mut selections = Vec::new();
840 let mut selection_min = -1;
841
842 if question_type == 1 || question_type == 2 {
843 selection_min = packet.read();
844 let count: i32 = packet.read();
845 for _ in 0..count {
846 selection_values.push(packet.read());
847 selections.push(packet.read());
848 }
849 }
850
851 (Self {
852 id, number, question_type, content,
853 selection_min, selection_values, selections
854 }, packet.read_index - 6)
855 }
856
857 fn to_packet(&self) -> Vec<u8> {
858 let mut packet = HPacket::from_header_id(0);
859
860 packet.append((self.id, self.number, self.question_type, self.content.clone()));
861 if self.question_type == 1 || self.question_type == 2 {
862 let len = max(self.selections.len(), self.selection_values.len());
863 packet.append((
864 self.selection_min,
865 len as i32
866 ));
867 for i in 0..len {
868 packet.append((
869 self.selection_values.get(i).unwrap().clone(),
870 self.selections.get(i).unwrap().clone()
871 ));
872 }
873 }
874
875 packet.get_bytes()[6..].to_vec()
876 }
877}
878
879#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
880pub struct CatalogNodeData {
881 pub visible: bool,
882 pub icon: i32,
883 pub page_id: LegacyId,
884 pub page_name: String,
885 pub localization: String,
886 pub offer_ids: Vec<LegacyId>,
887 pub children: Vec<CatalogNodeData>
888}
889
890#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
891pub struct CatalogLocalizationData {
892 pub images: Vec<String>,
893 pub texts: Vec<String>
894}
895
896#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
897pub struct CatalogPageMessageOfferData {
898 pub offer_id: LegacyId,
899 pub localization_id: String,
900 pub is_rent: bool,
901 pub price_in_credits: i32,
902 pub price_in_activity_points: i32,
903 pub activity_point_type: i32,
904 pub giftable: bool,
905 pub products: Vec<CatalogPageMessageProductData>,
906 pub club_level: i32,
907 pub bundle_purchase_allowed: bool,
908 pub _unused: bool,
909 pub preview_image: String
910}
911
912#[derive(Clone, Debug, Default, PartialEq)]
913pub struct CatalogPageMessageProductData {
914 pub product_type: String,
915 pub furni_class_id: LegacyId,
916 pub extra_param: String,
917 pub product_count: i32,
918 pub unique_limited_item: bool,
919 pub unique_limited_item_series_size: i32,
920 pub unique_limited_items_left: i32
921}
922
923impl PacketVariable for CatalogPageMessageProductData {
924 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
925 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
926
927 let product_type: String = packet.read();
928 let mut furni_class_id = LegacyId(-1);
929 let extra_param: String;
930 let mut product_count = 1;
931 let mut unique_limited_item = false;
932 let mut unique_limited_item_series_size = -1;
933 let mut unique_limited_items_left = -1;
934 if product_type.ne(&String::from("b")) {
935 (furni_class_id, extra_param, product_count, unique_limited_item) = packet.read();
936 if unique_limited_item {
937 (unique_limited_item_series_size, unique_limited_items_left) = packet.read();
938 }
939 } else {
940 extra_param = packet.read();
941 }
942
943 (Self {
944 product_type,
945 furni_class_id,
946 extra_param: extra_param.clone(),
947 product_count,
948 unique_limited_item,
949 unique_limited_item_series_size,
950 unique_limited_items_left
951 }, packet.read_index - 6)
952 }
953
954 fn to_packet(&self) -> Vec<u8> {
955 let mut packet = HPacket::from_header_id(0);
956
957 packet.append(self.product_type.clone());
958
959 if self.product_type.ne(&String::from("b")) {
960 packet.append((
961 self.furni_class_id, self.extra_param.clone(),
962 self.product_count, self.unique_limited_item
963 ));
964 if self.unique_limited_item {
965 packet.append((
966 self.unique_limited_item_series_size,
967 self.unique_limited_items_left
968 ));
969 }
970 } else {
971 packet.append(self.extra_param.clone());
972 }
973
974 packet.get_bytes()[6..].to_vec()
975 }
976}
977
978#[derive(Clone, Debug, Default, PartialEq)]
979pub struct FrontPageItem {
980 pub position: i32,
981 pub item_name: String,
982 pub item_promo_image: String,
983 pub item_type: i32,
984 pub catalogue_page_location: String,
985 pub product_offer_id: LegacyId,
986 pub product_code: String,
987 pub expiration_time: i32
988}
989
990impl PacketVariable for FrontPageItem {
991 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
992 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
993
994 let mut res = Self::default();
995 (res.position, res.item_name, res.item_promo_image, res.item_type) = packet.read();
996 match res.item_type {
997 0 => res.catalogue_page_location = packet.read(),
998 1 => res.product_offer_id = packet.read(),
999 2 => res.product_code = packet.read(),
1000 _ => panic!("Unknown item type")
1001 }
1002 res.expiration_time = packet.read();
1003
1004 (res.clone(), packet.read_index - 6)
1005 }
1006
1007 fn to_packet(&self) -> Vec<u8> {
1008 let mut packet = HPacket::from_header_id(0);
1009
1010 packet.append((
1011 self.position, self.item_name.clone(),
1012 self.item_promo_image.clone(), self.item_type
1013 ));
1014 match self.item_type {
1015 0 => packet.append(self.catalogue_page_location.clone()),
1016 1 => packet.append(self.product_offer_id),
1017 2 => packet.append(self.product_code.clone()),
1018 _ => panic!("Unknown item type")
1019 }
1020 packet.append(self.expiration_time);
1021
1022 packet.get_bytes()[6..].to_vec()
1023 }
1024}
1025
1026#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1027pub struct ClubGiftData {
1028 pub offer_id: LegacyId,
1029 pub is_vip: bool,
1030 pub days_required: i32,
1031 pub is_selectable: bool
1032}
1033
1034#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1035pub struct ClubOfferExtendData {
1036 pub original_price: i32,
1037 pub original_activity_point_price: i32,
1038 pub original_activity_point_type: i32,
1039 pub discount_credit_amount: i32
1040}
1041
1042#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1043pub struct PurchaseOKMessageOfferData {
1044 pub offer_id: LegacyId,
1045 pub localization_id: String,
1046 pub is_rent: bool,
1047 pub price_in_credits: i32,
1048 pub price_in_activity_points: i32,
1049 pub activity_point_type: i32,
1050 pub giftable: bool,
1051 pub products: Vec<CatalogPageMessageProductData>,
1052 pub club_level: i32,
1053 pub bundle_purchase_allowed: bool
1054}
1055
1056#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1057pub struct SellablePetPaletteData {
1058 pub palette_type: i32,
1059 pub breed_id: LegacyId,
1060 pub palette_id: LegacyId,
1061 pub sellable: bool,
1062 pub rare: bool
1063}
1064
1065#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1066pub struct SnowWarGameTokenOffer {
1067 pub offer_id: LegacyId,
1068 pub localization_id: String,
1069 pub price_in_credits: i32,
1070 pub price_in_activity_points: i32,
1071 pub activity_point_type: i32
1072}
1073
1074#[derive(Clone, Debug, Default, PartialEq)]
1075pub struct HeightMapTile {
1076 pub height: f32,
1077 pub is_stacking_blocked: bool,
1078 pub is_room_tile: bool
1079}
1080
1081impl PacketVariable for HeightMapTile {
1082 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
1083 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
1084
1085 let val: i16 = packet.read();
1086
1087 (Self {
1088 height: if val < 0 { -1.0 } else { (val & 16383) as f32 / 256.0 },
1089 is_stacking_blocked: (val & 16384) > 0,
1090 is_room_tile: val >= 0
1091 }, packet.read_index - 6)
1092 }
1093
1094 fn to_packet(&self) -> Vec<u8> {
1095 if !self.is_room_tile {
1096 (-1i16).to_packet()
1097 } else {
1098 let mut val: i16 = 0;
1099
1100 if self.is_stacking_blocked {
1101 val |= 16384;
1102 }
1103 val |= (self.height * 256.0) as i16 & 16383;
1104
1105 val.to_packet()
1106 }
1107 }
1108}
1109
1110#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1111pub struct HeightMapTileUpdate {
1112 pub x: i8,
1113 pub y: i8,
1114 pub tile: HeightMapTile
1115}
1116
1117#[derive(Clone, Debug, Default, PartialEq)]
1118pub struct WallItem {
1119 pub id: LegacyStringId,
1120 pub type_id: i32,
1121 pub location: String,
1122 pub data_str: String,
1123 pub seconds_to_expiration: i32,
1124 pub usage_policy: i32,
1125 pub owner_id: LegacyId,
1126 pub owner_name: Option<String>
1127}
1128
1129impl PacketVariable for WallItem {
1130 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
1131 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
1132
1133 let (id, type_id, location, data_str, seconds_to_expiration, usage_policy, owner_id) = packet.read();
1134
1135 (Self {
1136 id, type_id, location, data_str, seconds_to_expiration, usage_policy, owner_id,
1137 owner_name: None
1138 }, packet.read_index - 6)
1139 }
1140
1141 fn to_packet(&self) -> Vec<u8> {
1142 (
1143 self.id, self.type_id, self.location.clone(), self.data_str.clone(),
1144 self.seconds_to_expiration, self.usage_policy, self.owner_id
1145 ).to_packet()
1146 }
1147}
1148
1149#[derive(Clone, Debug, PartialEq)]
1150pub struct FloorItem {
1151 pub id: LegacyId,
1152 pub type_id: i32,
1153 pub x: i32,
1154 pub y: i32,
1155 pub dir: i32,
1156 pub z: LegacyDouble,
1157 pub size_z: LegacyDouble,
1158 pub extra: i32,
1159 pub data: StuffData,
1160 pub expiry_time: i32,
1161 pub usage_policy: i32,
1162 pub owner_id: LegacyId,
1163 pub static_class: String,
1164 pub owner_name: Option<String>
1165}
1166
1167impl PacketVariable for FloorItem {
1168 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
1169 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
1170
1171 let (id, type_id, x, y, dir, z, size_z, extra, data, expiry_time, usage_policy, owner_id) = packet.read();
1172
1173 (Self {
1174 id, type_id, x, y, dir, z, size_z, extra, data, expiry_time, usage_policy, owner_id,
1175 static_class: if *id < 0 { packet.read() } else { "".to_string()},
1176 owner_name: None
1177 }, packet.read_index - 6)
1178 }
1179
1180 fn to_packet(&self) -> Vec<u8> {
1181 let mut packet = HPacket::from_header_id(0);
1182 packet.append((
1183 self.id, self.type_id, self.x, self.y, self.dir, self.z, self.size_z,
1184 self.extra, self.data.clone(), self.expiry_time, self.usage_policy, self.owner_id
1185 ));
1186
1187 if *self.id < 0 {
1188 packet.append(self.static_class.clone());
1189 }
1190
1191 packet.get_bytes()[6..].to_vec()
1192 }
1193}
1194
1195#[derive(Clone, Debug, Default, PacketVariable, PartialEq, Eq)]
1196pub struct SlideObjectHeight {
1197 pub old_z: i32,
1198 pub new_z: i32,
1199}
1200
1201#[derive(Clone, Debug, PartialEq)]
1202pub enum User {
1203 Player {
1204 id: LegacyId,
1205 name: String,
1206 custom: String,
1207 figure: String,
1208 room_index: i32,
1209 x: i32,
1210 y: i32,
1211 z: LegacyDouble,
1212 dir: i32,
1213 sex: String,
1214 group_id: LegacyId,
1215 group_status: i32,
1216 group_name: String,
1217 swim_figure: String,
1218 achievement_score: i32,
1219 is_moderator: bool
1220 },
1221 Pet {
1222 id: LegacyId,
1223 name: String,
1224 custom: String,
1225 figure: String,
1226 room_index: i32,
1227 x: i32,
1228 y: i32,
1229 z: LegacyDouble,
1230 dir: i32,
1231 sub_type: i32,
1232 owner_id: LegacyId,
1233 owner_name: String,
1234 rarity_level: i32,
1235 has_saddle: bool,
1236 is_riding: bool,
1237 can_breed: bool,
1238 can_harvest: bool,
1239 can_revive: bool,
1240 has_breeding_permission: bool,
1241 pet_level: i32,
1242 pet_posture: String
1243 },
1244 OldBot {
1245 id: LegacyId,
1246 name: String,
1247 custom: String,
1248 figure: String,
1249 room_index: i32,
1250 x: i32,
1251 y: i32,
1252 z: LegacyDouble,
1253 dir: i32
1254 },
1255 Bot {
1256 id: LegacyId,
1257 name: String,
1258 custom: String,
1259 figure: String,
1260 room_index: i32,
1261 x: i32,
1262 y: i32,
1263 z: LegacyDouble,
1264 dir: i32,
1265 sex: String,
1266 owner_id: LegacyId,
1267 owner_name: String,
1268 bot_skills: Vec<i16>
1269 }
1270}
1271
1272impl PacketVariable for User {
1273 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
1274 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
1275
1276 let (id, name, custom, figure, room_index, x, y, z, dir) = packet.read();
1277
1278 (match packet.read::<i32>() {
1279 1 => User::Player {
1280 id, name, custom, figure, room_index, x, y, z, dir,
1281 sex: packet.read(),
1282 group_id: packet.read(),
1283 group_status: packet.read(),
1284 group_name: packet.read(),
1285 swim_figure: packet.read(),
1286 achievement_score: packet.read(),
1287 is_moderator: packet.read()
1288 },
1289 2 => User::Pet {
1290 id, name, custom, figure, room_index, x, y, z, dir,
1291 sub_type: packet.read(),
1292 owner_id: packet.read(),
1293 owner_name: packet.read(),
1294 rarity_level: packet.read(),
1295 has_saddle: packet.read(),
1296 is_riding: packet.read(),
1297 can_breed: packet.read(),
1298 can_harvest: packet.read(),
1299 can_revive: packet.read(),
1300 has_breeding_permission: packet.read(),
1301 pet_level: packet.read(),
1302 pet_posture: packet.read()
1303 },
1304 3 => User::OldBot {
1305 id, name, custom, figure, room_index, x, y, z, dir
1306 },
1307 4 => User::Bot {
1308 id,
1309 name,
1310 custom,
1311 figure,
1312 room_index,
1313 x,
1314 y,
1315 z,
1316 dir,
1317 sex: packet.read(),
1318 owner_id: packet.read(),
1319 owner_name: packet.read(),
1320 bot_skills: packet.read()
1321 },
1322 _ => panic!("Unknown user type")
1323 }, packet.read_index - 6)
1324 }
1325
1326 fn to_packet(&self) -> Vec<u8> {
1327 match self {
1328 User::Player { id, name, custom, figure,
1329 room_index, x, y, z, dir, sex,
1330 group_id, group_status, group_name, swim_figure,
1331 achievement_score, is_moderator } => {
1332 (
1333 *id, name.clone(), custom.clone(), figure.clone(), *room_index, *x, *y, *z,
1334 *dir, 1, sex.clone(), *group_id, *group_status, group_name.clone(),
1335 swim_figure.clone(), *achievement_score, *is_moderator
1336 ).to_packet()
1337 },
1338 User::Pet { id, name, custom, figure,
1339 room_index, x, y, z, dir, sub_type,
1340 owner_id, owner_name, rarity_level, has_saddle,
1341 is_riding, can_breed, can_harvest, can_revive,
1342 has_breeding_permission, pet_level, pet_posture } => {
1343 (
1344 *id, name.clone(), custom.clone(), figure.clone(), *room_index, *x, *y, *z,
1345 *dir, 2, *sub_type, *owner_id, owner_name.clone(), *rarity_level, *has_saddle,
1346 *is_riding, *can_breed, *can_harvest, *can_revive, *has_breeding_permission,
1347 *pet_level, pet_posture.clone()
1348 ).to_packet()
1349 },
1350 User::OldBot { id, name, custom, figure,
1351 room_index, x, y, z, dir } => {
1352 (
1353 *id, name.clone(), custom.clone(), figure.clone(),
1354 *room_index, *x, *y, *z, *dir, 3
1355 ).to_packet()
1356 },
1357 User::Bot { id, name, custom, figure,
1358 room_index, x, y, z, dir,
1359 sex, owner_id, owner_name, bot_skills } => {
1360 (
1361 *id, name.clone(), custom.clone(), figure.clone(),
1362 *room_index, *x, *y, *z, *dir, 4,
1363 sex.clone(), *owner_id, owner_name.clone(), bot_skills.clone()
1364 ).to_packet()
1365 }
1366 }
1367 }
1368}
1369
1370#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1371pub struct UserUpdateMessageData {
1372 pub index: i32,
1373 pub x: i32,
1374 pub y: i32,
1375 pub z: LegacyDouble,
1376 pub dir_head: i32,
1377 pub dir: i32,
1378 pub actions: Vec<UserUpdateAction>
1379}
1380
1381#[derive(Clone, Debug, PartialEq)]
1382pub enum UserUpdateAction {
1383 UserFlatControl {
1384 level: i32
1385 },
1386 SkipPositionUpdate,
1387 Move {
1388 x: i32,
1389 y: i32,
1390 z: f64
1391 },
1392 Sit {
1393 local_z: f64,
1394 can_stand_up: bool
1395 },
1396 Lay {
1397 local_z: f64,
1398 },
1399 Sign {
1400 id: i32
1401 },
1402 Gesture {
1403 gesture: Gesture
1404 },
1405 Posture {
1406 posture: Posture
1407 }
1408}
1409
1410impl UserUpdateAction {
1411 fn identify(action: &str) -> Option<Self> {
1412 let split: Vec<&str> = action.split(" ").collect();
1413
1414 match split[..] {
1415 [ "wf" ] => Some(Self::SkipPositionUpdate),
1416 [ key ] => Some(Self::Posture {
1417 posture: Posture::identify(key)
1418 }),
1419 [ "flatctrl", lvl ] => Some(Self::UserFlatControl {
1420 level: lvl.parse::<i32>().unwrap()
1421 }),
1422 [ "sit", z ] => Some(Self::Sit {
1423 local_z: z.parse::<f64>().unwrap(),
1424 can_stand_up: false
1425 }),
1426 [ "sit", z, stand ] => Some(Self::Sit {
1427 local_z: z.parse::<f64>().unwrap(),
1428 can_stand_up: stand == "1"
1429 }),
1430 [ "gst", key ] => Some(Self::Gesture {
1431 gesture: Gesture::identify(key)
1432 }),
1433 [ "sign", num ] => Some(Self::Sign {
1434 id: num.parse::<i32>().unwrap()
1435 }),
1436 [ "lay", z ] => Some(Self::Lay {
1437 local_z: z.parse::<f64>().unwrap()
1438 }),
1439 [ "mv", coords ] => {
1440 let split_coords: Vec<&str> = coords.split(',').collect();
1441 Some(Self::Move {
1442 x: split_coords[0].parse::<i32>().unwrap(),
1443 y: split_coords[1].parse::<i32>().unwrap(),
1444 z: split_coords[2].parse::<f64>().unwrap()
1445 })
1446 },
1447 [ .. ] => None
1448 }
1449 }
1450}
1451
1452impl ToString for UserUpdateAction {
1453 fn to_string(&self) -> String {
1454 match self {
1455 UserUpdateAction::UserFlatControl { level } =>
1456 format!("{level}"),
1457 UserUpdateAction::SkipPositionUpdate =>
1458 format!("wf"),
1459 UserUpdateAction::Move { x, y, z } =>
1460 format!("mv {x},{y},{z}"),
1461 UserUpdateAction::Sit { local_z, can_stand_up } =>
1462 format!("sit {local_z} {}", *can_stand_up as i32),
1463 UserUpdateAction::Lay { local_z } =>
1464 format!("lay {local_z}"),
1465 UserUpdateAction::Sign { id } =>
1466 format!("sign {id}"),
1467 UserUpdateAction::Gesture { gesture } =>
1468 format!("gst {}", gesture.to_string()),
1469 UserUpdateAction::Posture { posture } =>
1470 format!("{}", posture.to_string())
1471 }
1472 }
1473}
1474
1475impl PacketVariable for Vec<UserUpdateAction> {
1476 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
1477 let (str, size) = String::from_packet(bytes);
1478
1479 let mut actions = Vec::new();
1480 for s in str.split('/') {
1481 if s != "" {
1482 let action = UserUpdateAction::identify(s);
1483 if action.is_some() {
1484 actions.push(action.unwrap())
1485 }
1486 }
1487 }
1488
1489 (actions, size)
1490 }
1491
1492 fn to_packet(&self) -> Vec<u8> {
1493 let mut res = "/".to_string();
1494 for action in self {
1495 res += action.to_string().as_str();
1496 res += "/"
1497 }
1498
1499 res.to_packet()
1500 }
1501}
1502
1503#[derive(Clone, Debug, PartialEq)]
1504pub enum Posture {
1505 Lay,
1506 Move,
1507 Stand,
1508 Swim,
1509 Float,
1510 Sit,
1511 SnowWarRun,
1512 SnowWarDieFront,
1513 SnowWarDieBack,
1514 SnowWarPick,
1515 SnowWarThrow,
1516 Other(String)
1517}
1518
1519impl ToString for Posture {
1520 fn to_string(&self) -> String {
1521 match self {
1522 Self::Lay => "lay",
1523 Self::Move => "mv",
1524 Self::Stand => "std",
1525 Self::Swim => "swim",
1526 Self::Float => "float",
1527 Self::Sit => "sit",
1528 Self::SnowWarRun => "swrun",
1529 Self::SnowWarDieFront => "swdiefront",
1530 Self::SnowWarDieBack => "swdieback",
1531 Self::SnowWarPick => "swpick",
1532 Self::SnowWarThrow => "swthrow",
1533 Self::Other(key) => key
1534 }.to_string()
1535 }
1536}
1537
1538impl Posture {
1539 fn identify(key: &str) -> Self {
1540 match key {
1541 "lay" => Self::Lay,
1542 "mv" => Self::Move,
1543 "std" => Self::Stand,
1544 "swim" => Self::Swim,
1545 "float" => Self::Float,
1546 "sit" => Self::Sit,
1547 "swrun" => Self::SnowWarRun,
1548 "swdiefront" => Self::SnowWarDieFront,
1549 "swdieback" => Self::SnowWarDieBack,
1550 "swpick" => Self::SnowWarPick,
1551 "swthrow" => Self::SnowWarThrow,
1552 _ => Self::Other(key.to_string())
1553 }
1554 }
1555}
1556
1557#[derive(Clone, Debug, PartialEq)]
1558pub enum Gesture {
1559 Smile,
1560 Aggravated,
1561 Surprised,
1562 Sad,
1563 Joy,
1564 Crazy,
1565 Tongue,
1566 Blink,
1567 Miserable,
1568 Puzzled,
1569 Other(String)
1570}
1571
1572impl ToString for Gesture {
1573 fn to_string(&self) -> String {
1574 match self {
1575 Self::Smile => "sml",
1576 Self::Aggravated => "agr",
1577 Self::Surprised => "srp",
1578 Self::Sad => "sad",
1579 Self::Joy => "joy",
1580 Self::Crazy => "crz",
1581 Self::Tongue => "tng",
1582 Self::Blink => "eyb",
1583 Self::Miserable => "mis",
1584 Self::Puzzled => "puz",
1585 Self::Other(key) => key
1586 }.to_string()
1587 }
1588}
1589
1590impl Gesture {
1591 fn identify(key: &str) -> Self {
1592 match key {
1593 "sml" => Self::Smile,
1594 "agr" => Self::Aggravated,
1595 "srp" => Self::Surprised,
1596 "sad" => Self::Sad,
1597 "joy" => Self::Joy,
1598 "crz" => Self::Crazy,
1599 "tng" => Self::Tongue,
1600 "eyb" => Self::Blink,
1601 "mis" => Self::Miserable,
1602 "puz" => Self::Puzzled,
1603 _ => Self::Other(key.to_string())
1604 }
1605 }
1606}
1607
1608#[derive(Clone, Debug, PartialEq)]
1609pub enum WiredUserMoveType {
1610 Move,
1611 Slide
1612}
1613
1614impl Default for WiredUserMoveType {
1615 fn default() -> Self {
1616 Self::Move
1617 }
1618}
1619
1620impl PacketVariable for WiredUserMoveType {
1621 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
1622 let (key, size) = i32::from_packet(bytes);
1623
1624 if key == 0 {
1625 (Self::Move, size)
1626 } else {
1627 (Self::Slide, size)
1628 }
1629 }
1630
1631 fn to_packet(&self) -> Vec<u8> {
1632 match self {
1633 WiredUserMoveType::Move => 0i32,
1634 WiredUserMoveType::Slide => 1i32
1635 }.to_packet()
1636 }
1637}
1638
1639#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1640pub struct InputSourcesConf {
1641 allowed_furni_sources: Vec<Vec<LegacyId>>,
1642 allowed_user_sources: Vec<Vec<LegacyId>>,
1643 default_furni_sources: Vec<LegacyId>,
1644 default_user_sources: Vec<LegacyId>
1645}
1646
1647#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1648pub struct ActionDefinition {
1649 pub furni_limit: i32,
1650 pub stuff_ids: Vec<LegacyId>,
1651 pub stuff_type_id: i32,
1652 pub id: LegacyId,
1653 pub string_param: String,
1654 pub int_params: Vec<i32>,
1655 pub furni_source_types: Vec<i32>,
1656 pub user_source_types: Vec<i32>,
1657 pub code: i32,
1658 pub delay_in_pulses: i32,
1659 pub advanced_mode: bool,
1660 pub input_sources_conf: InputSourcesConf,
1661 pub allow_wall_furni: bool
1662}
1663
1664#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1665pub struct AddonDefinition {
1666 pub furni_limit: i32,
1667 pub stuff_ids: Vec<LegacyId>,
1668 pub stuff_type_id: i32,
1669 pub id: LegacyId,
1670 pub string_param: String,
1671 pub int_params: Vec<i32>,
1672 pub furni_source_types: Vec<i32>,
1673 pub user_source_types: Vec<i32>,
1674 pub code: i32,
1675 pub advanced_mode: bool,
1676 pub input_sources_conf: InputSourcesConf,
1677 pub allow_wall_furni: bool
1678}
1679
1680#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1681pub struct ConditionDefinition {
1682 pub furni_limit: i32,
1683 pub stuff_ids: Vec<LegacyId>,
1684 pub stuff_type_id: i32,
1685 pub id: LegacyId,
1686 pub string_param: String,
1687 pub int_params: Vec<i32>,
1688 pub furni_source_types: Vec<i32>,
1689 pub user_source_types: Vec<i32>,
1690 pub code: i32,
1691 pub quantifier_code: i32,
1692 pub is_invert: bool,
1693 pub advanced_mode: bool,
1694 pub input_sources_conf: InputSourcesConf,
1695 pub allow_wall_furni: bool,
1696 pub quantifier_type: i8
1697}
1698
1699#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1700pub struct SelectorDefinition {
1701 pub furni_limit: i32,
1702 pub stuff_ids: Vec<LegacyId>,
1703 pub stuff_type_id: i32,
1704 pub id: LegacyId,
1705 pub string_param: String,
1706 pub int_params: Vec<i32>,
1707 pub furni_source_types: Vec<i32>,
1708 pub user_source_types: Vec<i32>,
1709 pub code: i32,
1710 pub is_filter: bool,
1711 pub is_invert: bool,
1712 pub advanced_mode: bool,
1713 pub input_sources_conf: InputSourcesConf,
1714 pub allow_wall_furni: bool
1715}
1716
1717#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1718pub struct TriggerDefinition {
1719 pub furni_limit: i32,
1720 pub stuff_ids: Vec<LegacyId>,
1721 pub stuff_type_id: i32,
1722 pub id: LegacyId,
1723 pub string_param: String,
1724 pub int_params: Vec<i32>,
1725 pub furni_source_types: Vec<i32>,
1726 pub user_source_types: Vec<i32>,
1727 pub code: i32,
1728 pub advanced_mode: bool,
1729 pub input_sources_conf: InputSourcesConf,
1730 pub allow_wall_furni: bool
1731}
1732
1733#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1734pub struct HallOfFameEntryData {
1735 pub user_id: LegacyId,
1736 pub user_name: String,
1737 pub figure: String,
1738 pub rank: i32,
1739 pub current_score: i32
1740}
1741
1742#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1743pub struct CommunityGoalData {
1744 pub has_goal_expired: bool,
1745 pub personal_contribution_score: i32,
1746 pub personal_contribution_rank: i32,
1747 pub community_total_score: i32,
1748 pub community_highest_achieved_level: i32,
1749 pub score_remaining_until_next_level: i32,
1750 pub percent_completion_towards_next_level: i32,
1751 pub goal_code: String,
1752 pub time_remaining_in_seconds: i32,
1753 pub reward_user_limits: Vec<i32>
1754}
1755
1756#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1757pub struct QuestMessageData {
1758 pub campaign_code: String,
1759 pub completed_quests_in_campaign: i32,
1760 pub quest_count_in_campaign: i32,
1761 pub activity_point_type: i32,
1762 pub id: LegacyId,
1763 pub accepted: bool,
1764 pub quest_type: String,
1765 pub image_version: String,
1766 pub reward_currency_amount: i32,
1767 pub localization_code: String,
1768 pub completed_steps: i32,
1769 pub total_steps: i32,
1770 pub sort_order: i32,
1771 pub catalog_page_name: String,
1772 pub chain_code: String,
1773 pub easy: bool
1774}
1775
1776#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1777pub struct TalentTrackRewardPerk {
1778 pub perk_id: String
1779}
1780
1781#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1782pub struct TalentTrackRewardProduct {
1783 pub product_code: String,
1784 pub vip_days: i32
1785}
1786
1787#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1788pub struct TalentTrackLevelData {
1789 pub level: i32,
1790 pub state: i32,
1791 pub tasks: Vec<TalentTrackTask>,
1792 pub reward_perks: Vec<TalentTrackRewardPerk>,
1793 pub reward_products: Vec<TalentTrackRewardProduct>
1794}
1795
1796#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1797pub struct TalentTrackTask {
1798 pub achievement_id: LegacyId,
1799 pub required_level: i32,
1800 pub badge_code: String,
1801 pub state: i32,
1802 pub current_score: i32,
1803 pub total_score: i32
1804}
1805
1806#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1807pub struct CallForHelpPendingCall {
1808 pub call_id: String,
1809 pub time_stamp: String,
1810 pub message: String
1811}
1812
1813#[derive(Clone, Debug, Default, PartialEq)]
1814pub struct PendingGuideTicket {
1815 pub ticket_type: i32,
1816 pub seconds_ago: i32,
1817 pub is_guide: bool,
1818 pub other_party_name: String,
1819 pub other_party_figure: String,
1820 pub description: String,
1821 pub room_name: String
1822}
1823
1824impl PacketVariable for PendingGuideTicket {
1825 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
1826 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
1827
1828 let (ticket_type, seconds_ago, is_guide) = packet.read();
1829
1830 (Self {
1831 ticket_type, seconds_ago, is_guide,
1832 other_party_name: if ticket_type < 3 || (ticket_type == 3 && !is_guide) { packet.read() } else { "".to_string() },
1833 other_party_figure: if ticket_type < 3 || (ticket_type == 3 && !is_guide) { packet.read() } else { "".to_string() },
1834 description: if ticket_type == 1 { packet.read() } else { "".to_string() },
1835 room_name: if ticket_type == 3 && !is_guide { packet.read() } else { "".to_string() },
1836 }, packet.read_index - 6)
1837 }
1838
1839 fn to_packet(&self) -> Vec<u8> {
1840 let mut packet = HPacket::from_header_id(0);
1841
1842 packet.append((
1843 self.ticket_type, self.seconds_ago, self.is_guide
1844 ));
1845 if self.ticket_type < 3 || (self.ticket_type == 3 && !self.is_guide) {
1846 packet.append((
1847 self.other_party_name.clone(), self.other_party_figure.clone()
1848 ));
1849 }
1850 if self.ticket_type == 1 {
1851 packet.append(self.description.clone());
1852 }
1853 if self.ticket_type == 3 && !self.is_guide {
1854 packet.append(self.room_name.clone());
1855 }
1856
1857 packet.get_bytes()[6..].to_vec()
1858 }
1859}
1860
1861#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1862pub struct LeaderBoardEntry {
1863 pub user_id: LegacyId,
1864 pub score: i32,
1865 pub rank: i32,
1866 pub name: String,
1867 pub figure: String,
1868 pub gender: String
1869}
1870
1871#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1872pub struct GameLobbyData {
1873 pub game_id: LegacyId,
1874 pub level_name: String,
1875 pub game_type: i32,
1876 pub field_type: i32,
1877 pub number_of_teams: i32,
1878 pub maximum_players: i32,
1879 pub owning_player_name: String,
1880 pub level_entry_id: LegacyId,
1881 pub players: Vec<GameLobbyPlayerData>
1882}
1883
1884#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1885pub struct GameLobbyPlayerData {
1886 pub user_id: LegacyId,
1887 pub name: String,
1888 pub figure: String,
1889 pub gender: String,
1890 pub team_id: i32,
1891 pub skill_level: i32,
1892 pub total_score: i32,
1893 pub score_to_next_level: i32
1894}
1895
1896#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1897pub struct AcceptFriendFailureData {
1898 pub sender_id: LegacyId,
1899 pub error_code: i32
1900}
1901
1902#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1903pub struct FindFriendsProcessResult {
1904 pub success: bool
1905}
1906
1907#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1908pub struct FollowFriendFailed {
1909 pub error_code: i32
1910}
1911
1912#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1913pub struct FriendData {
1914 pub id: LegacyId,
1915 pub name: String,
1916 pub gender: i32,
1917 pub online: bool,
1918 pub following_allowed: bool,
1919 pub figure: String,
1920 pub category_id: i32,
1921 pub motto: String,
1922 pub real_name: String,
1923 pub facebook_id: String,
1924 pub persisted_message_user: bool,
1925 pub vip_member: bool,
1926 pub pocket_habbo_user: bool,
1927 pub relationship_status: i16
1928}
1929
1930#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1931pub struct FriendCategoryData {
1932 pub id: i32,
1933 pub name: String
1934}
1935
1936#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1937pub struct FriendRequestData {
1938 pub requester_user_id: LegacyId,
1939 pub requester_name: String,
1940 pub figure_string: String
1941}
1942
1943#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1944pub struct HabboSearchResultData {
1945 pub avatar_id: LegacyId,
1946 pub avatar_name: String,
1947 pub avatar_motto: String,
1948 pub is_avatar_online: bool,
1949 pub can_follow: bool,
1950 pub last_online_date: String,
1951 pub avatar_gender: i32,
1952 pub avatar_figure: String,
1953 pub real_name: String
1954}
1955
1956#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1957pub struct BreedingPetInfo {
1958 pub web_id: LegacyId,
1959 pub name: String,
1960 pub level: i32,
1961 pub figure: String,
1962 pub owner: String
1963}
1964
1965#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1966pub struct RarityCategoryData {
1967 pub chance: i32,
1968 pub breeds: Vec<i32>
1969}
1970
1971#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1972pub struct OutfitData {
1973 pub slot_id: i32,
1974 pub figure_string: String,
1975 pub gender: String
1976}
1977
1978#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1979pub struct BotData {
1980 pub id: LegacyId,
1981 pub name: String,
1982 pub motto: String,
1983 pub gender: String,
1984 pub figure: String
1985}
1986
1987#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
1988pub struct AchievementData {
1989 pub achievement_id: LegacyId,
1990 pub level: i32,
1991 pub badge_id: String,
1992 pub score_at_start_of_level: i32,
1993 pub score_limit: i32,
1994 pub level_reward_points: i32,
1995 pub level_reward_point_type: i32,
1996 pub current_points: i32,
1997 pub final_level: bool,
1998 pub category: String,
1999 pub sub_category: String,
2000 pub level_count: i32,
2001 pub display_method: i32,
2002 pub state: i32
2003}
2004
2005#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2006pub struct HotLookInfo {
2007 pub gender: String,
2008 pub figure_string: String
2009}
2010
2011#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2012pub struct PlayListEntry {
2013 pub id: LegacyId,
2014 pub length: i32,
2015 pub song_name: String,
2016 pub creator: String
2017}
2018
2019#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2020pub struct SongInfoEntry {
2021 pub id: LegacyId,
2022 pub _unused: String,
2023 pub song_name: String,
2024 pub data: String,
2025 pub length: i32,
2026 pub creator: String
2027}
2028
2029#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2030pub struct IncomeReward {
2031 pub reward_category: i8,
2032 pub reward_type: i8,
2033 pub amount: i32,
2034 pub product_code: String
2035}
2036
2037#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2038pub struct LiftedRoomData {
2039 pub flat_id: LegacyId,
2040 pub area_id: LegacyId,
2041 pub image: String,
2042 pub caption: String
2043}
2044
2045#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2046pub struct TopLevelContext {
2047 pub search_code: String,
2048 pub quick_links: Vec<SavedSearch>
2049}
2050
2051#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2052pub struct SavedSearch {
2053 pub id: LegacyId,
2054 pub search_code: String,
2055 pub filter: String,
2056 pub localization: String
2057}
2058
2059#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2060pub struct SearchResultSet {
2061 pub search_code_original: String,
2062 pub filtering_data: String,
2063 pub blocks: Vec<SearchResultList>
2064}
2065
2066#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2067pub struct SearchResultList {
2068 pub search_code: String,
2069 pub text: String,
2070 pub action_allowed: i32,
2071 pub force_closed: bool,
2072 pub view_mode: i32,
2073 pub guest_rooms: Vec<GuestRoomData>
2074}
2075
2076#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2077pub struct Game2PlayerData {
2078 pub reference_id: LegacyId,
2079 pub user_name: String,
2080 pub figure_string: String,
2081 pub gender: String,
2082 pub team_id: i32
2083}
2084
2085#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2086pub struct GameLevelData {
2087 pub width: i32,
2088 pub height: i32,
2089 pub height_map: String,
2090 pub fuse_objects: Vec<FuseObjectData>
2091}
2092
2093#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2094pub struct FuseObjectData {
2095 pub name: String,
2096 pub id: LegacyId,
2097 pub x: i32,
2098 pub y: i32,
2099 pub x_dimension: i32,
2100 pub y_dimension: i32,
2101 pub height: i32,
2102 pub direction: i32,
2103 pub altitude: i32,
2104 pub can_stand_on: i32,
2105 pub stuff_data: StuffData
2106}
2107
2108#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2109pub struct Game2GameResult {
2110 pub is_death_match: bool,
2111 pub result_type: i32,
2112 pub winner_id: LegacyId
2113}
2114
2115#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2116pub struct Game2TeamScoreData {
2117 pub team_reference: i32,
2118 pub score: i32,
2119 pub players: Vec<Game2TeamPlayerData>
2120}
2121
2122#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2123pub struct Game2TeamPlayerData {
2124 pub user_name: String,
2125 pub user_id: LegacyId,
2126 pub figure: String,
2127 pub gender: String,
2128 pub score: i32,
2129 pub player_stats: Game2PlayerStatsData
2130}
2131
2132#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2133pub struct Game2PlayerStatsData {
2134 pub score: i32,
2135 pub kills: i32,
2136 pub deaths: i32,
2137 pub snowball_hits: i32,
2138 pub snowball_hits_taken: i32,
2139 pub snowballs_thrown: i32,
2140 pub snowballs_created: i32,
2141 pub snowballs_from_machine: i32,
2142 pub friendly_hits: i32,
2143 pub friendly_kills: i32
2144}
2145
2146#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2147pub struct Game2SnowWarGameStats {
2148 pub player_with_most_kills: i32,
2149 pub player_with_most_hits: i32
2150}
2151
2152#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2153pub struct GameObjectsData {
2154 pub game_objects: Vec<SnowWarGameObjectData>
2155}
2156
2157#[derive(Clone, Debug, PartialEq)]
2158pub enum SnowWarGameObjectData {
2159 SnowballGameObjectData {
2160 id: i32,
2161 location_x_3d: i32,
2162 location_y_3d: i32,
2163 location_z_3d: i32,
2164 movement_direction_360: i32,
2165 trajectory: i32,
2166 time_to_live: i32,
2167 throwing_human: i32,
2168 parabola_offset: i32,
2169 planar_velocity: i32
2170 },
2171 TreeGameObjectData {
2172 id: i32,
2173 location_x_3d: i32,
2174 location_y_3d: i32,
2175 direction: i32,
2176 height: i32,
2177 fuse_object_id: i32,
2178 max_hits: i32,
2179 hits: i32
2180 },
2181 SnowballPileGameObjectData {
2182 id: i32,
2183 location_x_3d: i32,
2184 location_y_3d: i32,
2185 max_snow_balls: i32,
2186 snowball_count: i32,
2187 fuse_object_id: i32
2188 },
2189 SnowballMachineGameObjectData {
2190 id: i32,
2191 location_x_3d: i32,
2192 location_y_3d: i32,
2193 direction: i32,
2194 max_snow_balls: i32,
2195 snowball_count: i32,
2196 fuse_object_id: i32
2197 },
2198 HumanGameObjectData {
2199 id: i32,
2200 current_location_x: i32,
2201 current_location_y: i32,
2202 current_tile_x: i32,
2203 current_tile_y: i32,
2204 body_direction: i32,
2205 hit_points: i32,
2206 snow_ball_count: i32,
2207 is_bot: i32,
2208 activity_timer: i32,
2209 activity_state: i32,
2210 next_tile_x: i32,
2211 next_tile_y: i32,
2212 move_target_x: i32,
2213 move_target_y: i32,
2214 score: i32,
2215 team: i32,
2216 user_id: i32,
2217 name: String,
2218 mission: String,
2219 figure: String,
2220 sex: String
2221 }
2222}
2223
2224impl PacketVariable for SnowWarGameObjectData {
2225 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
2226 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
2227
2228 (match packet.read::<i32>() {
2229 1 => Self::SnowballGameObjectData {
2230 id: packet.read(),
2231 location_x_3d: packet.read(),
2232 location_y_3d: packet.read(),
2233 location_z_3d: packet.read(),
2234 movement_direction_360: packet.read(),
2235 trajectory: packet.read(),
2236 time_to_live: packet.read(),
2237 throwing_human: packet.read(),
2238 parabola_offset: packet.read(),
2239 planar_velocity: packet.read()
2240 },
2241 2 => Self::TreeGameObjectData {
2242 id: packet.read(),
2243 location_x_3d: packet.read(),
2244 location_y_3d: packet.read(),
2245 direction: packet.read(),
2246 height: packet.read(),
2247 fuse_object_id: packet.read(),
2248 max_hits: packet.read(),
2249 hits: packet.read()
2250 },
2251 3 => Self::SnowballPileGameObjectData {
2252 id: packet.read(),
2253 location_x_3d: packet.read(),
2254 location_y_3d: packet.read(),
2255 max_snow_balls: packet.read(),
2256 snowball_count: packet.read(),
2257 fuse_object_id: packet.read()
2258 },
2259 4 => Self::SnowballMachineGameObjectData {
2260 id: packet.read(),
2261 location_x_3d: packet.read(),
2262 location_y_3d: packet.read(),
2263 direction: packet.read(),
2264 max_snow_balls: packet.read(),
2265 snowball_count: packet.read(),
2266 fuse_object_id: packet.read()
2267 },
2268 5 => Self::HumanGameObjectData {
2269 id: packet.read(),
2270 current_location_x: packet.read(),
2271 current_location_y: packet.read(),
2272 current_tile_x: packet.read(),
2273 current_tile_y: packet.read(),
2274 body_direction: packet.read(),
2275 hit_points: packet.read(),
2276 snow_ball_count: packet.read(),
2277 is_bot: packet.read(),
2278 activity_timer: packet.read(),
2279 activity_state: packet.read(),
2280 next_tile_x: packet.read(),
2281 next_tile_y: packet.read(),
2282 move_target_x: packet.read(),
2283 move_target_y: packet.read(),
2284 score: packet.read(),
2285 team: packet.read(),
2286 user_id: packet.read(),
2287 name: packet.read(),
2288 mission: packet.read(),
2289 figure: packet.read(),
2290 sex: packet.read()
2291 },
2292 _ => panic!("SnowWarGameObjectData: Unknown type")
2293 }, packet.read_index - 6)
2294 }
2295
2296 fn to_packet(&self) -> Vec<u8> {
2297 match self {
2298 SnowWarGameObjectData::SnowballGameObjectData {
2299 id, location_x_3d, location_y_3d, location_z_3d,
2300 movement_direction_360, trajectory, time_to_live,
2301 throwing_human, parabola_offset, planar_velocity
2302 } => (
2303 *id, *location_x_3d, *location_y_3d, *location_z_3d,
2304 *movement_direction_360, *trajectory, *time_to_live,
2305 *throwing_human, *parabola_offset, *planar_velocity
2306 ).to_packet(),
2307 SnowWarGameObjectData::TreeGameObjectData {
2308 id, location_x_3d, location_y_3d, direction,
2309 height, fuse_object_id, max_hits, hits
2310 } => (
2311 *id, *location_x_3d, *location_y_3d, *direction,
2312 *height, *fuse_object_id, *max_hits, *hits
2313 ).to_packet(),
2314 SnowWarGameObjectData::SnowballPileGameObjectData {
2315 id, location_x_3d, location_y_3d,
2316 max_snow_balls, snowball_count, fuse_object_id
2317 } => (
2318 *id, *location_x_3d, *location_y_3d,
2319 *max_snow_balls, *snowball_count, *fuse_object_id
2320 ).to_packet(),
2321 SnowWarGameObjectData::SnowballMachineGameObjectData {
2322 id, location_x_3d, location_y_3d, direction,
2323 max_snow_balls, snowball_count, fuse_object_id
2324 } => (
2325 *id, *location_x_3d, *location_y_3d, *direction,
2326 *max_snow_balls, *snowball_count, *fuse_object_id
2327 ).to_packet(),
2328 SnowWarGameObjectData::HumanGameObjectData {
2329 id, current_location_x, current_location_y,
2330 current_tile_x, current_tile_y, body_direction,
2331 hit_points, snow_ball_count, is_bot, activity_timer,
2332 activity_state, next_tile_x, next_tile_y,
2333 move_target_x, move_target_y, score, team,
2334 user_id, name, mission, figure, sex
2335 } => (
2336 *id, *current_location_x, *current_location_y,
2337 *current_tile_x, *current_tile_y, *body_direction,
2338 *hit_points, *snow_ball_count, *is_bot, *activity_timer,
2339 *activity_state, *next_tile_x, *next_tile_y,
2340 *move_target_x, *move_target_y, *score, *team,
2341 *user_id, name.clone(), mission.clone(), figure.clone(), sex.clone()
2342 ).to_packet()
2343 }
2344 }
2345}
2346
2347#[derive(Clone, Debug, Default, PartialEq)]
2348pub struct FurniData {
2349 pub item_id: LegacyId,
2350 pub item_type: String,
2351 pub room_item_id: LegacyId,
2352 pub item_type_id: i32,
2353 pub category: i32,
2354 pub stuff_data: StuffData,
2355 pub is_recyclable: bool,
2356 pub is_tradeable: bool,
2357 pub is_groupable: bool,
2358 pub is_sellable: bool,
2359 pub seconds_to_expiration: i32,
2360 pub has_rent_period_started: bool,
2361 pub flat_id: LegacyId,
2362 pub slot_id: String,
2363 pub extra: i32
2364}
2365
2366impl PacketVariable for FurniData {
2367 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
2368 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
2369 let item_id = packet.read();
2370 let item_type: String = packet.read();
2371 let (
2372 room_item_id, item_type_id, category, stuff_data, is_recyclable, is_tradeable,
2373 is_groupable, is_sellable, seconds_to_expiration, has_rent_period_started, flat_id
2374 ) = packet.read();
2375
2376 (Self {
2377 slot_id: if item_type.clone() == "S" { packet.read() } else { Default::default() },
2378 extra: if item_type.clone() == "S" { packet.read() } else { Default::default() },
2379 item_id, item_type, room_item_id, item_type_id, category, stuff_data, is_recyclable,
2380 is_tradeable, is_groupable, is_sellable, seconds_to_expiration, has_rent_period_started,
2381 flat_id
2382 }, packet.read_index - 6)
2383 }
2384
2385 fn to_packet(&self) -> Vec<u8> {
2386 if self.item_type == "S" {
2387 (
2388 self.item_id, self.item_type.clone(), self.room_item_id, self.item_type_id,
2389 self.category, self.stuff_data.clone(), self.is_recyclable, self.is_tradeable,
2390 self.is_groupable, self.is_sellable, self.seconds_to_expiration,
2391 self.has_rent_period_started, self.flat_id, self.slot_id.clone(), self.extra
2392 ).to_packet()
2393 } else {
2394 (
2395 self.item_id, self.item_type.clone(), self.room_item_id, self.item_type_id,
2396 self.category, self.stuff_data.clone(), self.is_recyclable, self.is_tradeable,
2397 self.is_groupable, self.is_sellable, self.seconds_to_expiration,
2398 self.has_rent_period_started, self.flat_id
2399 ).to_packet()
2400 }
2401 }
2402}
2403
2404#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2405pub struct AvatarEffectData {
2406 pub effect_type: i32,
2407 pub sub_type: i32,
2408 pub duration: i32,
2409 pub inactive_effects_in_inventory: i32,
2410 pub seconds_left_if_active: i32,
2411 pub is_permanent: bool
2412}
2413
2414#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2415pub struct NftWardrobeItem {
2416 pub token_id: String,
2417 pub figure_string: String,
2418 pub gender: String
2419}
2420
2421#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2422pub struct AchievementLevelUpData {
2423 pub achievement_type: i32,
2424 pub level: i32,
2425 pub badge_id: i32,
2426 pub badge_code: String,
2427 pub points: i32,
2428 pub level_reward_points: i32,
2429 pub level_reward_point_type: i32,
2430 pub bonus_points: i32,
2431 pub achievement_id: i32,
2432 pub removed_badge_code: String,
2433 pub category: String,
2434 pub show_dialog_to_user: bool
2435}
2436
2437#[derive(Clone, Debug, Default, PartialEq)]
2438pub struct ItemDataStructure {
2439 pub item_id: LegacyId,
2440 pub item_type: String,
2441 pub room_item_id: LegacyId,
2442 pub item_type_id: i32,
2443 pub category: i32,
2444 pub is_groupable: bool,
2445 pub stuff_data: StuffData,
2446 pub creation_day: i32,
2447 pub creation_month: i32,
2448 pub creation_year: i32,
2449 pub extra: i32
2450}
2451
2452impl PacketVariable for ItemDataStructure {
2453 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
2454 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
2455
2456 let item_id = packet.read();
2457 let item_type: String = packet.read();
2458 let (room_item_id, item_type_id, category, is_groupable, stuff_data,
2459 creation_day, creation_month, creation_year) = packet.read();
2460 let extra = if item_type.clone().to_uppercase() == "S" { packet.read() } else { -1 };
2461
2462 (Self {
2463 item_id, item_type, room_item_id, item_type_id, category, is_groupable,
2464 stuff_data, creation_day, creation_month, creation_year, extra
2465 }, packet.read_index - 6)
2466 }
2467
2468 fn to_packet(&self) -> Vec<u8> {
2469 if self.item_type.clone().to_uppercase() == "S" {
2470 (
2471 self.item_id, self.item_type.clone(), self.room_item_id, self.item_type_id,
2472 self.category, self.is_groupable, self.stuff_data.clone(), self.creation_day,
2473 self.creation_month, self.creation_year, self.extra
2474 ).to_packet()
2475 } else {
2476 (
2477 self.item_id, self.item_type.clone(), self.room_item_id, self.item_type_id,
2478 self.category, self.is_groupable, self.stuff_data.clone(), self.creation_day,
2479 self.creation_month, self.creation_year
2480 ).to_packet()
2481 }
2482 }
2483}
2484
2485#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2486pub struct Perk {
2487 pub code: String,
2488 pub error_message: String,
2489 pub is_allowed: bool
2490}
2491
2492#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2493pub struct BotSkillData {
2494 pub id: LegacyId,
2495 pub data: String
2496}
2497
2498#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2499pub struct PromoArticleData {
2500 pub id: LegacyId,
2501 pub title: String,
2502 pub body_text: String,
2503 pub button_text: String,
2504 pub link_type: i32,
2505 pub link_content: String,
2506 pub image_url: String
2507}
2508
2509#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2510pub struct CfhSanctionTypeData {
2511 pub name: String,
2512 pub sanction_length_in_hours: i32,
2513 pub _unused: i32,
2514 pub avatar_only: bool,
2515 pub trade_lock_info: Option<String>,
2516 pub machine_ban_info: Option<String>
2517}
2518
2519#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2520pub struct CallForHelpCategoryData {
2521 pub name: String,
2522 pub topics: Vec<CallForHelpTopicData>
2523}
2524
2525#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2526pub struct CallForHelpTopicData {
2527 pub name: String,
2528 pub id: LegacyId,
2529 pub consequence: String
2530}
2531
2532#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2533pub struct BannedUserData {
2534 pub user_id: LegacyId,
2535 pub user_name: String
2536}
2537
2538#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2539pub struct FlatControllerData {
2540 pub user_id: LegacyId,
2541 pub user_name: String
2542}
2543
2544#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2545pub struct RoomChatSettings {
2546 pub mode: i32,
2547 pub bubble_width: i32,
2548 pub scroll_speed: i32,
2549 pub full_hear_range: i32,
2550 pub flood_sensitivity: i32
2551}
2552
2553#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2554pub struct FullGameStatusData {
2555 pub _unused: i32,
2556 pub remaining_time_seconds: i32,
2557 pub duration_in_seconds: i32,
2558 pub game_objects: GameObjectsData,
2559 pub _unused2: i32,
2560 pub number_of_teams: i32,
2561 pub game_status: GameStatusData
2562}
2563
2564#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2565pub struct GameStatusData {
2566 pub turn: i32,
2567 pub checksum: i32,
2568 pub events: Vec<Vec<SnowWarGameEventData>>
2569}
2570
2571#[derive(Clone, Debug, PartialEq)]
2572pub enum SnowWarGameEventData {
2573 HumanLeftGameEventData {
2574 human_game_object_id: i32
2575 },
2576 NewMoveTargetEventData {
2577 human_game_object_id: i32,
2578 x: i32,
2579 y: i32
2580 },
2581 HumanThrowsSnowballAtHumanEventData {
2582 human_game_object_id: i32,
2583 target_human_game_object_id: i32,
2584 trajectory: i32
2585 },
2586 HumanThrowsSnowballAtPositionEventData {
2587 human_game_object_id: i32,
2588 target_x: i32,
2589 target_y: i32,
2590 trajectory: i32
2591 },
2592 HumanStartsToMakeASnowballEventData {
2593 human_game_object_id: i32
2594 },
2595 CreateSnowballEventData {
2596 snow_ball_game_object_id: i32,
2597 human_game_object_id: i32,
2598 target_x: i32,
2599 target_y: i32,
2600 trajectory: i32
2601 },
2602 MachineCreatesSnowballEventData {
2603 snow_ball_machine_reference: i32
2604 },
2605 HumanGetsSnowballsFromMachineEventData {
2606 human_game_object_id: i32,
2607 snow_ball_machine_reference: i32
2608 }
2609}
2610
2611impl PacketVariable for SnowWarGameEventData {
2612 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
2613 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
2614
2615 (match packet.read::<i32>() {
2616 1 => SnowWarGameEventData::HumanLeftGameEventData {
2617 human_game_object_id: packet.read()
2618 },
2619 2 => SnowWarGameEventData::NewMoveTargetEventData {
2620 human_game_object_id: packet.read(),
2621 x: packet.read(),
2622 y: packet.read()
2623 },
2624 3 => SnowWarGameEventData::HumanThrowsSnowballAtHumanEventData {
2625 human_game_object_id: packet.read(),
2626 target_human_game_object_id: packet.read(),
2627 trajectory: packet.read()
2628 },
2629 4 => SnowWarGameEventData::HumanThrowsSnowballAtPositionEventData {
2630 human_game_object_id: packet.read(),
2631 target_x: packet.read(),
2632 target_y: packet.read(),
2633 trajectory: packet.read()
2634 },
2635 7 => SnowWarGameEventData::HumanStartsToMakeASnowballEventData {
2636 human_game_object_id: packet.read()
2637 },
2638 8 => SnowWarGameEventData::CreateSnowballEventData {
2639 snow_ball_game_object_id: packet.read(),
2640 human_game_object_id: packet.read(),
2641 target_x: packet.read(),
2642 target_y: packet.read(),
2643 trajectory: packet.read()
2644 },
2645 11 => SnowWarGameEventData::MachineCreatesSnowballEventData {
2646 snow_ball_machine_reference: packet.read()
2647 },
2648 12 => SnowWarGameEventData::HumanGetsSnowballsFromMachineEventData {
2649 human_game_object_id: packet.read(),
2650 snow_ball_machine_reference: packet.read()
2651 },
2652 _ => panic!("SnowWarGameEventData: Unknown type")
2653 }, packet.read_index - 6)
2654 }
2655
2656 fn to_packet(&self) -> Vec<u8> {
2657 match self {
2658 SnowWarGameEventData::HumanLeftGameEventData {
2659 human_game_object_id
2660 } => (
2661 1i32, *human_game_object_id
2662 ).to_packet(),
2663 SnowWarGameEventData::NewMoveTargetEventData {
2664 human_game_object_id, x, y
2665 } => (
2666 2i32, *human_game_object_id, *x, *y
2667 ).to_packet(),
2668 SnowWarGameEventData::HumanThrowsSnowballAtHumanEventData {
2669 human_game_object_id, target_human_game_object_id, trajectory
2670 } => (
2671 3i32, *human_game_object_id, *target_human_game_object_id, *trajectory
2672 ).to_packet(),
2673 SnowWarGameEventData::HumanThrowsSnowballAtPositionEventData {
2674 human_game_object_id, target_x, target_y, trajectory
2675 } => (
2676 4i32, *human_game_object_id, *target_x, *target_y, *trajectory
2677 ).to_packet(),
2678 SnowWarGameEventData::HumanStartsToMakeASnowballEventData {
2679 human_game_object_id
2680 } => (
2681 7i32, *human_game_object_id
2682 ).to_packet(),
2683 SnowWarGameEventData::CreateSnowballEventData {
2684 snow_ball_game_object_id, human_game_object_id,
2685 target_x, target_y, trajectory
2686 } => (
2687 8i32, *snow_ball_game_object_id, *human_game_object_id,
2688 *target_x, *target_y, *trajectory
2689 ).to_packet(),
2690 SnowWarGameEventData::MachineCreatesSnowballEventData {
2691 snow_ball_machine_reference
2692 } => (
2693 11i32, *snow_ball_machine_reference
2694 ).to_packet(),
2695 SnowWarGameEventData::HumanGetsSnowballsFromMachineEventData {
2696 human_game_object_id, snow_ball_machine_reference
2697 } => (
2698 12i32, *human_game_object_id, *snow_ball_machine_reference
2699 ).to_packet()
2700 }
2701 }
2702}
2703
2704#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2705pub struct PetBreedingResultData {
2706 pub stuff_id: LegacyId,
2707 pub class_id: i32,
2708 pub product_code: String,
2709 pub user_id: LegacyId,
2710 pub user_name: String,
2711 pub rarity_level: i32,
2712 pub has_mutation: bool
2713}
2714
2715#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2716pub struct BadgeAndPointLimit {
2717 pub badge_id: i32,
2718 pub limit: i32
2719}
2720
2721#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2722pub struct NewUserExperienceGiftOptions {
2723 pub day_index: i32,
2724 pub step_index: i32,
2725 pub options: Vec<NewUserExperienceGift>
2726}
2727
2728#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2729pub struct NewUserExperienceGift {
2730 pub thumbnail_url: String,
2731 pub product_offers: Vec<NewUserExperienceGiftProduct>
2732}
2733
2734#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2735pub struct NewUserExperienceGiftProduct {
2736 pub product_code: String,
2737 pub localization_key: String
2738}
2739
2740#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2741pub struct MarketplaceItemStatsData {
2742 pub day_offset: i32,
2743 pub average_price: i32,
2744 pub sold_amount: i32
2745}
2746
2747#[derive(Clone, Debug, Default, PartialEq)]
2748pub struct MarketPlaceOffer {
2749 pub offer_id: LegacyId,
2750 pub status: i32,
2751 pub furni_type: i32,
2752 pub furni_id: LegacyId,
2753 pub stuff_data: StuffData,
2754 pub extra_data: String,
2755 pub price: i32,
2756 pub time_left_minutes: i32,
2757 pub average_price: i32,
2758 pub offer_count: i32
2759}
2760
2761impl PacketVariable for MarketPlaceOffer {
2762 fn from_packet(bytes: Vec<u8>) -> (Self, usize) where Self: Sized {
2763 let mut packet = HPacket::from_header_id_and_bytes(0, bytes);
2764
2765 let (offer_id, status) = packet.read();
2766 let furni_type: i32 = packet.read();
2767 let mut furni_id = LegacyId(-1);
2768 let mut stuff_data = StuffData::default();
2769 let mut extra_data = "".to_string();
2770 if furni_type == 1 {
2771 furni_id = packet.read();
2772 stuff_data = packet.read();
2773 } else if furni_type == 2 {
2774 furni_id = packet.read();
2775 extra_data = packet.read();
2776 } else if furni_type == 3 {
2777 furni_id = packet.read();
2778 stuff_data = StuffData::EmptyStuffData {
2779 unique_serial_data: packet.read()
2780 }
2781 }
2782 let (price, time_left_minutes, average_price) = packet.read();
2783
2784 (Self {
2785 offer_id,
2786 furni_id,
2787 furni_type,
2788 extra_data,
2789 stuff_data,
2790 price,
2791 status,
2792 time_left_minutes,
2793 average_price,
2794 offer_count: -1
2795 }, packet.read_index - 6)
2796 }
2797
2798 fn to_packet(&self) -> Vec<u8> {
2799 let mut packet = HPacket::from_header_id(0);
2800
2801 packet.append((
2802 self.offer_id, self.status, self.furni_type
2803 ));
2804 if self.furni_type == 1 {
2805 packet.append((self.furni_id, self.stuff_data.clone()));
2806 } else if self.furni_type == 2 {
2807 packet.append((self.furni_id, self.extra_data.clone()));
2808 } else if self.furni_type == 3 {
2809 packet.append((self.furni_id, self.stuff_data.get_unique_serial_data()));
2810 }
2811 packet.append((
2812 self.price, self.time_left_minutes, self.average_price
2813 ));
2814
2815 packet.get_bytes()[6..].to_vec()
2816 }
2817}
2818
2819#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2820pub struct ClassifiedUser {
2821 pub id: LegacyId,
2822 pub name: String,
2823 pub user_type: String
2824}
2825
2826#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2827pub struct NewUserExperienceGetGiftsSelection {
2828 pub day_index: i32,
2829 pub step_index: i32,
2830 pub gift_index: i32
2831}
2832
2833#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2834pub struct UpdateForumReadMarkerData {
2835 pub group_id: LegacyId,
2836 pub message_count: i32,
2837 pub has_unread_messages: bool
2838}
2839
2840#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
2841pub struct CallForHelpFromIMMessage {
2842 pub user_id: LegacyId,
2843 pub message: String
2844}
2845
2846
2847
2848
2849