g_rust/extension/parsers/
subparsers.rs

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// WIN63-202307010021-160474147
9
10#[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, // Might be a LegacyLength
31    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, // Might be just a LegacyId
96    pub secondary_color_id: i32, // Might be just a LegacyId
97    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, // Might be a LegacyId
109    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, // Might be a LegacyId
116    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, // Might be a LegacyLength
126    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, // Might be a LegacyLength
146    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, // Might be a LegacyLength
153    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, // Might be a LegacyId
167    pub palette_id: i32, // Might be a LegacyId
168    pub color: String,
169    pub breed_id: i32, // Might be a LegacyId
170    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, // Might be a LegacyId
199    pub queue: HashMap<String, i32> // Might be <String, LegacyId
200}
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, // Might be a LegacyId
213    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, // Might be a LegacyId
288    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, // Might be a LegacyId
306    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, // Might be a LegacyId
437    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 // Might be a LegacyId
525}
526
527#[derive(Clone, Debug, Default, PacketVariable, PartialEq)]
528pub struct EventCategory {
529    pub category_id: i32, // Might be a LegacyId
530    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, // Might be a LegacyId
537    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, // Might be a LegacyId
639    pub issue_age_in_milliseconds: i32,
640    pub priority: i32,
641    pub grouping_id: i32, // Might be a LegacyId
642    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