Compare commits

..

14 Commits

Author SHA1 Message Date
Tiger ce30ee601b Fixed issue with achievement badges 2023-10-21 17:07:07 +02:00
Tiger b5fbeb7852 Started on rooms, also created the private room categories map and made Repository log errors on exception instead of breaking 2023-10-21 08:34:12 +02:00
Tiger df75c4d4e6 Added Habbo subscriptions and subscription purchasing 2023-10-21 07:19:21 +02:00
Tiger b1c3bfd2b6 Changed packet reading operations to never return null 2023-10-20 21:02:11 +02:00
Tiger 77f3b6a983 Added start of navigator 2023-10-14 22:32:12 +02:00
Tiger f56198e9cb Added catalogue features pages + add some extra checks in catalogue index + pages 2023-10-14 19:35:03 +02:00
Tiger e20079bc2c Changed packet header names to Nitro's packet header names and make sure the events+composer files match Nitro as well (classname and namespace) 2023-10-14 18:21:53 +02:00
Tiger e3a24c5d3d Added achievement system and changed up badges saving 2023-10-07 15:32:19 +02:00
Tiger 7dbdf8aa22 Added landingview promo articles 2023-10-06 21:23:27 +02:00
Tiger e1fd118ade Added look updating and made a start on a figure validator 2023-10-06 20:46:50 +02:00
Tiger 59d90aeeb2 Started on catalogue, added the index and pages packets 2023-10-06 18:12:35 +02:00
Tiger 66744ead65 Added badges 2023-09-29 20:20:28 +02:00
Tiger 6e9b6d0449 Replaced uint to int and added profiles packet and some logging changes 2023-09-23 18:51:16 +02:00
Tiger 5ed8eb6913 Added credits, activitypoints and moved some files 2023-09-23 15:33:23 +02:00
113 changed files with 3894 additions and 1111 deletions

View File

@ -5,5 +5,5 @@ namespace Tiger.Communication.Messages;
public interface IMessageHandler public interface IMessageHandler
{ {
Task TryHandleAsync(GameSession session, ClientMessage request); Task TryHandleAsync(GameSession gameSession, ClientMessage request);
} }

View File

@ -0,0 +1,33 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Inventory.Achievements;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Achievements;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Achievement;
public class RequestAchievementsMessageEvent : IMessageEvent
{
private readonly IGameSessionManager _gameSessionManager;
private readonly IAchievementManager _achievementManager;
public RequestAchievementsMessageEvent(IGameSessionManager gameSessionManager, IAchievementManager achievementManager)
{
_gameSessionManager = gameSessionManager;
_achievementManager = achievementManager;
}
public IncomingHeaders Header => IncomingHeaders.AchievementList;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
await gameSession.SendComposerAsync(new AchievementsScoreComposer(gameSession.Habbo.AchievementScore));
await gameSession.SendComposerAsync(new AchievementsComposer(_achievementManager.Achievements.Values,
gameSession.Habbo));
}
}

View File

@ -0,0 +1,37 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Catalog;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Catalogue;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Catalog;
public class GetCatalogIndexEvent : IMessageEvent
{
private readonly ICatalogueManager _catalogueManager;
private readonly IGameSessionManager _gameSessionManager;
public GetCatalogIndexEvent(ICatalogueManager catalogueManager, IGameSessionManager gameSessionManager)
{
_catalogueManager = catalogueManager;
_gameSessionManager = gameSessionManager;
}
public IncomingHeaders Header => IncomingHeaders.GetCatalogIndex;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
var mode = request.ReadString();
var categories =
_catalogueManager.Pages.Values.Where(
p => p.Parent is null && p.Modes.Contains(mode.ToLower()) && p.MinRank <= gameSession.Habbo.Rank);
await gameSession.SendComposerAsync(new CatalogPagesListComposer(categories, mode));
}
}

View File

@ -0,0 +1,45 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Catalog;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Catalogue;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Catalog;
public class GetCatalogPageEvent : IMessageEvent
{
private readonly ICatalogueManager _catalogueManager;
private readonly IGameSessionManager _gameSessionManager;
public GetCatalogPageEvent(ICatalogueManager catalogueManager, IGameSessionManager gameSessionManager)
{
_catalogueManager = catalogueManager;
_gameSessionManager = gameSessionManager;
}
public IncomingHeaders Header => IncomingHeaders.GetCatalogPage;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
var pageId = request.ReadInt32();
var offerId = request.ReadInt32();
var mode = request.ReadString();
if (!_catalogueManager.Pages.TryGetValue(pageId, out var page) || !page.Enabled ||
page.MinRank > gameSession.Habbo.Rank || !page.Modes.Contains(mode.ToLower()))
{
return;
}
var featuredPages = page.Layout.Equals("frontpage4")
? _catalogueManager.FeaturedPages.Values
: new List<CatalogueFeaturedPage>();
await gameSession.SendComposerAsync(new CatalogPageMessageComposer(page, offerId, mode, featuredPages));
}
}

View File

@ -0,0 +1,38 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Catalog;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Catalogue;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Catalog;
public class GetClubOffersMessageEvent : IMessageEvent
{
private readonly ICatalogueManager _catalogueManager;
private readonly IGameSessionManager _gameSessionManager;
public GetClubOffersMessageEvent(ICatalogueManager catalogueManager, IGameSessionManager gameSessionManager)
{
_catalogueManager = catalogueManager;
_gameSessionManager = gameSessionManager;
}
public IncomingHeaders Header => IncomingHeaders.GetClubOffers;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
var currentSubscription = gameSession.Habbo.GetActiveSubscription();
await gameSession.SendComposerAsync(new HabboClubOffersMessageComposer(
_catalogueManager.ClubOffers.Values.Where(co =>
co.DiscountExtension == currentSubscription is
{
MonthsLeft: 0, DaysInMonthLeft: <= 5 and > 0
}).ToList(), currentSubscription));
}
}

View File

@ -0,0 +1,43 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Catalogue;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Catalog;
public class PurchaseFromCatalogEvent : IMessageEvent
{
private readonly ICatalogueManager _catalogueManager;
private readonly IGameSessionManager _gameSessionManager;
public PurchaseFromCatalogEvent(ICatalogueManager catalogueManager, IGameSessionManager gameSessionManager)
{
_catalogueManager = catalogueManager;
_gameSessionManager = gameSessionManager;
}
public IncomingHeaders Header => IncomingHeaders.CatalogPurchase;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
var pageId = request.ReadInt32();
var offerId = request.ReadInt32();
var extraData = request.ReadString();
var amount = request.ReadInt32();
if (amount < 0 || !_catalogueManager.Pages.TryGetValue(pageId, out var page))
{
return;
}
if (page.Layout.Equals("vip_buy"))
{
await _catalogueManager.PurchaseClubOffer(offerId, gameSession);
}
}
}

View File

@ -1,20 +1,20 @@
using Tiger.Communication.Messages.Interfaces; using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Handshake; using Tiger.Communication.Messages.Outgoing.User.Data;
using Tiger.Communication.Messages.Types; using Tiger.Communication.Messages.Types;
using Tiger.Networking.Game.Sessions; using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Handshake; namespace Tiger.Communication.Messages.Incoming.Handshake;
public class InfoRetrieveEvent : IMessageEvent public class InfoRetrieveMessageEvent : IMessageEvent
{ {
private readonly IGameSessionManager _gameSessionManager; private readonly IGameSessionManager _gameSessionManager;
public InfoRetrieveEvent(IGameSessionManager gameSessionManager) public InfoRetrieveMessageEvent(IGameSessionManager gameSessionManager)
{ {
_gameSessionManager = gameSessionManager; _gameSessionManager = gameSessionManager;
} }
public IncomingHeaders Header => IncomingHeaders.InfoRetrieveEvent; public IncomingHeaders Header => IncomingHeaders.UserInfo;
public async Task HandleAsync(GameSession gameSession, ClientMessage request) public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{ {
if (gameSession.Habbo == null) if (gameSession.Habbo == null)
@ -23,6 +23,6 @@ public class InfoRetrieveEvent : IMessageEvent
return; return;
} }
await gameSession.SendComposerAsync(new UserObjectMessageComposer(gameSession.Habbo)); await gameSession.SendComposerAsync(new UserInfoComposer(gameSession.Habbo));
} }
} }

View File

@ -1,53 +0,0 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Generic.Alerts;
using Tiger.Communication.Messages.Outgoing.Handshake;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
using Tiger.Game.Settings;
using Tiger.Networking.Game.Sessions;
using Tiger.Storage;
namespace Tiger.Communication.Messages.Incoming.Handshake;
public class SsoTicketEvent : IMessageEvent
{
private readonly IRepository<Habbo> _habboRepository;
private readonly IGameSessionManager _gameSessionManager;
private readonly ISettingManager _settingManager;
public SsoTicketEvent(IRepository<Habbo> habboRepository, IGameSessionManager gameSessionManager, ISettingManager settingManager)
{
_habboRepository = habboRepository;
_gameSessionManager = gameSessionManager;
_settingManager = settingManager;
}
public IncomingHeaders Header => IncomingHeaders.SSoTicketEvent;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
var sso = request.ReadString();
if (sso == null)
{
await _gameSessionManager.CloseAsync("Malformed packet", gameSession);
return;
}
var habbo = await _habboRepository.FindOneByAsync(h => h.SsoTicket == sso);
if (habbo == null)
{
await _gameSessionManager.CloseAsync("User not found", gameSession);
return;
}
gameSession.Habbo = habbo;
await gameSession.SendComposerAsync(new AuthenticationOkMessageComposer());
await gameSession.SendComposerAsync(new HabboBroadcastMessageComposer(
_settingManager.GetSetting<string>("welcome.message")
.Replace("{user}", gameSession.Habbo.Username)
));
}
}

View File

@ -0,0 +1,61 @@
using Microsoft.Extensions.Logging;
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Notifications;
using Tiger.Communication.Messages.Outgoing.Security;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Achievements;
using Tiger.Game.Habbos;
using Tiger.Game.Settings;
using Tiger.Networking.Game.Sessions;
using Tiger.Storage;
namespace Tiger.Communication.Messages.Incoming.Handshake;
public class SsoTicketMessageEvent : IMessageEvent
{
private readonly IRepository<Habbo> _habboRepository;
private readonly IGameSessionManager _gameSessionManager;
private readonly ISettingManager _settingManager;
private readonly ILogger<SsoTicketMessageEvent> _logger;
private readonly IAchievementManager _achievementManager;
public SsoTicketMessageEvent(IRepository<Habbo> habboRepository, IGameSessionManager gameSessionManager, ISettingManager settingManager, ILogger<SsoTicketMessageEvent> logger, IAchievementManager achievementManager)
{
_habboRepository = habboRepository;
_gameSessionManager = gameSessionManager;
_settingManager = settingManager;
_logger = logger;
_achievementManager = achievementManager;
}
public IncomingHeaders Header => IncomingHeaders.SecurityTicket;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
var habbo = await _habboRepository.FindOneByAsync(h => h.SsoTicket == request.ReadString());
if (habbo == null)
{
await _gameSessionManager.CloseAsync("User not found", gameSession);
return;
}
gameSession.Habbo = habbo;
gameSession.Habbo.LastLogin = DateTime.Now;
gameSession.Habbo.Online = true;
_habboRepository.SaveAsync(gameSession.Habbo);
if (DateTime.Now.Hour == 15)
{
_achievementManager.UpdateAchievementAsync("ACH_HappyHour", 1, gameSession);
}
_logger.LogInformation("{User} logged in", gameSession.Habbo.Username);
await gameSession.SendComposerAsync(new AuthenticatedComposer());
await gameSession.SendComposerAsync(new HabboBroadcastMessageComposer(
_settingManager.GetSetting<string>("welcome.message")
.Replace("{user}", gameSession.Habbo.Username)
));
}
}

View File

@ -2,490 +2,468 @@ namespace Tiger.Communication.Messages.Incoming;
public enum IncomingHeaders : short public enum IncomingHeaders : short
{ {
AcceptFriendEvent = 137, AchievementList = 219,
AcceptTradingEvent = 3863, Authentication = -1,
AddAdminRightsToMemberEvent = 2894, BotConfiguration = 1986,
AddFavouriteRoomEvent = 3817, BotPickup = 3323,
AddItemToTradeEvent = 3107, BotPlace = 1592,
AddItemsToTradeEvent = 1263, BotSkillSave = 2624,
AddJukeboxDiskEvent = 753, GetClubOffers = 3285,
AddSpamWallPostItEvent = 3283,
AmbassadorAlertEvent = 2996,
AnswerPollEvent = 3505,
ApplySnapshotEvent = 3373,
ApproveMembershipRequestEvent = 3386,
ApproveNameEvent = 2109,
AssignRightsEvent = 808,
AvatarEffectActivatedEvent = 2959,
AvatarEffectSelectedEvent = 1752,
AvatarExpressionEvent = 2456,
BanUserWithDurationEvent = 1477,
BreedPetsEvent = 1638,
BuildersClubPlaceWallItemEvent = 2462,
BuildersClubQueryFurniCountEvent = 2529,
BuyMarketplaceOfferEvent = 1603,
CallForHelpEvent = 1691,
CallForHelpFromForumMessageEvent = 1412,
CallForHelpFromForumThreadEvent = 534,
CallForHelpFromImEvent = 2950,
CallForHelpFromPhotoEvent = 2492,
CanCreateRoomEvent = 2128,
CancelMarketplaceOfferEvent = 434,
CancelPetBreedingEvent = 2713,
CancelTypingEvent = 1474,
ChangeMottoEvent = 2228,
ChangePostureEvent = 2235,
ChangeUserNameEvent = 2977,
ChatEvent = 1314,
ChatReviewGuideDecidesOnOfferEvent = 3365,
ChatReviewGuideDetachedEvent = 2501,
ChatReviewGuideVoteEvent = 3961,
ChatReviewSessionCreateEvent = 3060,
CheckUserNameEvent = 3950,
ClientHelloEvent = 4000,
CloseIssueDefaultActionEvent = 2717,
CloseIssuesEvent = 2067,
CloseTradingEvent = 2551,
CommandBotEvent = 2624,
CompleteDiffieHandshakeEvent = 773,
CompostPlantEvent = 3835,
ConfirmAcceptTradingEvent = 2760,
ConfirmDeclineTradingEvent = 2341,
ConfirmPetBreedingEvent = 3382,
ControlYoutubeDisplayPlaybackEvent = 3005,
CraftEvent = 3591,
CraftSecretEvent = 1251,
CreateFlatEvent = 2752,
CreateGuildEvent = 230,
CreditFurniRedeemEvent = 3115,
CustomizeAvatarWithFurniEvent = 3374,
CustomizePetWithFurniEvent = 1328,
DanceEvent = 2080,
DeactivateGuildEvent = 1134,
DeclineFriendEvent = 2890,
DeleteFavouriteRoomEvent = 309,
DeleteRoomEvent = 532,
DeselectFavouriteHabboGroupEvent = 1820,
DiceOffEvent = 1533,
DropCarryItemEvent = 2814,
EditEventEvent = 3991,
EnterOneWayDoorEvent = 2765,
EventLogEvent = 3457,
FindNewFriendsEvent = 516,
FollowFriendEvent = 2970,
ForwardToSomeRoomEvent = 1703,
FriendFurniConfirmLockEvent = 3775,
Game2GetAccountGameStatusEvent = 11,
GameUnloadedEvent = 3207,
GetAchievementsEvent = 219,
GetBadgePointLimitsEvent = 1371,
GetBadgesEvent = 2769,
GetBannedUsersFromRoomEvent = 2267,
GetBonusRareInfoEvent = 957,
GetBotCommandConfigurationDataEvent = 1986,
GetBotInventoryEvent = 3848,
GetBundleDiscountRulesetEvent = 223,
GetCatalogIndexEvent = 1195,
GetCatalogPageEvent = 412,
GetCfhChatlogEvent = 211,
GetCfhStatusEvent = 2746,
GetClubGiftInfo = 487, GetClubGiftInfo = 487,
GetClubOffersEvent = 3285, GetCatalogIndex = 1195,
GetCraftableProductsEvent = 633, GetCatalogPage = 412,
GetCraftingRecipeEvent = 1173, CatalogPurchase = 3492,
GetCraftingRecipesAvailableEvent = 3086, CatalogPurchaseGift = 1411,
GetCreditsInfoEvent = 273, GetProductOffer = 2594,
GetCurrentTimingCodeEvent = 2912, ClientLatency = 295,
GetCustomRoomFilterEvent = 1911, ClientLatencyMeasure = 96,
GetExtendedProfileEvent = 3265, ClientPolicy = 26979,
GetFlatControllersEvent = 3385, ClientPong = 2596,
GetForumStatsEvent = 3149, ClientToolbarToggle = 2313,
GetForumsListEvent = 873, ClientVariables = 1053,
GetFriendRequestsEvent = 2448, GetCurrentTimingCode = 2912,
GetFurnitureAliasesEvent = 3898, DesktopView = 105,
GetGameListEvent = 741, GetBundleDiscountRuleset = 223,
GetGameStatusEvent = 3171, EventTracker = 3457,
GetGiftWrappingConfigurationEvent = 418, FindNewFriends = 516,
GetGuestRoomEvent = 2230, FurnitureAliases = 3898,
GetGuideReportingStatusEvent = 3786, FurnitureFloorUpdate = 248,
GetGuildCreationInfoEvent = 798, FurnitureMultistate = 99,
GetGuildEditInfoEvent = 1004, FurniturePickup = 3456,
GetGuildEditorDataEvent = 813, FurniturePlace = 1258,
GetGuildFurniContextMenuInfoEvent = 2651, FurniturePostitPlace = 2248,
GetGuildMembersEvent = 312, FurniturePostitSaveStickyPole = 3283,
GetGuildMembershipsEvent = 367, FurnitureRandomstate = 3617,
GetHabboGroupBadgesEvent = 21, FurnitureWallMultistate = 210,
GetHabboGroupDetailsEvent = 2991, FurnitureWallUpdate = 168,
GetIgnoredUsersEvent = 3878, GamesInit = 2914,
GetItemDataEvent = 3964, GamesList = 741,
GetJukeboxPlayListEvent = 1435, Acceptgameinvite = 3802,
GetLimitedOfferAppearingNextEvent = 410, Gameunloadedmessage = 3207,
GetMotdEvent = 1523, Getgameachievementsmessage = 2399,
GetMarketplaceCanMakeOfferEvent = 848, Getgamestatusmessage = 3171,
GetMarketplaceConfigurationEvent = 2597, Getusergameachievementsmessage = 389,
GetMarketplaceItemStatsEvent = 3288, Joinqueuemessage = 1458,
GetMarketplaceOffersEvent = 2407, Leavequeuemessage = 2384,
GetMarketplaceOwnOffersEvent = 2105, Resetresolutionachievementmessage = 3144,
GetMemberGuildItemCountEvent = 3593, Getweeklygamerewardwinners = 1054,
GetMessagesEvent = 232, Game2Getaccountgamestatusmessage = 11,
GetModeratorRoomInfoEvent = 707, Game2Checkgamedirectorystatusmessage = 3259,
GetModeratorUserInfoEvent = 3295, Game2Exitgamemessage = 1445,
GetNowPlayingEvent = 1325, Game2Gamechatmessage = 2502,
GetOccupiedTilesEvent = 1687, Game2Loadstagereadymessage = 2415,
GetOfficialSongIdEvent = 3189, Game2Playagainmessage = 3196,
GetPendingCallsForHelpEvent = 3267, Game2Requestfullstatusupdatemessage = 1598,
GetPetCommandsEvent = 2161, Game2Getweeklyfriendsleaderboard = 1232,
GetPetInfoEvent = 2934, Game2Getweeklyleaderboard = 2565,
GetPetInventoryEvent = 3095, GetGiftWrappingConfig = 418,
GetPopularRoomTagsEvent = 826, GroupAdminAdd = 2894,
GetProductOfferEvent = 2594, GroupAdminRemove = 722,
GetPromoArticlesEvent = 1827, GroupCreateOptions = 798,
GetRecyclerPrizesEvent = 398, GroupFavorite = 3549,
GetRecyclerStatusEvent = 1342, GetForumStats = 3149,
GetRelationshipStatusInfoEvent = 2138, GetForumThreads = 873,
GetResolutionAchievementsEvent = 359, GetForumsList = 436,
GetRoomAdPurchaseInfoEvent = 1075, GetForumMessages = 232,
GetRoomChatlogEvent = 2587, GetForumThread = 3900,
GetRoomEntryDataEvent = 2300, GetUnreadForumsCount = 2908,
GetRoomEntryTileEvent = 3559, ForumModerateMessage = 286,
GetRoomSettingsEvent = 3129, ForumModerateThread = 1397,
GetRoomVisitsEvent = 3526, ForumPostMessage = 3529,
GetSelectedBadgesEvent = 2091, UpdateForumReadMarker = 1855,
GetSellablePetPalettesEvent = 1756, UpdateForumSettings = 2214,
GetSongInfoEvent = 3082, ForumUpdateThread = 3045,
GetSoundSettingsEvent = 2388, GroupInfo = 2991,
GetTalentTrackEvent = 196, GroupDelete = 1134,
GetTalentTrackLevelEvent = 2127, GroupMemberRemoveConfirm = 3593,
GetThreadsEvent = 436, GroupMemberRemove = 593,
GetUnreadForumsCountEvent = 2908, GroupMembers = 312,
GetUserChatlogEvent = 1391, GroupMemberships = 367,
GetUserEventCatsEvent = 1782, GroupRequest = 998,
GetUserFlatCatsEvent = 3027, GroupRequestAccept = 3386,
GetUserTagsEvent = 17, GroupRequestDecline = 1894,
GetWardrobeEvent = 2742, GroupSettings = 1004,
GetWeeklyGameRewardEvent = 2914, GroupParts = 813,
GetWeeklyGameRewardWinnersEvent = 1054, GroupBuy = 230,
GetYoutubeDisplayStatusEvent = 336, GroupSaveInformation = 3137,
GuideSessionCreateEvent = 3338, GroupSaveBadge = 1991,
GuideSessionFeedbackEvent = 477, GroupSaveColors = 1764,
GuideSessionGetRequesterRoomEvent = 1052, GroupSavePreferences = 3435,
GuideSessionGuideDecidesEvent = 1424, GroupBadges = 21,
GuideSessionInviteRequesterEvent = 234, GroupUnblockMember = 2864,
GuideSessionIsTypingEvent = 519, GetBadgePointsLimits = 1371,
GuideSessionMessageEvent = 3899, Requestabadge = 3077,
GuideSessionOnDutyUpdateEvent = 1922, Getisbadgerequestfulfilled = 1364,
GuideSessionReportEvent = 3969, ItemClothingRedeem = 3374,
GuideSessionRequesterCancelsEvent = 291, ItemColorWheelClick = 2144,
GuideSessionResolvedEvent = 887, ItemDiceClick = 1990,
HabboSearchEvent = 1210, ItemDiceClose = 1533,
// HotelViewClaimBadgeRewardEvent = -1, ItemDimmerSave = 1648,
HotelViewRequestBadgeRewardEvent = 2318, ItemDimmerSettings = 2813,
HotelViewRequestSecondsUntilEvent = 271, ItemDimmerToggle = 2296,
IgnoreUserEvent = 1117, ItemExchangeRedeem = 3115,
InfoRetrieveEvent = 357, ItemPaint = 711,
InitDiffieHandshakeEvent = 3110, SetObjectData = 3608,
JoinHabboGroupEvent = 998, ItemStackHelper = 3839,
JoinQueueEvent = 1458, MarketplaceConfig = 2597,
JukeBoxEventOne = 2304, AcceptFriend = 137,
KickMemberEvent = 593, MessengerChat = 3567,
LatencyPingRequestEvent = 295, DeclineFriend = 2890,
LetUserInEvent = 1644, FollowFriend = 3997,
LookToEvent = 3301, MessengerFriends = 1523,
MakeOfferEvent = 3447, MessengerInit = 2781,
MessengerInitEvent = 2781, MessengerRelationships = 2138,
ModAlertEvent = 229, SetRelationshipStatus = 3768,
ModBanEvent = 2766, RemoveFriend = 1689,
ModKickEvent = 2582, RequestFriend = 3157,
ModMessageEvent = 1840, GetFriendRequests = 2448,
ModMuteEvent = 1945, SendRoomInvite = 1276,
// ModToolRequestRoomUserChatlogEvent = -1, HabboSearch = 1210,
ModToolSanctionEvent = 1392, FriendListUpdate = 1419,
// ModToolWarnEvent = -1, ModToolUserInfo = 3295,
ModTradingLockEvent = 3742, GetUserFlatCats = 3027,
ModerateMessageEvent = 286, NavigatorInit = 2110,
ModerateRoomEvent = 3260, NavigatorSearch = 249,
ModerateThreadEvent = 1397, NavigatorSearchClose = 1834,
ModeratorActionEvent = 3842, NavigatorSearchOpen = 637,
MountPetEvent = 1036, NavigatorSearchSave = 2226,
MoveAvatarEvent = 3320, GetUserEventCats = 1782,
MoveObjectEvent = 248, NavigatorSettingsSave = 3159,
MovePetEvent = 3449, NavigatorCategoryListMode = 1202,
MoveWallItemEvent = 168, NavigatorDeleteSavedSearch = 1954,
MuteAllInRoomEvent = 3637, PetInfo = 2934,
MyFavouriteRoomsSearchEvent = 2578, PetPickup = 1581,
MyFriendsRoomsSearchEvent = 2266, PetPlace = 2647,
MyGuildBasesSearchEvent = 39, PetRespect = 3202,
MyRoomHistorySearchEvent = 2264, PetRide = 1036,
MyRoomRightsSearchEvent = 272, PetMove = 3449,
MyRoomsSearchEvent = 2277, PetOpenPackage = 3698,
NavigatorAddCollapsedCategoryEvent = 1834, PetSelected = 549,
NavigatorAddSavedSearchEvent = 2226, PetsBreed = 1638,
NavigatorDeleteSavedSearchEvent = 1954, PetCancelBreeding = 2713,
NavigatorRemoveCollapsedCategoryEvent = 637, PetConfirmBreeding = 3382,
NavigatorSetSearchCodeViewModeEvent = 1202, GetPetTrainingPanel = 2161,
NewNavigatorInitEvent = 2110, RecyclerPrizes = 398,
NewNavigatorSearchEvent = 249, RecyclerStatus = 1342,
NewUserExperienceGetGiftsEvent = 1822, RecyclerItems = 2771,
NewUserExperienceScriptProceedEvent = 1299, ReleaseVersion = 4000,
OpenCampaignCalendarDoorEvent = 8809, CallForHelp = 1691,
OpenCampaignCalendarDoorAsStaffEvent = 2507, RoomAmbassadorAlert = 2996,
OpenFlatConnectionEvent = 2312, RoomBanGive = 1477,
OpenPetPackageEvent = 3698, RoomBanList = 2267,
OpenTradingEvent = 1481, RoomBanRemove = 992,
PassCarryItemEvent = 2941, RoomCreate = 2752,
PickIssuesEvent = 15, RoomDelete = 532,
PickupObjectEvent = 3456, RoomDoorbell = 1644,
PlaceBotEvent = 1592, RoomEnter = 2312,
PlaceObjectEvent = 1258, RoomFavorite = 3817,
PlacePetEvent = 2647, RoomFavoriteRemove = 309,
PlacePostItEvent = 2248, CanCreateRoom = 2128,
PollRejectEvent = 1773, CancelRoomEvent = 2725,
PollStartEvent = 109, EditRoomEvent = 3991,
PongEvent = 2596, CompetitionRoomSearch = 433,
PopularRoomsSearchEvent = 2758, ForwardToRandomPromotedRoom = 10,
PostMessageEvent = 3529, ForwardToSomeRoom = 1703,
PresentOpenEvent = 3558, GetCategoriesWithUserCount = 3782,
PublishPhotoEvent = 2068, GetGuestRoom = 2230,
PurchaseFromCatalogAsGiftEvent = 1411, GetOfficialRooms = 1229,
PurchaseFromCatalogEvent = 3492, GetPopularRoomTags = 826,
PurchasePhotoEvent = 2408, GuildBaseSearch = 2930,
PurchaseRoomAdEvent = 777, MyFavouriteRoomsSearch = 2578,
PurchaseTargetedOfferEvent = 1826, MyFrequentRoomHistorySearch = 1002,
PurchaseVipMembershipExtensionEvent = 3407, MyFriendsRoomSearch = 2266,
QuitEvent = 105, MyGuildBasesSearch = 39,
RateFlatEvent = 3582, MyRecommendedRooms = 2537,
RecycleItemsEvent = 2771, MyRoomHistorySearch = 2264,
RedeemMarketplaceOfferCreditsEvent = 2650, MyRoomRightsSearch = 272,
RedeemVoucherEvent = 339, MyRoomsSearch = 2277,
RejectMembershipRequestEvent = 1894, PopularRoomsSearch = 2758,
ReleaseIssuesEvent = 1572, RoomAdEventTabClicked = 2412,
RemoveAdminRightsFromMemberEvent = 722, RoomAdEventTabViewed = 2668,
RemoveAllRightsEvent = 2683, RoomAdSearch = 2809,
RemoveBotFromFlatEvent = 3323, RoomTextSearch = 3943,
RemoveFriendEvent = 1689, RoomsWhereMyFriendsAre = 1786,
RemoveItemEvent = 3336, RoomsWithHighestScoreSearch = 2939,
RemoveItemFromTradeEvent = 3845, SetRoomSessionTags = 3305,
RemoveJukeboxDiskEvent = 3050, UpdateRoomThumbnail = 2468,
RemoveOwnRoomRightsRoomEvent = 3182, RoomKick = 1320,
RemovePetFromFlatEvent = 1581, RoomLike = 3582,
RemoveRightsEvent = 2064, RoomModel = 2300,
RemoveSaddleFromPetEvent = 186, GetOccupiedTiles = 1687,
RenderRoomEvent = 3226, GetRoomEntryTile = 3559,
RenderRoomThumbnailEvent = 1982, RoomModelSave = 875,
RentableSpaceCancelRentEvent = 1667, RoomMute = 3637,
RentableSpaceRentEvent = 2946, RoomMuteUser = 3485,
// RequestAchievementConfigurationEvent = -1, RoomRightsGive = 808,
RequestCameraConfigurationEvent = 796, RoomRightsList = 3385,
RequestFriendEvent = 3157, RoomRightsRemove = 2064,
RequestFurniInventoryEvent = 3150, RoomRightsRemoveAll = 2683,
RequestFurniInventoryWhenNotInRoomEvent = 3500, RoomRightsRemoveOwn = 3182,
RequestRoomPropertySet = 711, RoomSettings = 3129,
RespectPetEvent = 3202, RoomSettingsSave = 1969,
RespectUserEvent = 2694, RoomSettingsUpdateRoomCategoryAndTrade = 1265,
RoomDimmerChangeStateEvent = 2296, RoomStaffPick = 1918,
RoomDimmerGetPresetsEvent = 2813, RoomFilterWords = 1911,
RoomDimmerSavePresetEvent = 1648, RoomFilterWordsModify = 3001,
RoomTextSearchEvent = 3943, Mysteryboxwaitingcanceledmessage = 2012,
RoomUserKickEvent = 1320, MysteryboxOpenTrophy = 3074,
RoomUserMuteEvent = 3485, SecurityMachine = 2490,
RoomsWhereMyFriendsAreSearchEvent = 1786, SecurityTicket = 2419,
RoomsWithHighestScoreSearchEvent = 2939, Trade = 1481,
SSoTicketEvent = 2419, TradeAccept = 3863,
SaveRoomSettingsEvent = 1969, TradeCancel = 2341,
SaveWardrobeOutfitEvent = 800, TradeClose = 2551,
ScrGetKickbackInfoEvent = 869, TradeConfirm = 2760,
ScrGetUserInfoEvent = 3166, TradeItem = 3107,
// SearchRoomsByTagEvent = -1, TradeItemRemove = 3845,
SelectClubGiftEvent = 2276, TradeItems = 1263,
SelectFavouriteHabboGroupEvent = 3549, TradeUnaccept = 1444,
SendMsgEvent = 3567, UnitAction = 2456,
SendRoomInviteEvent = 1276, UnitChat = 1314,
SetActivatedBadgesEvent = 644, UnitChatShout = 2085,
SetChatPreferencesEvent = 1262, UnitChatWhisper = 1543,
SetChatStylePreferenceEvent = 1030, UnitDance = 2080,
SetClothingChangeDataEvent = 924, UnitDropHandItem = 2814,
SetCustomStackingHeightEvent = 3839, UnitGiveHanditem = 2941,
SetIgnoreRoomInvitesEvent = 1086, UnitLook = 3301,
SetItemDataEvent = 3666, UnitPosture = 2235,
SetMannequinFigureEvent = 2209, UnitSign = 1975,
SetMannequinNameEvent = 2850, UnitTyping = 1597,
SetNewNavigatorWindowPreferencesEvent = 3159, UnitTypingStop = 1474,
SetObjectDataEvent = 3608, UnitWalk = 3320,
SetRandomStateEvent = 3617, UserBadges = 2769,
SetRelationshipStatusEvent = 3768, UserBadgesCurrent = 2091,
SetRoomBackgroundColorDataEvent = 2880, UserBadgesCurrentUpdate = 644,
SetRoomCameraPreferencesEvent = 1461, UserBots = 3848,
SetSoundSettingsEvent = 1367, UserCurrency = 273,
SetTargetedOfferStateEvent = 2041, UserEffectActivate = 2959,
SetYoutubeDisplayPlaylistEvent = 2069, UserEffectEnable = 1752,
ShoutEvent = 2085, UserFigure = 2730,
SignEvent = 1975, UserFurniture = 3150, // sent when in room
SpinWheelOfFortuneEvent = 2144, Requestfurniinventorywhennotinroom = 3500, // sent when not in room
StartTypingEvent = 1597, UserHomeRoom = 1740,
SubmitRoomToCompetitionEvent = 2595, UserInfo = 357,
ThrowDiceEvent = 1990, UserMotto = 2228,
TogglePetBreedingPermissionEvent = 3379, UserIgnored = 3878,
TogglePetRidingPermissionEvent = 1472, UserPets = 3095,
ToggleStaffPickEvent = 1918, UserProfile = 3265,
UnacceptTradingEvent = 1444, UserProfileByName = 2249,
UnbanUserFromRoomEvent = 992, UserRespect = 2694,
UnignoreUserEvent = 2061, GetSoundSettings = 2388,
UniqueIdEvent = 2490, UserSettingsCamera = 1461,
UpdateActionEvent = 2281, UserSettingsChatStyle = 1030,
UpdateConditionEvent = 3203, UserSettingsInvites = 1086,
UpdateFigureDataEvent = 2730, UserSettingsOldChat = 1262,
UpdateFloorPropertiesEvent = 875, UserSettingsVolume = 1367,
UpdateForumSettingsEvent = 2214, UserSubscription = 3166,
UpdateGuildBadgeEvent = 1991, GetWardrobe = 2742,
UpdateGuildColorsEvent = 1764, SaveWardrobeOutfit = 800,
UpdateGuildIdentityEvent = 3137, UserTags = 17,
UpdateGuildSettingsEvent = 3435, PeerUsersClassification = 1160,
UpdateHomeRoomEvent = 1740, UserClassification = 2285,
UpdateRoomFilterEvent = 3001, VisitUser = 2970,
UpdateThreadEvent = 3045, WiredActionSave = 2281,
UpdateTriggerEvent = 1520, WiredApplySnapshot = 3373,
UpdateUiFlagsEvent = 2313, WiredConditionSave = 3203,
UseFurnitureEvent = 99, WiredOpen = 768,
UseWallItemEvent = 210, WiredTriggerSave = 1520,
VisitUserEvent = 3997, GetItemData = 3964,
WhisperEvent = 1543, OneWayDoorClick = 2765,
AcceptGameInviteEvent = 3802, RemoveWallItem = 3336,
AcceptQuestEvent = 3604, SetItemData = 3666,
ApproveAllMembershipRequestsEvent = 882, CatalogRedeemVoucher = 339,
BuildersClubPlaceRoomItemEvent = 1051, RoomTonerApply = 2880,
BuyMarketplaceTokensEvent = 1866, FriendFurniConfirmLock = 3775,
CallForHelpFromSelfieEvent = 2755, MannequinSaveName = 2850,
CancelEventEvent = 2725, MannequinSaveLook = 2209,
CancelQuestEvent = 3133, PresentOpenPresent = 3558,
ChangeEmailEvent = 3965, CatalogSelectVipGift = 2276,
ChangeQueueEvent = 3093, UserIgnoreId = 3314,
CommunityGoalVoteEvent = 3536, UserIgnore = 1117,
CompetitionRoomsSearchEvent = 433, UserUnignore = 2061,
DeletePendingCallsForHelpEvent = 3605, ModtoolRequestRoomInfo = 707,
DisconnectEvent = 2445, ModtoolChangeRoomSettings = 3260,
ExtendRentOrBuyoutFurniEvent = 1071, ModtoolRequestUserChatlog = 1391,
ExtendRentOrBuyoutStripItemEvent = 2115, ModtoolRequestRoomChatlog = 2587,
ForwardToACompetitionRoomEvent = 172, ModtoolSanctionAlert = 229,
ForwardToARandomPromotedRoomEvent = 10, ModtoolSanctionBan = 2766,
ForwardToRandomCompetitionRoomEvent = 865, ModtoolSanctionKick = 2582,
FriendListUpdateEvent = 1419, ModtoolSanctionTradelock = 3742,
FriendRequestQuestCompleteEvent = 1148, ModtoolAlertevent = 1840,
Game2CheckGameDirectoryStatusEvent = 3259, ModtoolSanctionMute = 1945,
Game2ExitGameEvent = 1445, ModtoolRequestUserRooms = 3526,
Game2GameChatEvent = 2502, ModtoolRoomAlert = 3842,
Game2GetWeeklyFriendsLeaderboardEvent = 1232, ModtoolPreferences = 31,
Game2GetWeeklyLeaderboardEvent = 2565, CloseIssueDefaultAction = 2717,
Game2LoadStageReadyEvent = 2415, CloseIssues = 2067,
Game2PlayAgainEvent = 3196, DefaultSanction = 1681,
Game2RequestFullStatusUpdateEvent = 1598, GetCfhChatlog = 211,
GetCatalogPageExpirationEvent = 742, ModtoolSanction = 1392,
GetCatalogPageWithEarliestExpiryEvent = 3135, PickIssues = 15,
GetCategoriesWithUserCountEvent = 3782, ReleaseIssues = 1572,
GetCommunityGoalEarnedPrizesEvent = 2688, ConvertGlobalRoomId = 314,
GetCommunityGoalHallOfFameEvent = 2167, RequestSellItem = 848,
GetCommunityGoalProgressEvent = 1145, RequestMarketplaceItemStats = 3288,
GetConcurrentUsersGoalProgressEvent = 1343, MarketplaceSellItem = 3447,
GetConcurrentUsersRewardEvent = 3872, MarketplaceRequestOwnItems = 2105,
GetDailyQuestEvent = 2486, MarketplaceTakeBackItem = 434,
GetDirectClubBuyAvailableEvent = 801, MarketplaceRedeemCredits = 2650,
GetEmailStatusEvent = 2557, MarketplaceRequestOffers = 2407,
GetExtendedProfileByNameEvent = 2249, MarketplaceBuyOffer = 1603,
GetFaqCategoryEvent = 3445, MarketplaceBuyTokens = 1866,
GetFaqTextEvent = 1849, CatalogRequesetPetBreeds = 1756,
GetGameAchievementsEvent = 2399, ApproveName = 2109,
GetHabboBasicMembershipExtendOfferEvent = 603, UnitGiveHanditemPet = 2768,
GetInterstitialEvent = 2519, PetSupplement = 749,
GetIsBadgeRequestFulfilledEvent = 1364, FurnitureGroupInfo = 2651,
GetIsOfferGiftableEvent = 1347, AchievementResolutionOpen = 359,
GetIsUserPartOfCompetitionEvent = 2077, UsePetProduct = 1328,
GetNextTargetedOfferEvent = 2487, RemovePetSaddle = 186,
GetOfficialRoomsEvent = 1229, TogglePetRiding = 1472,
GetQuestsEvent = 3333, TogglePetBreeding = 3379,
GetQuizQuestionsEvent = 1296, UnseenResetCategory = 3493,
GetSeasonalCalendarDailyOfferEvent = 3257, UnseenResetItems = 2343,
GetSeasonalQuestsOnlyEvent = 1190, CommunityGoalVoteComposer = 3536,
GetSoundMachinePlayListEvent = 3498, GetPromoArticles = 1827,
GetTargetedOfferEvent = 596, AcceptQuest = 3604,
GetThreadEvent = 3900, ActivateQuest = 793,
GetUserGameAchievementsEvent = 389, CancelQuest = 3133,
GiveSupplementToPetEvent = 749, FriendRequestQuestComplete = 1148,
GoToFlatEvent = 685, GetCommunityGoalEarnedPrizes = 2688,
GuideAdvertisementReadEvent = 2455, GetCommunityGoalHallOfFame = 2167,
GuildBaseSearchEvent = 2930, GetCommunityGoalProgress = 1145,
HarvestPetEvent = 1521, GetConcurrentUsersGoalProgress = 1343,
IgnoreUserIdEvent = 3314, GetConcurrentUsersReward = 3872,
InterstitialShownEvent = 1109, GetDailyQuest = 2486,
LagWarningReportEvent = 3847, GetQuests = 3333,
LatencyPingReportEvent = 96, GetSeasonalQuestsOnly = 1190,
LeaveQueueEvent = 2384, OpenQuestTracker = 2750,
ModToolPreferencesEvent = 31, RedeemCommunityGoalPrize = 90,
MyFrequentRoomHistorySearchEvent = 1002, RejectQuest = 2397,
MyRecommendedRoomsEvent = 2537, StartCampaign = 1697,
MysteryBoxWaitingCanceledEvent = 2012, GetBonusRareInfo = 957,
OpenMysteryTrophyEvent = 3074, Craft = 3591,
OpenQuestTrackerEvent = 2750, CraftSecret = 1251,
OpenWelcomeGiftEvent = 2638, GetCraftableProducts = 633,
PassCarryItemToPetEvent = 2768, GetCraftingRecipe = 1173,
PeerUsersClassificationEvent = 1160, GetCraftingRecipesAvailable = 3086,
PerformanceLogEvent = 3230, PhotoCompetition = 3959,
PetSelectedEvent = 549, PublishPhoto = 2068,
PhotoCompetitionEvent = 3959, PurchasePhoto = 2408,
PostQuizAnswersEvent = 3720, RenderRoom = 3226,
PurchaseBasicMembershipExtensionEvent = 2735, RenderRoomThumbnail = 1982,
RedeemCommunityGoalPrizeEvent = 90, RequestCameraConfiguration = 796,
RejectQuestEvent = 2397, AddJukeboxDisk = 753,
RentableSpaceStatusEvent = 872, GetJukeboxPlaylist = 1435,
RequestABadgeEvent = 3077, GetNowPlaying = 1325,
ResetPhoneNumberStateEvent = 2741, GetOfficialSongId = 3189,
ResetResolutionAchievementEvent = 3144, GetSongInfo = 3082,
ResetUnseenItemIdsEvent = 3493, GetSoundMachinePlaylist = 3498,
ResetUnseenItemsEvent = 2343, GetUserSongDisks = 2304,
RoomAdEventTabAdClickedEvent = 2412, RemoveJukeboxDisk = 3050,
RoomAdEventTabViewedEvent = 2668, InterstitialShown = 1109,
RoomAdPurchaseInitiatedEvent = 2283, GetInterstitial = 2519,
RoomAdSearchEvent = 2809, ChangeUsername = 2977,
RoomCompetitionInitEvent = 1334, CheckUsername = 3950,
RoomNetworkOpenConnectionEvent = 3736, OpenCampaignCalendarDoorStaff= 3889,
RoomUsersClassificationEvent = 2285, OpenCampaignCalendarDoor = 2257,
SearchFaqsEvent = 2031, BuildersClubPlaceRoomItem = 1051,
SetPhoneNumberVerificationStatusEvent = 1379, BuildersClubPlaceWallItem = 462,
SetRoomSessionTagsEvent = 3305, BuildersClubQueryFurniCount = 2529,
ShopTargetedOfferViewedEvent = 3483, GetCatalogPageExpiration = 742,
StartCampaignEvent = 1697, GetCatalogPageWithEarliestExp = 3135,
TryPhoneNumberEvent = 790, GetDirectClubBuyAvailable = 801,
UnblockGroupMemberEvent = 2864, GetHabboBasicMembershipExtendOffer = 603,
UpdateForumReadMarkerEvent = 1855, GetHabboClubExtendOffer = 2462,
UpdateRoomCategoryAndTradeSettingsEvent = 1265, GetIsOfferGiftable = 1347,
UpdateRoomThumbnailEvent = 2468, GetLimitedOfferAppearingNext = 410,
VerifyCodeEvent = 2721, GetNextTargetedOffer = 596,
VersionCheckEvent = 1053, GetRoomAdPurchaseInfo = 1075,
VoteForRoomEvent = 143, GetSeasonalCalendarDailyOffer = 3257,
WelcomeGiftChangeEmailEvent = 66, GetTargetedOffer = 2487,
UnknownSnowStormEvent6000 = 6000, MarkCatalogNewAdditionsPageOpened = 2150,
UnknownSnowStormEvent6001 = 6001, PurchaseBasicMembershipExtension = 2735,
UnknownSnowStormEvent6002 = 6002, PurchaseRoomAd = 777,
UnknownSnowStormEvent6003 = 6003, PurchaseTargetedOffer = 1826,
UnknownSnowStormEvent6004 = 6004, PurchaseVipMembershipExtension = 3407,
UnknownSnowStormEvent6005 = 6005, RoomAdPurchaseInitiated = 2283,
UnknownSnowStormEvent6006 = 6006, SetTargettedOfferState = 2041,
UnknownSnowStormEvent6007 = 6007, ShopTargetedOfferViewed = 3483,
UnknownSnowStormEvent6008 = 6008, HelperTalentTrack = 196,
UnknownSnowStormEvent6009 = 6009, TalentTrackGetLevel = 2127,
UnknownSnowStormEvent6010 = 6010, ForwardToACompetitionRoom = 172,
UnknownSnowStormEvent6011 = 6011, ForwardToASubmittableRoom = 1450,
SnowStormJoinQueueEvent = 6012, ForwardToRandomCompetitionRoom = 865,
UnknownSnowStormEvent6013 = 6013, GetIsUserPartOfCompetition = 2077,
UnknownSnowStormEvent6014 = 6014, GetSecondsUntil = 271,
UnknownSnowStormEvent6015 = 6015, RoomCompetitionInit = 1334,
UnknownSnowStormEvent6016 = 6016, SubmitRoomToCompetition = 2595,
UnknownSnowStormEvent6017 = 6017, VoteForRoom = 143,
UnknownSnowStormEvent6018 = 6018, GetGift = 2436,
UnknownSnowStormEvent6019 = 6019, ResetPhoneNumberState = 2741,
UnknownSnowStormEvent6020 = 6020, SetPhoneNumberVerificationStatus = 1379,
UnknownSnowStormEvent6021 = 6021, TryPhoneNumber = 790,
UnknownSnowStormEvent6022 = 6022, VerifyCode = 2721,
UnknownSnowStormEvent6023 = 6023, ControlYoutubeDisplayPlayback = 3005,
UnknownSnowStormEvent6024 = 6024, GetYoutubeDisplayStatus = 336,
UnknownSnowStormEvent6025 = 6025, SetYoutubeDisplayPlaylist = 2069,
SnowStormUserPickSnowballEvent = 6026, GoToFlat = 685,
ChangeQueue = 3093,
CallForHelpFromForumMessage = 1412,
CallForHelpFromForumThread = 534,
CallForHelpFromIm = 2950,
CallForHelpFromPhoto = 2492,
CallForHelpFromSelfie = 2755,
ChatReviewGuideDecides = 3365,
ChatReviewGuideDetached = 2501,
ChatReviewGuideVote = 3961,
ChatReviewSessionCreate = 3060,
DeletePendingCallsForHelp = 3605,
GetCfhStatus = 2746,
GetFaqCategory = 3445,
GetFaqText = 1849,
GetGuideReportingStatus = 3786,
GetPendingCallsForHelp = 3267,
GetQuizQuestions = 1296,
GuideSessionCreate = 3338,
GuideSessionFeedback = 477,
GuideSessionGetRequesterRoom = 1052,
GuideSessionGuideDecides = 1424,
GuideSessionInviteRequester = 234,
GuideSessionIsTyping = 519,
GuideSessionMessage = 3899,
GuideSessionOnDutyUpdate = 1922,
GuideSessionReport = 3969,
GuideSessionRequesterCancels = 291,
GuideSessionResolved = 887,
PostQuizAnswers = 3720,
SearchFaqs = 2031,
PollAnswer = 3505,
PollReject = 1773,
PollStart = 109,
PollVoteCounter = 6200,
Disconnect = 2445,
ScrGetKickbackInfo = 869,
CompostPlant = 3835,
HarvestPet = 1521,
SetClothingChangeData = 924,
GroupUnfavorite = 1820,
NewUserExperienceGetGifts = 1822,
NewUserExperienceScriptProceed = 1299,
HandshakeInitDiffie = 3110,
HandshakeCompleteDiffie = 773,
WelcomeOpenGift = 2638,
WelcomeGiftChangeEmail = 66,
EmailGetStatus = 2557,
EmailChange = 3965,
ApproveAllMembershipRequests = 882,
RentableSpaceCancelRent = 1667,
RentableSpaceRent = 2946,
RentableSpaceStatus = 872,
TrackingPerformanceLog = 3230,
TrackingLagWarningReport = 3847,
RoomDirectoryRoomNetworkOpenConnection = 3736,
RentableExtendRentOrBuyoutStripItem = 2115,
RentableExtendRentOrBuyoutFurni = 1071,
RentableGetRentOrBuyoutOffer = 2518,
} }

View File

@ -0,0 +1,28 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Inventory.Badges;
using Tiger.Communication.Messages.Types;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Inventory.Badges;
public class RequestBadgesEvent : IMessageEvent
{
private readonly IGameSessionManager _gameSessionManager;
public RequestBadgesEvent(IGameSessionManager gameSessionManager)
{
_gameSessionManager = gameSessionManager;
}
public IncomingHeaders Header => IncomingHeaders.UserBadges;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
await gameSession.SendComposerAsync(new BadgesComposer(gameSession.Habbo.Badges));
}
}

View File

@ -0,0 +1,60 @@
using System.Collections.ObjectModel;
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.User.Data;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
using Tiger.Networking.Game.Sessions;
using Tiger.Storage;
namespace Tiger.Communication.Messages.Incoming.Inventory.Badges;
public class SetActivatedBadgesEvent : IMessageEvent
{
private readonly IGameSessionManager _gameSessionManager;
private readonly IRepository<Badge> _badgeRepository;
public SetActivatedBadgesEvent(IGameSessionManager gameSessionManager, IRepository<Badge> badgeRepository)
{
_gameSessionManager = gameSessionManager;
_badgeRepository = badgeRepository;
}
public IncomingHeaders Header => IncomingHeaders.UserBadgesCurrentUpdate;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
var wearingBadges = new Collection<Badge>();
var badgesToUpdate = new Dictionary<int, Badge>();
var current = gameSession.Habbo.Badges.Where(b => b.Slot != 0);
foreach (var currentBadge in current)
{
currentBadge.Slot = 0;
badgesToUpdate.Add(currentBadge.Id, currentBadge);
}
for (var i = 0; i < 5; i++)
{
var slotId = request.ReadInt32();
var code = request.ReadString();
if (slotId is < 1 or > 5 || string.IsNullOrEmpty(code)) continue;
var badge = gameSession.Habbo.Badges.FirstOrDefault(b => b.Code == code);
if (badge == null) continue;
badge.Slot = slotId;
wearingBadges.Add(badge);
badgesToUpdate.TryAdd(badge.Id, badge);
}
await _badgeRepository.SaveManyAsync(badgesToUpdate.Values);
await gameSession.SendComposerAsync(new UserCurrentBadgesComposer(gameSession.Habbo.Id, wearingBadges));
}
}

View File

@ -0,0 +1,30 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Inventory.Currency;
using Tiger.Communication.Messages.Outgoing.Notifications;
using Tiger.Communication.Messages.Types;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Inventory.Currency;
public class UserCurrencyEvent : IMessageEvent
{
private readonly IGameSessionManager _gameSessionManager;
public UserCurrencyEvent(IGameSessionManager gameSessionManager)
{
_gameSessionManager = gameSessionManager;
}
public IncomingHeaders Header => IncomingHeaders.UserCurrency;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
await gameSession.SendComposerAsync(new UserCreditsComposer(gameSession.Habbo.Credits));
await gameSession.SendComposerAsync(new UserCurrencyComposer(gameSession.Habbo.Activitypoints.Values));
}
}

View File

@ -0,0 +1,34 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Inventory.Subscription;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Achievements;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Inventory.Subscription;
public class UserSubscriptionEvent : IMessageEvent
{
private readonly IGameSessionManager _gameSessionManager;
private readonly IAchievementManager _achievementManager;
public UserSubscriptionEvent(IGameSessionManager gameSessionManager, IAchievementManager achievementManager)
{
_gameSessionManager = gameSessionManager;
_achievementManager = achievementManager;
}
public IncomingHeaders Header => IncomingHeaders.UserSubscription;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
_achievementManager.UpdateAchievementAsync("ACH_HC", ((gameSession.Habbo.GetPastSubscriptionDays() / 31)), gameSession);
await gameSession.SendComposerAsync(new UserSubscriptionComposer(gameSession.Habbo.GetActiveSubscription(),
gameSession.Habbo.GetPastSubscriptionDays()));
}
}

View File

@ -0,0 +1,31 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Landingview;
using Tiger.Communication.Messages.Types;
using Tiger.Game.LandingView;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Landingview;
public class GetPromoArticlesEvent : IMessageEvent
{
private readonly IGameSessionManager _gameSessionManager;
private readonly ILandingViewManager _landingViewManager;
public GetPromoArticlesEvent(IGameSessionManager gameSessionManager, ILandingViewManager landingViewManager)
{
_gameSessionManager = gameSessionManager;
_landingViewManager = landingViewManager;
}
public IncomingHeaders Header => IncomingHeaders.GetPromoArticles;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
await gameSession.SendComposerAsync(new PromoArticlesMessageComposer(_landingViewManager.PromoArticles));
}
}

View File

@ -0,0 +1,32 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Navigator;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Rooms;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Navigator;
public class GetUserFlatCatsMessageEvent : IMessageEvent
{
private readonly IGameSessionManager _gameSessionManager;
private readonly IRoomManager _roomManager;
public GetUserFlatCatsMessageEvent(IRoomManager roomManager, IGameSessionManager gameSessionManager)
{
_roomManager = roomManager;
_gameSessionManager = gameSessionManager;
}
public IncomingHeaders Header => IncomingHeaders.GetUserFlatCats;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
await gameSession.SendComposerAsync(new UserFlatCatsComposer(_roomManager.PrivateCategories.Values,
gameSession.Habbo.Rank));
}
}

View File

@ -0,0 +1,32 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Navigator;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Navigator;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Navigator;
public class NavigatorInitEvent : IMessageEvent
{
private readonly IGameSessionManager _gameSessionManager;
private readonly INavigatorManager _navigatorManager;
public NavigatorInitEvent(IGameSessionManager gameSessionManager, INavigatorManager navigatorManager)
{
_gameSessionManager = gameSessionManager;
_navigatorManager = navigatorManager;
}
public IncomingHeaders Header => IncomingHeaders.NavigatorInit;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
await gameSession.SendComposerAsync(new NavigatorMetadataComposer(_navigatorManager.NavigatorViews.Values));
await gameSession.SendComposerAsync(new NavigatorCollapsedComposer());
}
}

View File

@ -0,0 +1,41 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing;
using Tiger.Communication.Messages.Outgoing.Navigator;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Navigator;
using Tiger.Networking.Game.Sessions;
namespace Tiger.Communication.Messages.Incoming.Navigator;
public class NavigatorSearchEvent : IMessageEvent
{
private readonly IGameSessionManager _gameSessionManager;
private readonly INavigatorManager _navigatorManager;
public NavigatorSearchEvent(IGameSessionManager gameSessionManager, INavigatorManager navigatorManager)
{
_gameSessionManager = gameSessionManager;
_navigatorManager = navigatorManager;
}
public IncomingHeaders Header => IncomingHeaders.NavigatorSearch;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
if (!_navigatorManager.NavigatorViews.TryGetValue(request.ReadString(), out var navigatorView)) return;
var qry = request.ReadString();
var message = new ServerMessage((short)OutgoingHeaders.NavigatorSearch);
message.AppendString(navigatorView.Code);
message.AppendString(qry);
await navigatorView.Compose(message, gameSession.Habbo, qry);
await gameSession.SendMessageAsync(message);
// await gameSession.SendComposerAsync(new NavigatorSearchComposer(navigatorView, request.ReadString(), gameSession.Habbo));
}
}

View File

@ -0,0 +1,35 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.User.Data;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
using Tiger.Networking.Game.Sessions;
using Tiger.Storage;
namespace Tiger.Communication.Messages.Incoming.User.Data;
public class UserCurrentBadgesEvent : IMessageEvent
{
private readonly IGameSessionManager _gameSessionManager;
private readonly IRepository<Badge> _badgeRepository;
public UserCurrentBadgesEvent(IGameSessionManager gameSessionManager, IRepository<Badge> badgeRepository)
{
_gameSessionManager = gameSessionManager;
_badgeRepository = badgeRepository;
}
public IncomingHeaders Header => IncomingHeaders.UserBadgesCurrent;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
var habboId = request.ReadInt32();
var badges = await _badgeRepository.FindByAsync(b => b.Habbo.Id == habboId && b.Slot > 0);
await gameSession.SendComposerAsync(new UserCurrentBadgesComposer(habboId, badges.ToList()));
}
}

View File

@ -0,0 +1,53 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.Avatar;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Achievements;
using Tiger.Game.Figuredata;
using Tiger.Game.Habbos;
using Tiger.Networking.Game.Sessions;
using Tiger.Storage;
namespace Tiger.Communication.Messages.Incoming.User.Data;
public class UserFigureEvent : IMessageEvent
{
private readonly IGameSessionManager _gameSessionManager;
private readonly IFigureDataManager _figureDataManager;
private readonly IRepository<Habbo> _habboRepository;
private readonly IAchievementManager _achievementManager;
public UserFigureEvent(IGameSessionManager gameSessionManager, IFigureDataManager figureDataManager, IRepository<Habbo> habboRepository, IAchievementManager achievementManager)
{
_gameSessionManager = gameSessionManager;
_figureDataManager = figureDataManager;
_habboRepository = habboRepository;
_achievementManager = achievementManager;
}
public IncomingHeaders Header => IncomingHeaders.UserFigure;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
if (gameSession.Habbo == null)
{
await _gameSessionManager.CloseAsync("Not logged in", gameSession);
return;
}
var gender = request.ReadString().ToUpper();
var figure = request.ReadString();
if ((gender != "M" && gender != "F") || (figure == gameSession.Habbo.Figure && gender == gameSession.Habbo.Gender.ToUpper()) /*||
!_figureDataManager.ValidateFigure(figure, gender, gameSession.Habbo)*/)
{
return;
}
gameSession.Habbo.Figure = figure;
gameSession.Habbo.Gender = gender;
_habboRepository.SaveAsync(gameSession.Habbo);
_achievementManager.UpdateAchievementAsync("ACH_AvatarLooks", 1, gameSession);
await gameSession.SendComposerAsync(new FigureUpdateComposer(figure, gender));
}
}

View File

@ -0,0 +1,30 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Outgoing.User.Data;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
using Tiger.Networking.Game.Sessions;
using Tiger.Storage;
namespace Tiger.Communication.Messages.Incoming.User.Data;
public class UserProfileEvent : IMessageEvent
{
private readonly IGameSessionManager _gameSessionManager;
private readonly IRepository<Habbo> _habboRepository;
public UserProfileEvent(IGameSessionManager gameSessionManager, IRepository<Habbo> habboRepository)
{
_gameSessionManager = gameSessionManager;
_habboRepository = habboRepository;
}
public IncomingHeaders Header => IncomingHeaders.UserProfile;
public async Task HandleAsync(GameSession gameSession, ClientMessage request)
{
var habbo = await _habboRepository.FindAsync(request.ReadInt32());
if (habbo == null) return;
await gameSession.SendComposerAsync(new UserProfileComposer(habbo));
}
}

View File

@ -27,20 +27,20 @@ public class MessageHandler : IMessageHandler
public async Task TryHandleAsync(GameSession session, ClientMessage request) public async Task TryHandleAsync(GameSession session, ClientMessage request)
{ {
if (request.Header == null) if (request.Header == -1)
{ {
return; return;
} }
if (_messageEvents.TryGetValue(request.Header.Value, out var messageEvent)) if (_messageEvents.TryGetValue(request.Header, out var messageEvent))
{ {
_logger.LogInformation("Handling header ID {Header} on class {Class}", request.Header.Value, messageEvent.GetType()); _logger.LogInformation("Handling header ID {Header} on class {Class}", request.Header, messageEvent.GetType());
await messageEvent.HandleAsync(session, request); await messageEvent.HandleAsync(session, request);
} }
else else
{ {
_logger.LogWarning("Unregistered header {Header} {Name}", request.Header.Value, _messageNames.TryGetValue(request.Header.Value, out var messageName) ? messageName : string.Empty); _logger.LogWarning("Unregistered header {Header} {Name}", request.Header, _messageNames.TryGetValue(request.Header, out var messageName) ? messageName : string.Empty);
} }
} }
} }

View File

@ -0,0 +1,23 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
namespace Tiger.Communication.Messages.Outgoing.Avatar;
public class FigureUpdateComposer : IMessageComposer
{
private readonly string _figure;
private readonly string _gender;
public FigureUpdateComposer(string figure, string gender)
{
_figure = figure;
_gender = gender;
}
public OutgoingHeaders Header => OutgoingHeaders.UserFigure;
public void Compose(ServerMessage message)
{
message.AppendString(_figure);
message.AppendString(_gender);
}
}

View File

@ -0,0 +1,68 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Catalogue;
namespace Tiger.Communication.Messages.Outgoing.Catalog;
public class CatalogPageMessageComposer : IMessageComposer
{
private readonly CataloguePage _page;
private readonly int _offerId;
private readonly string _mode;
private readonly ICollection<CatalogueFeaturedPage> _featuredPages;
public CatalogPageMessageComposer(CataloguePage page, int offerId, string mode,
ICollection<CatalogueFeaturedPage> featuredPages)
{
_page = page;
_offerId = offerId;
_mode = mode;
_featuredPages = featuredPages;
}
public OutgoingHeaders Header => OutgoingHeaders.CatalogPage;
public void Compose(ServerMessage message)
{
message.AppendInt32(_page.Id);
message.AppendString(_mode);
message.AppendString(_page.Layout);
message.AppendInt32(_page.Images.Count);
foreach (var image in _page.Images)
{
message.AppendString(image);
}
message.AppendInt32(_page.Texts.Count);
foreach (var text in _page.Texts)
{
message.AppendString(text);
}
message.AppendInt32(0);
message.AppendInt32(_offerId);
message.AppendBoolean(_page.SeasonalCurrency);
message.AppendInt32(_featuredPages.Count);
foreach (var featuredPage in _featuredPages)
{
message.AppendInt32(featuredPage.SlotId);
message.AppendString(featuredPage.Caption);
message.AppendString(featuredPage.Image);
message.AppendInt32((int)featuredPage.Type);
switch (featuredPage.Type)
{
default:
case CatalogueFeaturedPageType.PageName:
case CatalogueFeaturedPageType.ProductName:
message.AppendString(featuredPage.Data);
break;
case CatalogueFeaturedPageType.PageId:
message.AppendInt32(int.TryParse(featuredPage.Data, out var pageId) ? pageId : -1);
break;
}
message.AppendInt32((int)(DateTime.Now - featuredPage.Expire).TotalSeconds);
}
}
}

View File

@ -0,0 +1,53 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Catalogue;
namespace Tiger.Communication.Messages.Outgoing.Catalog;
public class CatalogPagesListComposer : IMessageComposer
{
private readonly IEnumerable<CataloguePage> _pages;
private readonly string _mode;
public CatalogPagesListComposer(IEnumerable<CataloguePage> pages, string mode)
{
_pages = pages;
_mode = mode;
}
public OutgoingHeaders Header => OutgoingHeaders.CatalogPageList;
public void Compose(ServerMessage message)
{
message.AppendBoolean(true);
message.AppendInt32(0);
message.AppendInt32(-1);
message.AppendString("root");
message.AppendString(string.Empty);
message.AppendInt32(0);
message.AppendInt32(_pages.Count());
foreach (var page in _pages)
{
SerializeNode(page, message);
}
message.AppendBoolean(false);
message.AppendString(_mode);
}
private void SerializeNode(CataloguePage page, ServerMessage message)
{
message.AppendBoolean(page.Visible);
message.AppendInt32(page.Icon);
message.AppendInt32(page.Id);
message.AppendString(page.InternalName);
message.AppendString(page.Name);
message.AppendInt32(0);
message.AppendInt32(page.Children.Count);
foreach (var child in page.Children)
{
SerializeNode(child, message);
}
}
}

View File

@ -0,0 +1,45 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Catalogue;
using Tiger.Game.Habbos;
namespace Tiger.Communication.Messages.Outgoing.Catalog;
public class HabboClubOffersMessageComposer : IMessageComposer
{
private readonly ICollection<ClubOffer> _clubOffers;
private readonly HabboSubscription? _habboSubscription;
public HabboClubOffersMessageComposer(ICollection<ClubOffer> clubOffers, HabboSubscription? habboSubscription)
{
_clubOffers = clubOffers;
_habboSubscription = habboSubscription;
}
public OutgoingHeaders Header => OutgoingHeaders.ClubOffers;
public void Compose(ServerMessage message)
{
message.AppendInt32(_clubOffers.Count);
foreach (var clubOffer in _clubOffers)
{
var end = _habboSubscription is not null
? _habboSubscription.Expires.AddDays(clubOffer.Days)
: DateTime.Now.AddMonths(1);
message.AppendInt32(clubOffer.Id);
message.AppendString(clubOffer.Name);
message.AppendBoolean(false); // does absolutely NOTHING
message.AppendInt32(clubOffer.PriceCredits);
message.AppendInt32(clubOffer.PriceActivitypoints);
message.AppendInt32(clubOffer.ActivitypointsType);
message.AppendBoolean(true); // always vip
message.AppendInt32(0); // months
message.AppendInt32(clubOffer.Days); // extra days
message.AppendBoolean(true); // gift-able
message.AppendInt32(0); // days left after purchase
message.AppendInt32(end.Year);
message.AppendInt32(end.Month);
message.AppendInt32(end.Day);
}
}
}

View File

@ -0,0 +1,26 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
namespace Tiger.Communication.Messages.Outgoing.Catalog;
public class NotEnoughBalanceMessageComposer : IMessageComposer
{
private readonly bool _notEnoughCredits;
private readonly bool _notEnoughActivityPoints;
private readonly int _activityPointsType;
public NotEnoughBalanceMessageComposer(bool notEnoughCredits, bool notEnoughActivityPoints, int activityPointsType)
{
_notEnoughCredits = notEnoughCredits;
_notEnoughActivityPoints = notEnoughActivityPoints;
_activityPointsType = activityPointsType;
}
public OutgoingHeaders Header => OutgoingHeaders.NotEnoughBalance;
public void Compose(ServerMessage message)
{
message.AppendBoolean(_notEnoughCredits);
message.AppendBoolean(_notEnoughActivityPoints);
message.AppendInt32(_activityPointsType);
}
}

View File

@ -0,0 +1,40 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Achievements;
using Tiger.Game.Habbos;
namespace Tiger.Communication.Messages.Outgoing.Inventory.Achievements;
public class AchievementComposer : IMessageComposer
{
private readonly Achievement _achievement;
private readonly HabboAchievement _habboAchievement;
public AchievementComposer(Achievement achievement, HabboAchievement habboAchievement)
{
_achievement = achievement;
_habboAchievement = habboAchievement;
}
public OutgoingHeaders Header => OutgoingHeaders.AchievementProgressed;
public void Compose(ServerMessage message)
{
var targetLevel = _habboAchievement.Level == _achievement.Levels.Count
? _habboAchievement.Level
: _habboAchievement.Level + 1;
message.AppendInt32(_achievement.Id);
message.AppendInt32(targetLevel);
message.AppendString($"{_achievement.Badge}{targetLevel}");
message.AppendInt32(_habboAchievement.Progress);
message.AppendInt32(_achievement.Levels[targetLevel].ProgressNeeded);
message.AppendInt32(_achievement.Levels[targetLevel].RewardAmount);
message.AppendInt32(_achievement.Levels[targetLevel].RewardType);
message.AppendInt32(_habboAchievement.Progress);
message.AppendBoolean(_habboAchievement.Level >= _achievement.Levels.Count);
message.AppendString(_achievement.Category);
message.AppendString(string.Empty);
message.AppendInt32(_achievement.Levels.Count);
message.AppendInt32(_habboAchievement.Level >= _achievement.Levels.Count ? 1 : 0);
}
}

View File

@ -0,0 +1,50 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Achievements;
using Tiger.Game.Habbos;
namespace Tiger.Communication.Messages.Outgoing.Inventory.Achievements;
public class AchievementsComposer : IMessageComposer
{
private readonly ICollection<Achievement> _achievements;
private readonly Habbo _habbo;
public AchievementsComposer(ICollection<Achievement> achievements, Habbo habbo)
{
_achievements = achievements;
_habbo = habbo;
}
public OutgoingHeaders Header => OutgoingHeaders.AchievementList;
public void Compose(ServerMessage message)
{
message.AppendInt32(_achievements.Count);
foreach (var achievement in _achievements)
{
var targetLevel = 1;
if (_habbo.Achievements.TryGetValue(achievement.Id, out var habboAchievement))
targetLevel = habboAchievement.Level == achievement.Levels.Count
? habboAchievement.Level
: habboAchievement.Level + 1;
message.AppendInt32(achievement.Id);
message.AppendInt32(targetLevel);
message.AppendString($"{achievement.Badge}{targetLevel}");
message.AppendInt32(habboAchievement?.Progress ?? 0);
message.AppendInt32(achievement.Levels[targetLevel].ProgressNeeded);
message.AppendInt32(achievement.Levels[targetLevel].RewardAmount);
message.AppendInt32(achievement.Levels[targetLevel].RewardType);
message.AppendInt32(habboAchievement?.Progress ?? 0);
message.AppendBoolean((habboAchievement?.Level ?? 0) >= achievement.Levels.Count);
message.AppendString(achievement.Category);
message.AppendString(string.Empty);
message.AppendInt32(achievement.Levels.Count);
message.AppendInt32((habboAchievement?.Level ?? 0) >= achievement.Levels.Count ? 1 : 0);
}
message.AppendString(string.Empty);
}
}

View File

@ -0,0 +1,20 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
namespace Tiger.Communication.Messages.Outgoing.Inventory.Achievements;
public class AchievementsScoreComposer : IMessageComposer
{
private readonly int _score;
public AchievementsScoreComposer(int score)
{
_score = score;
}
public OutgoingHeaders Header => OutgoingHeaders.UserAchievementScore;
public void Compose(ServerMessage message)
{
message.AppendInt32(_score);
}
}

View File

@ -0,0 +1,37 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
namespace Tiger.Communication.Messages.Outgoing.Inventory.Badges;
public class BadgesComposer : IMessageComposer
{
private readonly IReadOnlyList<Badge> _badges;
public BadgesComposer(IEnumerable<Badge>? badges)
{
_badges = badges != null ? badges.ToList() : new List<Badge>();
}
public OutgoingHeaders Header => OutgoingHeaders.UserBadges;
public void Compose(ServerMessage message)
{
message.AppendInt32(_badges.Count);
foreach (var badge in _badges)
{
message.AppendInt32(badge.Id);
message.AppendString(badge.Code);
}
var wearingBadges = _badges.Where(b => b.Slot > 0).ToList();
message.AppendInt32(wearingBadges.Count);
foreach (var wearingBadge in wearingBadges)
{
message.AppendInt32(wearingBadge.Slot);
message.AppendString(wearingBadge.Code);
}
}
}

View File

@ -0,0 +1,20 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
namespace Tiger.Communication.Messages.Outgoing.Inventory.Currency;
public class UserCreditsComposer : IMessageComposer
{
private readonly int _credits;
public UserCreditsComposer(int credits)
{
_credits = credits;
}
public OutgoingHeaders Header => OutgoingHeaders.UserCredits;
public void Compose(ServerMessage message)
{
message.AppendString($"{_credits}.0");
}
}

View File

@ -0,0 +1,27 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
namespace Tiger.Communication.Messages.Outgoing.Inventory.Currency;
public class UserCurrencyComposer : IMessageComposer
{
private readonly ICollection<Activitypoints> _activitypoints;
public UserCurrencyComposer(ICollection<Activitypoints> activitypoints)
{
_activitypoints = activitypoints;
}
public OutgoingHeaders Header => OutgoingHeaders.UserCurrency;
public void Compose(ServerMessage message)
{
message.AppendInt32(_activitypoints.Count);
foreach (var activitypoint in _activitypoints)
{
message.AppendInt32(activitypoint.Type);
message.AppendInt32(activitypoint.Amount);
}
}
}

View File

@ -0,0 +1,32 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
namespace Tiger.Communication.Messages.Outgoing.Inventory.Subscription;
public class UserSubscriptionComposer : IMessageComposer
{
private readonly HabboSubscription? _habboSubscription;
private readonly int _pastSubscriptionDays;
public UserSubscriptionComposer(HabboSubscription? habboSubscription, int pastSubscriptionDays)
{
_habboSubscription = habboSubscription;
_pastSubscriptionDays = pastSubscriptionDays;
}
public OutgoingHeaders Header => OutgoingHeaders.UserSubscription;
public void Compose(ServerMessage message)
{
message.AppendString(_habboSubscription?.SubscriptionType ?? string.Empty);
message.AppendInt32(_habboSubscription?.DaysInMonthLeft ?? 0);
message.AppendInt32(_habboSubscription?.MonthsLeft ?? 0);
message.AppendInt32(0); // periods subscribed ahead but why is this different than above?
message.AppendInt32(0); // response type
message.AppendBoolean(_pastSubscriptionDays > 0);
message.AppendBoolean(true); // vip but always vip?
message.AppendInt32(0); // past club days but is always vip so below is used
message.AppendInt32(_pastSubscriptionDays);
message.AppendInt32((int)(_habboSubscription?.MinutesLeft ?? 0));
}
}

View File

@ -0,0 +1,32 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.LandingView;
namespace Tiger.Communication.Messages.Outgoing.Landingview;
public class PromoArticlesMessageComposer : IMessageComposer
{
private readonly ICollection<PromoArticle> _promoArticles;
public PromoArticlesMessageComposer(ICollection<PromoArticle> promoArticles)
{
_promoArticles = promoArticles;
}
public OutgoingHeaders Header => OutgoingHeaders.PromoArticles;
public void Compose(ServerMessage message)
{
message.AppendInt32(_promoArticles.Count);
foreach (var promoArticle in _promoArticles)
{
message.AppendInt32(promoArticle.Id);
message.AppendString(promoArticle.Title);
message.AppendString(promoArticle.BodyText);
message.AppendString(promoArticle.ButtonText);
message.AppendInt32((int)promoArticle.LinkType);
message.AppendString(promoArticle.LinkContent);
message.AppendString(promoArticle.ImageUrl);
}
}
}

View File

@ -0,0 +1,14 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
namespace Tiger.Communication.Messages.Outgoing.Navigator;
public class NavigatorCollapsedComposer : IMessageComposer
{
public OutgoingHeaders Header => OutgoingHeaders.NavigatorCollapsed;
public void Compose(ServerMessage message)
{
message.AppendInt32(1);
message.AppendString("official");
}
}

View File

@ -0,0 +1,27 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Navigator.Views;
namespace Tiger.Communication.Messages.Outgoing.Navigator;
public class NavigatorMetadataComposer : IMessageComposer
{
private readonly ICollection<INavigatorView> _navigatorViews;
public NavigatorMetadataComposer(ICollection<INavigatorView> navigatorViews)
{
_navigatorViews = navigatorViews;
}
public OutgoingHeaders Header => OutgoingHeaders.NavigatorMetadata;
public void Compose(ServerMessage message)
{
message.AppendInt32(_navigatorViews.Count);
foreach (var navigatorView in _navigatorViews)
{
message.AppendString(navigatorView.Code);
message.AppendInt32(0); // saved searches
}
}
}

View File

@ -0,0 +1,28 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
using Tiger.Game.Navigator.Views;
namespace Tiger.Communication.Messages.Outgoing.Navigator;
public class NavigatorSearchComposer : IMessageComposer
{
private readonly INavigatorView _navigatorView;
private readonly string _query;
private readonly Habbo _habbo;
public NavigatorSearchComposer(INavigatorView navigatorView, string query, Habbo habbo)
{
_navigatorView = navigatorView;
_query = query;
_habbo = habbo;
}
public OutgoingHeaders Header => OutgoingHeaders.NavigatorSearch;
public void Compose(ServerMessage message)
{
message.AppendString(_navigatorView.Code);
message.AppendString(_query);
_navigatorView.Compose(message, _habbo, _query).Wait();
}
}

View File

@ -0,0 +1,34 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Rooms;
namespace Tiger.Communication.Messages.Outgoing.Navigator;
public class UserFlatCatsComposer : IMessageComposer
{
private readonly ICollection<RoomPrivateCategory> _privateCategories;
private readonly int _rank;
public UserFlatCatsComposer(ICollection<RoomPrivateCategory> privateCategories, int rank)
{
_privateCategories = privateCategories;
_rank = rank;
}
public OutgoingHeaders Header => OutgoingHeaders.NavigatorCategories;
public void Compose(ServerMessage message)
{
message.AppendInt32(_privateCategories.Count);
foreach (var privateCategory in _privateCategories)
{
message.AppendInt32(privateCategory.Id);
message.AppendString(privateCategory.Name);
message.AppendBoolean(privateCategory.MinRank <= _rank);
message.AppendBoolean(true); // automatic?
message.AppendString(""); // automatic category key?
message.AppendString(""); // global category key?
message.AppendBoolean(privateCategory.MinRank >= 4);
}
}
}

View File

@ -0,0 +1,34 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
namespace Tiger.Communication.Messages.Outgoing.Notifications;
public class AchievementNotificationMessageComposer : IMessageComposer
{
private readonly HabboAchievement _habboAchievement;
private readonly int _badgeId;
public AchievementNotificationMessageComposer(HabboAchievement habboAchievement, int badgeId)
{
_habboAchievement = habboAchievement;
_badgeId = badgeId;
}
public OutgoingHeaders Header => OutgoingHeaders.AchievementNotification;
public void Compose(ServerMessage message)
{
message.AppendInt32(_habboAchievement.Achievement.Id);
message.AppendInt32(_habboAchievement.Level);
message.AppendInt32(_badgeId);
message.AppendString($"{_habboAchievement.Achievement.Badge}{_habboAchievement.Level}");
message.AppendInt32(0); // points?
message.AppendInt32(_habboAchievement.Achievement.Levels[_habboAchievement.Level].RewardAmount);
message.AppendInt32(_habboAchievement.Achievement.Levels[_habboAchievement.Level].RewardType);
message.AppendInt32(_habboAchievement.Achievement.Levels[_habboAchievement.Level].Points);
message.AppendInt32(_habboAchievement.Achievement.Id);
message.AppendString(_habboAchievement.Level > 1 ? $"{_habboAchievement.Achievement.Badge}{_habboAchievement.Level - 1}" : string.Empty);
message.AppendString(_habboAchievement.Achievement.Category);
message.AppendBoolean(true);
}
}

View File

@ -0,0 +1,26 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
namespace Tiger.Communication.Messages.Outgoing.Notifications;
public class ActivityPointNotificationMessageComposer : IMessageComposer
{
private readonly int _amount;
private readonly int _amountChanged;
private readonly int _type;
public ActivityPointNotificationMessageComposer(int amount, int amountChanged, int type)
{
_amount = amount;
_amountChanged = amountChanged;
_type = type;
}
public OutgoingHeaders Header => OutgoingHeaders.ActivityPointNotification;
public void Compose(ServerMessage message)
{
message.AppendInt32(_amount);
message.AppendInt32(_amountChanged);
message.AppendInt32(_type);
}
}

View File

@ -1,7 +1,7 @@
using Tiger.Communication.Messages.Interfaces; using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types; using Tiger.Communication.Messages.Types;
namespace Tiger.Communication.Messages.Outgoing.Generic.Alerts; namespace Tiger.Communication.Messages.Outgoing.Notifications;
public class HabboBroadcastMessageComposer : IMessageComposer public class HabboBroadcastMessageComposer : IMessageComposer
{ {
@ -12,7 +12,7 @@ public class HabboBroadcastMessageComposer : IMessageComposer
_welcomeMessage = welcomeMessage; _welcomeMessage = welcomeMessage;
} }
public OutgoingHeaders Header => OutgoingHeaders.HabboBroadcastMessageComposer; public OutgoingHeaders Header => OutgoingHeaders.GenericAlert;
public void Compose(ServerMessage message) public void Compose(ServerMessage message)
{ {
message.AppendString(_welcomeMessage); message.AppendString(_welcomeMessage);

View File

@ -1,507 +1,475 @@
namespace Tiger.Communication.Messages.Outgoing; namespace Tiger.Communication.Messages.Outgoing;
public enum OutgoingHeaders public enum OutgoingHeaders : short
{ {
AcceptFriendResultComposer = 896, AchievementList = 305,
AccountPreferencesComposer = 513, Authenticated = 2491,
AccountSafetyLockStatusChangeMessageComposer = 1243, Authentication = -1,
AchievementComposer = 2107, AvailabilityStatus = 2033,
AchievementResolutionCompletedMessageComposer = 740, BuildersClubExpired = 1452,
AchievementResolutionProgressMessageComposer = 3370, ClubOffers = 2405,
AchievementResolutionsMessageComposer = 66, CatalogPage = 804,
AchievementsComposer = 305, CatalogPageList = 1032,
AchievementsScoreComposer = 1968, CatalogPurchaseOk = 869,
ActivityPointsMessageComposer = 2018, CatalogPurchaseError = 1404,
ApproveNameMessageComposer = 1503, CatalogPurchaseNotAllowed = 3770,
AuthenticationOkMessageComposer = 2491, ProductOffer = 3388,
AvailabilityStatusMessageComposer = 2033, LimitedSoldOut = 377,
AvailabilityTimeMessageComposer = 600, CatalogPublished = 1866,
AvatarEffectActivatedMessageComposer = 1959, CfhResultMessage = 3635,
AvatarEffectAddedMessageComposer = 2867, ClientLatency = 10,
AvatarEffectExpiredMessageComposer = 2228, ClientPing = 3928,
AvatarEffectMessageComposer = 1167, DesktopCampaign = 1745,
AvatarEffectSelectedMessageComposer = 3473, DesktopNews = 286,
AvatarEffectsMessageComposer = 340, DesktopView = 122,
BadgePointLimitsComposer = 2501, BundleDiscountRuleset = 2347,
BadgeReceivedComposer = 2493, FirstLoginOfDay = 793,
BadgesComposer = 717, FurnitureAliases = 1723,
BannedUsersFromRoomComposer = 1869, FurnitureData = 2547,
BonusRareInfoMessageComposer = 1533, FurnitureFloor = 1778,
BotAddedToInventoryComposer = 1352, FurnitureFloorAdd = 1534,
BotCommandConfigurationComposer = 1618, FurnitureFloorRemove = 2703,
BotErrorComposer = 639, FurnitureFloorUpdate = 3776,
BotForceOpenContextMenuComposer = 296, FurnitureItemdata = 2202,
BotInventoryComposer = 3086, FurnitureState = 2376,
BotReceivedMessageComposer = 3684, FurnitureGroupContextMenuInfo = 3293,
BotRemovedFromInventoryComposer = 233, FurniturePostitStickyPoleOpen = 2366,
BotSkillListUpdateComposer = 69, GameCenterAchievements = 2265,
BuildersClubFurniCountMessageComposer = 3828, GameCenterGameList = 222,
BuildersClubSubscriptionStatusMessageComposer = 1452, GameCenterStatus = 2893,
BundleDiscountRulesetMessageComposer = 2347, GameCenterInArenaQueue = 872,
CallForHelpDisabledNotifyMessageComposer = 1651, GameCenterStopCounter = 3191,
CallForHelpPendingCallsDeletedMessageComposer = 77, GameCenterUserLeftGame = 3138,
CallForHelpPendingCallsMessageComposer = 1121, GameCenterDirectoryStatus = 2246,
CallForHelpReplyMessageComposer = 3796, GameCenterStartingGameFailed = 2142,
CallForHelpResultMessageComposer = 3635, GameCenterJoiningFailed = 1730,
CameraPublishStatusMessageComposer = 2057, Gamestatusmessage = 3805,
CameraPurchaseOkMessageComposer = 2783, Gameachievements = 1689,
CameraSnapshotMessageComposer = 463, Gameinvite = 904,
CameraStorageUrlMessageComposer = 3696, Joiningqueuefailed = 3035,
CampaignCalendarDataMessageComposer = 2531, Joinedqueuemessage = 2260,
CampaignCalendarDoorOpenedMessageComposer = 2551, Leftqueue = 1477,
CanCreateRoomComposer = 378, LoadGameUrl = 2624,
CanCreateRoomEventComposer = 2599, Loadgame = 3654,
CantConnectMessageComposer = 899, Unloadgame = 1715,
CarryObjectMessageComposer = 1474, Achievementresolutioncompleted = 740,
CatalogPageExpirationComposer = 2668, Achievementresolutionprogress = 3370,
CatalogPageMessageComposer = 804, Achievementresolutions = 66,
CatalogPagesListComposer = 1032, GenericAlert = 3801,
CatalogPageWithEarliestExpiryMessageComposer = 2515, ModeratorMessage = 2030,
CatalogPublishedMessageComposer = 1866, GenericError = 1600,
CategoriesWithVisitorCountComposer = 1455, GiftWrapperConfig = 2234,
CfhChatlogComposer = 607, GroupBadges = 2402,
CfhSanctionMessageComposer = 2782, GroupCreateOptions = 2159,
CfhTopicsInitComposer = 325, GroupForumData = 3011,
ChangeEmailResultComposer = 1815, GroupForumList = 3001,
ChangeUserNameResultMessageEvent = 118, GroupForumThreads = 1073,
ChatMessageComposer = 1446, GroupForumPost = 2049,
ChatReviewSessionDetachedMessageComposer = 30, GroupForumPostThread = 1862,
ChatReviewSessionOfferedToGuideMessageComposer = 735, GroupForumThreadMessages = 509,
ChatReviewSessionResultsMessageComposer = 3276, GroupForumUnreadCount = 2379,
ChatReviewSessionStartedMessageComposer = 143, GroupForumUpdateMessage = 324,
ChatReviewSessionVotingStatusMessageComposer = 1829, GroupForumUpdateThread = 2528,
CheckUserNameResultMessageComposer = 563, GroupInfo = 1702,
CitizenshipVipOfferPromoEnabledComposer = 2278, GroupList = 420,
CloseConnectionMessageComposer = 122, GroupMember = 265,
ClubGiftInfoComposer = 619, GroupMembers = 1200,
ClubGiftNotificationComposer = 2188, GroupMembersRefresh = 2445,
ClubGiftSelectedComposer = 659, GroupMemberRemoveConfirm = 1876,
CollapsedCategoriesComposer = 1543, GroupPurchased = 2808,
CommunityGoalEarnedPrizesMessageComposer = 3319, GroupSettings = 3965,
CommunityGoalHallOfFameMessageComposer = 3005, GroupBadgeParts = 2238,
CommunityGoalProgressMessageComposer = 2525, GroupMembershipRequested = 1180,
CommunityGoalVoteMessageComposer = 1435, GroupDetailsChanged = 1459,
CompetitionEntrySubmitResultComposer = 1177, GroupHabboJoinFailed = 762,
CompetitionRoomsDataMessageComposer = 3954, GuildEditFailed = 3988,
CompetitionStatusMessageComposer = 133, GuildMemberMgmtFailed = 818,
CompetitionVotingInfoMessageComposer = 3506, ItemDimmerSettings = 2710,
CompleteDiffieHandshakeComposer = 3885, ItemStackHelper = 2816,
ConcurrentUsersGoalProgressMessageComposer = 2737, ItemWall = 1369,
ConfirmBreedingRequestComposer = 634, ItemWallAdd = 2187,
ConfirmBreedingResultComposer = 1625, ItemWallRemove = 3208,
ConvertedRoomIdComposer = 1331, ItemWallUpdate = 2009,
CraftableProductsComposer = 1000, MarketplaceConfig = 1823,
CraftingRecipeComposer = 2774, MessengerAcceptFriends = 896,
CraftingRecipesAvailableComposer = 2124, MessengerChat = 1587,
CraftingResultComposer = 618, MessengerFindFriends = 1210,
CreditBalanceComposer = 3475, MessengerFollowFailed = 3048,
CurrentTimingCodeMessageComposer = 1745, MessengerFriendNotification = 3082,
CustomUserNotificationMessageComposer = 909, MessengerFriends = 3130,
DanceMessageComposer = 2233, MessengerInit = 1605,
DiceValueMessageComposer = 3431, MessengerInstanceMessageError = 3359,
DirectSmsClubBuyAvailableMessageComposer = 195, MessengerInvite = 3870,
DisconnectReasonComposer = 4000, MessengerInviteError = 462,
DoorbellMessageComposer = 2309, MessengerMessageError = 892,
ElementPointerMessageComposer = 1787, MessengerMinimailCount = 2803,
EmailStatusResultComposer = 612, MessengerMinimailNew = 1911,
EpicPopupMessageComposer = 3945, MessengerRelationships = 2016,
ErrorReportComposer = 1004, MessengerRequest = 2219,
ExpressionMessageComposer = 1631, MessengerRequestError = 892,
ExtendedProfileChangedMessageComposer = 876, MessengerRequests = 280,
ExtendedProfileMessageComposer = 3898, MessengerSearch = 973,
FaqCategoriesMessageComposer = 2756, MessengerUpdate = 2800,
FaqCategoryMessageComposer = 2819, ModerationReportDisabled = 1651,
FaqClientFaqsMessageComposer = 2492, ModerationTool = 2696,
FaqSearchResultsMessageComposer = 1551, ModerationUserInfo = 2866,
FaqTextMessageComposer = 3292, MotdMessages = 2035,
FavoriteMembershipUpdateMessageComposer = 3403, NavigatorCategories = 1562,
FavouriteChangedComposer = 2524, NavigatorCollapsed = 1543,
FavouritesComposer = 151, NavigatorEventCategories = 3244,
FigureSetIdsComposer = 1450, NavigatorLifted = 3104,
FigureUpdateComposer = 2429, NavigatorMetadata = 3052,
FindFriendsProcessResultComposer = 1210, NavigatorOpenRoomCreator = 2064,
FlatAccessDeniedMessageComposer = 878, NavigatorSearch = 2690,
FlatAccessibleMessageComposer = 3783, NavigatorSearches = 3984,
FlatControllerAddedComposer = 2088, NavigatorSettings = 518,
FlatControllerRemovedComposer = 1327, ThumbnailUpdateResult = 1927,
FlatControllersComposer = 1284, CanCreateRoom = 378,
FlatCreatedComposer = 1304, CategoriesWithVisitorCount = 1455,
FloodControlMessageComposer = 566, CompetitionRoomsData = 3954,
FloorHeightMapComposer = 1301, ConvertedRoomId = 1331,
FollowFriendFailedComposer = 3048, GuestRoomSearchResult = 52,
ForumDataMessageComposer = 3011, NotificationList = 1992,
ForumsListMessageComposer = 3001, NotificationOfferRewardDelivered = 2125,
FriendFurniCancelLockMessageComposer = 770, NotificationSimpleAlert = 5100,
FriendFurniOtherLockConfirmedMessageComposer = 382, NotificationElementPointer = 1787,
FriendFurniStartConfirmationMessageComposer = 3753, PetFigureUpdate = 1924,
FriendListFragmentMessageComposer = 3130, PetInfo = 2901,
FriendListUpdateComposer = 2800, PetTrainingPanel = 1164,
FriendNotificationComposer = 3082, PetLevelUpdate = 2824,
FriendRequestsComposer = 280, PetScratchFailed = 1130,
FurniListAddOrUpdateComposer = 104, PetOpenPackageRequested = 2380,
FurniListComposer = 994, PetOpenPackageResult = 546,
FurniListInvalidateComposer = 3151, PetBreeding = 1746,
FurniListRemoveComposer = 159, PetConfirmBreedingResult = 1625,
FurniRentOrBuyoutOfferMessageComposer = 35, PetGoToBreedingNestFailure = 2621,
FurnitureAliasesMessageComposer = 1723, PetNestBreedingSuccess = 2527,
Game2AccountGameStatusMessageComposer = 2893, PetConfirmBreedingRequest = 634,
Game2GameDirectoryStatusMessageComposer = 2246, PetBreedingResult = 1553,
Game2InArenaQueueMessageComposer = 872, RecyclerPrizes = 3164,
Game2JoiningGameFailedMessageComposer = 1730, RecyclerStatus = 3433,
Game2StopCounterMessageComposer = 2233, RecyclerFinished = 468,
Game2UserLeftGameMessageComposer = 2383, RoomBanList = 1869,
Game2WeeklyFriendsLeaderboardComposer = 2270, RoomBanRemove = 3429,
Game2WeeklyLeaderboardComposer = 2196, RoomCreated = 1304,
GameAchievementsMessageComposer = 1689, RoomDoorbell = 2309,
GameInviteMessageComposer = 904, RoomDoorbellAccepted = 3783,
GameListMessageComposer = 222, RoomDoorbellRejected = 878,
GamePlayerValueMessageComposer = 2324, RoomEnter = 758,
GameStatusMessageComposer = 3805, RoomEnterError = 899,
GenericErrorComposer = 1600, RoomForward = 160,
GetGuestRoomResultComposer = 687, RoomHeightMap = 2753,
GiftReceiverNotFoundComposer = 1517, RoomHeightMapUpdate = 558,
GiftWrappingConfigurationComposer = 2234, RoomInfo = 687,
GotMysteryBoxPrizeMessageComposer = 3712, RoomInfoOwner = 749,
GoToBreedingNestFailureComposer = 2621, RoomModel = 1301,
GroupDetailsChangedMessageComposer = 1459, RoomModelBlockedTiles = 3990,
GroupMembershipRequestedMessageComposer = 1180, RoomModelDoor = 1664,
GuestRoomSearchResultComposer = 52, RoomModelName = 2031,
GuideOnDutyStatusMessageComposer = 1548, RoomMuted = 2533,
GuideReportingStatusMessageComposer = 3463, RoomMuteUser = 826,
GuideSessionAttachedMessageComposer = 1591, RoomPaint = 2454,
GuideSessionDetachedMessageComposer = 138, RoomPromotion = 2274,
GuideSessionEndedMessageComposer = 1456, RoomQueueStatus = 2208,
GuideSessionErrorMessageComposer = 673, RoomRights = 780,
GuideSessionInvitedToGuideRoomMessageComposer = 219, RoomRightsClear = 2392,
GuideSessionMessageMessageComposer = 841, RoomRightsList = 1284,
GuideSessionPartnerIsTypingComposer = 1016, RoomRightsListAdd = 2088,
GuideSessionRequesterRoomMessageComposer = 1847, RoomRightsListRemove = 1327,
GuideSessionStartedComposer = 3209, RoomRightsOwner = 339,
GuideTicketCreationResultMessageComposer = 3285, RoomRolling = 3207,
GuideTicketResolutionMessageComposer = 2674, RoomScore = 482,
GuildCreatedMessageComposer = 2808, RoomSettings = 1498,
GuildCreationInfoMessageComposer = 2159, RoomSettingsChat = 1191,
GuildEditFailedMessageComposer = 3988, RoomSettingsSave = 948,
GuildEditInfoMessageComposer = 3965, RoomSettingsSaveError = 1555,
GuildEditorDataMessageComposer = 2238, RoomInfoUpdated = 3297,
GuildForumThreadsComposer = 1073, RoomSpectator = 1033,
GuildFurniContextMenuInfoMessageComposer = 3293, RoomThickness = 3547,
GuildMemberFurniCountInHqMessageComposer = 1876, RoomGetFilterWords = 2937,
GuildMemberMgmtFailedMessageComposer = 818, RoomMessageNotification = 1634,
GuildMembersComposer = 1200, RoomPopularTagsResult = 2012,
GuildMembershipRejectedMessageComposer = 2445, InfoFeedEnable = 3284,
GuildMembershipsMessageComposer = 420, SecurityMachine = 1488,
GuildMembershipUpdatedMessageComposer = 265, MysteryBoxKeys = 2833,
HabboAchievementNotificationMessageComposer = 806, Gotmysteryboxprizemessage = 3712,
HabboActivityPointNotificationMessageComposer = 2275, Cancelmysteryboxwaitmessage = 596,
HabboBroadcastMessageComposer = 3801, Showmysteryboxwaitmessage = 3201,
HabboClubExtendOfferMessageComposer = 3964, TradeAccepted = 2568,
HabboClubOffersMessageComposer = 2405, TradeClosed = 1373,
HabboGroupBadgesMessageComposer = 2402, TradeCompleted = 1001,
HabboGroupDeactivatedMessageComposer = 3129, TradeConfirmation = 2720,
HabboGroupDetailsMessageComposer = 1702, TradeListItem = 2024,
HabboGroupJoinFailedMessageComposer = 762, TradeNotOpen = 3128,
HabboSearchResultComposer = 973, TradeOpen = 2505,
HabboWayQuizComposer1 = 3379, TradeOpenFailed = 217,
HandItemReceivedMessageComposer = 354, TradeOtherNotAllowed = 1254,
HeightMapComposer = 2753, TradeYouNotAllowed = 3058,
HeightMapUpdateMessageComposer = 558, TradeNoSuchItem = 2873,
HotelClosedAndOpensComposer = 3728, Unit = 374,
HotelClosesAndWillOpenAtComposer = 2771, UnitChangeName = 2182,
HotelMergeNameChangeComposer = 1663, UnitChat = 1446,
HotelViewCatalogPageExpiringComposer = 690, UnitChatShout = 1036,
HotelViewCustomTimerComposer = -1, UnitChatWhisper = 2704,
HotelWillCloseInMinutesComposer = 1050, UnitDance = 2233,
IdentityAccountsComposer = 3523, UnitEffect = 1167,
IgnoredUsersMessageComposer = 126, UnitExpression = 1631,
IgnoreResultMessageComposer = 207, UnitHandItem = 1474,
InClientLinkMessageComposer = 2023, UnitIdle = 1797,
InfoFeedEnableMessageComposer = 3284, UnitInfo = 3920,
InitCameraMessageComposer = 3878, UnitNumber = 2324,
InitDiffieHandshakeComposer = 1347, UnitRemove = 2661,
InstantMessageErrorComposer = 3359, UnitStatus = 1640,
InterstitialMessageComposer = 1808, UnitTyping = 1717,
IsBadgeRequestFulfilledComposer = 2998, UnseenItems = 2103,
IsFirstLoginOfDayComposer = 793, UserAchievementScore = 1968,
IsOfferGiftableMessageComposer = 761, UserBadges = 717,
IssueCloseNotificationMessageComposer = 934, UserBadgesAdd = 2493,
IssueDeletedMessageComposer = 3192, UserBadgesCurrent = 1087,
IssueInfoMessageComposer = 3609, UserBotRemove = 233,
IssuePickFailedMessageComposer = 3150, UserBots = 3086,
IsUserPartOfCompetitionMessageComposer = 3841, UserChangeName = 118,
ItemAddMessageComposer = 2187, UserClothing = 1450,
ItemDataUpdateMessageComposer = 2202, UserCredits = 3475,
ItemRemoveMessageComposer = 3208, UserCurrency = 2018,
ItemsComposer = 1369, ActivityPointNotification = 2275,
ItemUpdateMessageComposer = 2009, UserEffects = 340,
JoinedQueueMessageComposer = 2260, UserFavoriteRoom = 2524,
JoiningQueueFailedMessageComposer = 3035, UserFavoriteRoomCount = 151,
JukeBoxPlaylistFullMessageComposer = 105, UserFigure = 2429,
JukeboxSongDisksMessageComposer = 34, UserFurniture = 994,
LatencyPingResponseMessageComposer = 10, UserFurnitureAdd = 104,
LeftQueueMessageComposer = 1477, UserFurniturePostitPlaced = 1501,
LimitedEditionSoldOutComposer = 377, UserFurnitureRefresh = 3151,
LimitedOfferAppearingNextMessageComposer = 44, UserFurnitureRemove = 159,
LoadGameMessageComposer = 3654, UserHomeRoom = 2875,
LoadGameUrlMessageComposer = 2624, RoomEventCancel = 3479,
MaintenanceStatusMessageComposer = 1350, RoomEvent = 1840,
MarketplaceBuyOfferResultComposer = 2032, UserIgnored = 126,
MarketplaceCancelOfferResultComposer = 3264, UserIgnoredResult = 207,
MarketplaceCanMakeOfferResult = 54, UserInfo = 2725,
MarketplaceConfigurationComposer = 1823, UserOutfits = 3315,
MarketplaceItemStatsComposer = 725, UserPerks = 2586,
MarketplaceMakeOfferResult = 1359, UserPermissions = 411,
MarketplaceOffersComposer = 680, UserPetAdd = 2101,
MarketPlaceOwnOffersComposer = 3884, UserPetRemove = 3253,
MessengerErrorComposer = 892, UserPets = 3522,
MessengerInitComposer = 1605, UserProfile = 3898,
MiniMailNewMessageComposer = 1911, UserRespect = 2815,
MiniMailUnreadCountComposer = 2803, UserSanctionStatus = 3679,
ModeratorActionResultMessageComposer = 2335, UserSettings = 513,
ModeratorCautionComposer = 1890, UserSubscription = 954,
ModeratorInitMessageComposer = 2696, UserWardrobePage = 3315,
ModeratorMessageComposer = 2030, UserClassification = 966,
ModeratorRoomInfoComposer = 1333, GetUserTags = 1255,
ModeratorToolPreferencesComposer = 1576, WiredAction = 1434,
ModeratorUserInfoComposer = 2866, WiredCondition = 1108,
MOtdNotificationComposer = 2035, WiredError = 156,
MuteAllInRoomComposer = 2533, WiredOpen = 1830,
MysteryBoxClosingComposer = 596, WiredReward = 178,
MysteryBoxKeysMessageComposer = 2833, WiredSave = 1155,
MysteryBoxStartComposer = 3201, WiredTrigger = 383,
NavigatorLiftedRoomsComposer = 3104, PlayingGame = 448,
NavigatorMetaDataComposer = 3052, FurnitureState2 = 3431,
NavigatorSavedSearchesComposer = 3984, RemoveBotFromInventory = 233,
NavigatorSearchResultBlocksComposer = 2690, AddBotToInventory = 1352,
NavigatorSettingsComposer = 2875, AchievementProgressed = 2107,
NestBreedingSuccessComposer = 2527, ModtoolRoomInfo = 1333,
NewConsoleMessageComposer = 1587, ModtoolUserChatlog = 3377,
NewFriendRequestComposer = 2219, ModtoolRoomChatlog = 3434,
NewNavigatorPreferencesComposer = 518, ModtoolVisitedRoomsUser = 1752,
NewUserExperienceGiftOfferComposer = 3575, ModeratorActionResult = 2335,
NewUserExperienceNotCompleteComposer = 3639, IssueDeleted = 3192,
NoobnessLevelMessageComposer = 3738, IssueInfo = 3609,
NoOwnedRoomsAlertMessageComposer = 2064, IssuePickFailed = 3150,
NoSuchFlatComposer = 84, CfhChatlog = 607,
NotEnoughBalanceMessageComposer = 3914, ModeratorToolPreferences = 1576,
NotificationDialogMessageComposer = 1992, LovelockFurniStart = 3753,
NowPlayingMessageComposer = 469, LovelockFurniFriendComfirmed = 382,
ObjectAddMessageComposer = 1534, LovelockFurniFinished = 770,
ObjectDataUpdateMessageComposer = 2547, GiftReceiverNotFound = 1517,
ObjectRemoveMessageComposer = 2703, GiftOpened = 56,
ObjectsDataUpdateMessageComposer = 1453, FloodControl = 566,
ObjectsMessageComposer = 1778, RemainingMute = 826,
ObjectUpdateMessageComposer = 3776, UserEffectList = 340,
OfferRewardDeliveredMessageComposer = 2125, UserEffectListAdd = 2867,
OfficialRoomsComposer = 2726, UserEffectListRemove = 2228,
OfficialSongIdMessageComposer = 1381, UserEffectActivate = 1959,
OneWayDoorStatusMessageComposer = 2376, AvatarEffectSelected = 3473,
OpenComposer = 1830, ClubGiftInfo = 619,
OpenConnectionMessageComposer = 758, RedeemVoucherError = 714,
OpenPetPackageRequestedMessageComposer = 2380, RedeemVoucherOk = 3336,
OpenPetPackageResultMessageComposer = 546, InClientLink = 2023,
PerkAllowancesComposer = 2586, BotCommandConfiguration = 1618,
PetAddedToInventoryComposer = 2101, BotSkillListUpdate = 69,
PetBreedingComposer = 1746, BotForceOpenContextMenu = 296,
PetBreedingResultComposer = 1553, HandItemReceived = 354,
PetExperienceComposer = 2156, PetPlacingError = 2913,
PetFigureUpdateComposer = 1924, BotError = 639,
PetInfoMessageComposer = 2901, MarketplaceSellItem = 54,
PetInventoryComposer = 3522, MarketplaceItemStats = 725,
PetLevelNotificationComposer = 859, MarketplaceOwnItems = 3884,
PetLevelUpdateComposer = 2824, MarketplaceCancelSale = 3264,
PetPlacingErrorComposer = 2913, MarketplaceItemPosted = 1359,
PetReceivedMessageComposer = 1111, MarketplaceItemsSearched = 680,
PetRemovedFromInventoryComposer = 3253, MarketplaceAfterOrderStatus = 2032,
PetRespectFailedComposer = 1130, CatalogReceivePetBreeds = 3331,
PetRespectNotificationComposer = 2788, CatalogApproveNameResult = 1503,
PetStatusUpdateComposer = 1907, ObjectsDataUpdate = 1453,
PetSupplementedNotificationComposer = 3441, PetExperience = 2156,
PetTrainingPanelComposer = 1164, CommunityGoalVoteEvent = 1435,
PhoneCollectionStateMessageComposer = 2890, PromoArticles = 286,
PingMessageComposer = 3928, CommunityGoalEarnedPrizes = 3319,
PlayListMessageComposer = 1748, CommunityGoalProgress = 2525,
PlayListSongAddedMessageComposer = 1140, ConcurrentUsersGoalProgress = 2737,
PollContentsComposer = 2997, QuestDaily = 1878,
PollErrorComposer = 662, QuestCancelled = 3027,
PollOfferComposer = 3785, QuestCompleted = 949,
PopularRoomTagsResultComposer = 2012, CommunityGoalHallOfFame = 3005,
PostItPlacedComposer = 1501, EpicPopup = 3945,
PostMessageMessageComposer = 2049, SeasonalQuests = 1122,
PostThreadMessageComposer = 1862, Quests = 3625,
PresentOpenedMessageComposer = 56, Quest = 230,
ProductOfferComposer = 3388, BonusRareInfo = 1533,
PromoArticlesMessageComposer = 286, CraftableProducts = 1000,
PurchaseErrorMessageComposer = 1404, CraftingRecipe = 2774,
PurchaseNotAllowedMessageComposer = 3770, CraftingRecipesAvailable = 2124,
PurchaseOkMessageComposer = 869, CraftingResult = 618,
QuestCancelledMessageComposer = 3027, CameraPublishStatus = 2057,
QuestCompletedMessageComposer = 949, CameraPurchaseOk = 2783,
QuestDailyMessageComposer = 1878, CameraStorageUrl = 3696,
QuestionAnsweredComposer = 2589, CameraSnapshot = 463,
QuestionComposer = 2665, CompetitionStatus = 133,
QuestionFinishedComposer = 1066, InitCamera = 3878,
QuestionInfoComposer = -1, ThumbnailStatus = 3595,
QuestMessageComposer = 230, AchievementNotification = 806,
QuestsMessageComposer = 3625, ClubGiftNotification = 2188,
QuizDataMessageComposer = 2927, InterstitialMessage = 1808,
QuizResultsMessageComposer = 2772, RoomAdError = 1759,
RecyclerFinishedComposer = 468, AvailabilityTime = 600,
RecyclerPrizesComposer = 3164, HotelClosedAndOpens = 3728,
RecyclerStatusComposer = 3433, HotelClosesAndOpensAt = 2771,
RelationshipStatusInfoComposer = 2016, HotelWillCloseMinutes = 1050,
RemainingMutePeriodComposer = 826, HotelMaintenance = 1350,
RentableSpaceRentFailedMessageComposer = 1868, JukeboxPlaylistFull = 105,
RentableSpaceRentOkMessageComposer = 2046, JukeboxSongDisks = 34,
RentableSpaceStatusMessageComposer = 3559, NowPlaying = 469,
RequestSpamWallPostItMessageComposer = 2366, OfficialSongId = 1381,
RestoreClientMessageComposer = 426, Playlist = 1748,
RoomAdErrorComposer = 1759, PlaylistSongAdded = 1140,
RoomAdPurchaseInfoComposer = 2468, TraxSongInfo = 3365,
RoomChatlogComposer = 3434, UserSongDisksInventory = 2602,
RoomChatSettingsMessageComposer = 1191, CheckUserName = 563,
RoomDimmerPresetsComposer = 2710, CfhSanction = 2782,
RoomEntryInfoComposer = -1, CfhTopics = 325,
RoomEntryInfoMessageComposer = 749, CfhSanctionStatus = 2221,
RoomEntryTileMessageComposer = 1664, CampaignCalendarData = 2531,
RoomEventCancelComposer = 3479, CampaignCalendarDoorOpened = 2551,
RoomEventComposer = 1840, BuildersClubFurniCount = 3828,
RoomFilterSettingsMessageComposer = 2937, BuildersClubSubscription = 1452,
RoomFloorThicknessUpdatedComposer = 3786, CatalogPageExpiration = 2668,
RoomForwardMessageComposer = 160, CatalogEarliestExpiry = 2515,
RoomInfoUpdatedComposer = 3297, ClubGiftSelected = 659,
RoomInviteComposer = 3870, TargetOfferNotFound = 1237,
RoomInviteErrorComposer = 462, TargetOffer = 119,
RoomMessageNotificationMessageComposer = 1634, DirectSmsClubBuy = 195,
RoomOccupiedTilesMessageComposer = 3990, RoomAdPurchase = 2468,
RoomPropertyMessageComposer = 2454, NotEnoughBalance = 3914,
RoomQueueStatusMessageComposer = 2208, LimitedOfferAppearingNext = 44,
RoomRatingComposer = 482, IsOfferGiftable = 761,
RoomReadyMessageComposer = 2031, ClubExtendedOffer = 3964,
RoomSettingsDataComposer = 1498, SeasonalCalendarOffer = 1889,
RoomSettingsErrorComposer = 2897, CompetitionEntrySubmit = 1177,
RoomSettingsSavedComposer = 948, CompetitionVotingInfo = 3506,
RoomSettingsSaveErrorComposer = 1555, CompetitionTimingCode = 1745,
RoomThumbnailUpdateResultComposer = 1927, CompetitionUserPartOf = 3841,
RoomUserQuestionAnsweredComposer = -1, CompetitionNoOwnedRooms = 2064,
RoomUserRespectComposer = 2815, CompetitionSecondsUntil = 3926,
RoomVisitsComposer = 1752, BadgePointLimits = 2501,
RoomVisualizationSettingsComposer = 3547, BadgeRequestFulfilled = 2998,
SanctionStatusComposer = 2221, HelperTalentTrack = 3406,
ScrSendKickbackInfoMessageComposer = 3277, TalentTrackLevel = 1203,
ScrSendUserInfoComposer = 954, TalentTrackLevelUp = 638,
SeasonalCalendarDailyOfferMessageComposer = 1889, UserBanned = 1683,
SeasonalQuestsMessageComposer = 1122, BotReceived = 3684,
SecondsUntilMessageComposer = 3926, PetLevelNotification = 859,
SellablePetPalettesMessageComposer = 3331, PetReceived = 1111,
ShoutMessageComposer = 1036, ModerationCaution = 1890,
ShowEnforceRoomCategoryDialogComposer = 3896, YoutubeControlVideo = 1554,
SleepMessageComposer = 1797, YoutubeDisplayPlaylists = 1112,
SlideObjectBundleMessageComposer = 3207, YoutubeDisplayVideo = 1411,
Str16258Composer = 1660, CfhDisabledNotify = 1651,
Str16667Composer = 3099, Question = 2665,
Str17054Composer = 416, PollContents = 2997,
TalentLevelUpComposer = 638, PollError = 662,
TalentTrackLevelMessageEvent = 1203, PollOffer = 3785,
TalentTrackMessageComposer = 3406, PollRoomResult = 5201,
TargetedOfferComposer = 119, PollStartRoom = 5200,
TargetedOfferNotFoundComposer = 1237, QuestionAnswered = 2589,
ThreadMessagesMessageComposer = 509, QuestionFinished = 1066,
ThumbnailStatusMessageComposer = 3595, CfhPendingCalls = 1121,
TradeCloseWindowComposer = 1001, GuideOnDutyStatus = 1548,
TradeCompleteComposer = 2369, GuideSessionAttached = 1591,
TradingAcceptComposer = 2568, GuideSessionDetached = 138,
TradingCloseComposer = 1373, GuideSessionEnded = 1456,
TradingConfirmationComposer = 2720, GuideSessionError = 673,
TradingItemListComposer = 2024, GuideSessionInvitedToGuideRoom = 219,
TradingNoSuchItemComposer = 2873, GuideSessionMessage = 841,
TradingNotOpenComposer = 3128, GuideSessionPartnerIsTyping = 1016,
TradingOpenComposer = 2505, GuideSessionRequesterRoom = 1847,
TradingOpenFailedComposer = 217, GuideSessionStarted = 3209,
TradingOtherNotAllowedComposer = 1254, GuideTicketCreationResult = 3285,
TradingYouAreNotAllowedComposer = 3058, GuideTicketResolution = 2674,
TraxSongInfoMessageComposer = 3365, GuideReportingStatus = 3463,
TryPhoneNumberResultMessageComposer = 800, HotelMergeNameChange = 1663,
TryVerificationCodeResultMessageComposer = 91, IssueCloseNotification = 934,
UniqueMachineIdComposer = 1488, QuizData = 2927,
Unknowncomposer1188 = 1437, QuizResults = 2772,
UnloadGameMessageComposer = 1715, CfhPendingCallsDeleted = 77,
UnreadForumsCountMessageComposer = 2379, CfhReply = 3796,
UnseenItemsComposer = 2103, ChatReviewSessionDetached = 30,
UpdateMessageMessageComposer = 324, ChatReviewSessionOfferedToGuide = 735,
UpdateStackHeightTileHeightComposer = 2816, ChatReviewSessionResults = 3276,
UpdateThreadMessageComposer = 2528, ChatReviewSessionStarted = 143,
UseObjectMessageComposer = 1774, ChatReviewSessionVotingStatus = 1829,
UserBadgesComposer = 1087, ScrSendKickbackInfo = 3277,
UserBannedMessageComposer = 1683, PetStatus = 1907,
UserBcLimitsComposer = -1, GroupDeactivate = 3129,
UserChangeMessageComposer = 3920, PetRespected = 2788,
UserChatlogComposer = 3377, PetSupplement = 3441,
UserClassificationMessageComposer = 966, NoobnessLevel = 3738,
UserEventCatsComposer = 3244, DisconnectReason = 4000,
UserFlatCatsComposer = 1562, CanCreateRoomEvent = 2599,
UserGameAchievementsMessageComposer = 2265, FavoriteGroupUdpate = 3403,
UserNameChangedMessageComposer = 2182, NoSuchFlat = 84,
UserObjectComposer = 2725, RoomSettingsError = 2897,
UserRemoveMessageComposer = 2661, ShowEnforceRoomCategory = 3896,
UserRightsMessageComposer = 411, CustomUserNotification = 909,
UsersComposer = 374, NewUserExperienceGiftOffer = 3575,
UserSongDisksInventoryMessageComposer = 2602, RestoreClient = 426,
UserTagsMessageComposer = 1255, FireworkChargeData = 5210,
UserTypingMessageComposer = 1717, NewUserExperienceNotComplete = 3639,
UserUnbannedFromRoomComposer = 3429, ConnectionError = 1004,
UserUpdateComposer = 1640, AccountSafetyLockStatusChange = 1243,
VoucherRedeemErrorMessageComposer = 714, PhoneCollectionState = 2890,
VoucherRedeemOkMessageComposer = 3336, PhoneTryNumberResult = 800,
WardrobeMessageComposer = 3315, PhoneTryVerificationCodeResult = 91,
WeeklyCompetitiveFriendsLeaderboardComposer = 3560, ExtendedProfileChanged = 876,
WeeklyCompetitiveLeaderboardComposer = 3512, WelcomeGiftChangeEmailResult = 2293,
WeeklyGameRewardComposer = 2641, WelcomeGiftStatus = 2707,
WeeklyGameRewardWinnersComposer = 3097, HandshakeInitDiffie = 1347,
WelcomeGiftChangeEmailResultComposer = 2293, HandshakeCompleteDiffie = 3885,
WelcomeGiftStatusComposer = 2707, RentableSpaceRentOk = 2046,
WhisperMessageComposer = 2704, RentableSpaceStatus = 3559,
WiredConditionDataComposer = 1108, RentableSpaceRentFailed = 1868,
WiredEffectDataComposer = 1434, EmailStatus = 612,
WiredRewardResultMessageComposer = 178, ChangeEmailResult = 1815,
WiredSavedComposer = 1155, WeeklyGameReward = 2641,
WiredTriggerDataComposer = 383, WeeklyGameRewardWinners = 3097,
WiredValidationErrorComposer = 156, WeeklyCompetitiveLeaderboard = 3512,
YouAreControllerMessageComposer = 780, WeeklyCompetitiveFriendsLeaderboard = 3560,
YouAreNotControllerMessageComposer = 2392, WeeklyGame2FriendsLeaderboard = 2270,
YouAreOwnerMessageComposer = 339, WeeklyGame2Leaderboard = 2196,
YouArePlayingGameMessageComposer = 448, RentableFurniRentOrBuyoutOffer = 35,
YouAreSpectatorMessageEvent = 1033, HandshakeIdentityAccount = 3523,
YoutubeControlVideoMessageComposer = 1554,
YoutubeDisplayPlaylistsComposer = 1112,
YoutubeDisplayVideoMessageComposer = 1411,
SnowStormGameStartedComposer = 5000,
SnowStormQuePositionComposer = 5001,
SnowStormStartBlockTickerComposer = 5002,
SnowStormStartLobbyCounterComposer = 5003,
SnowStormUnusedAlertGenericComposer = 5004,
SnowStormLongDataComposer = 5005,
SnowStormGameEndedComposer = 5006,
SnowStormQuePlayerAddedComposer = 5008,
SnowStormPlayAgainComposer = 5009,
SnowStormGamesLeftComposer = 5010,
SnowStormQuePlayerRemovedComposer = 5011,
SnowStormGamesInformationComposer = 5012,
SnowStormLongData2Composer = 5013,
UnusedSnowstorm5014 = 5014,
SnowStormGameStatusComposer = 5015,
SnowStormFullGameStatusComposer = 5016,
SnowStormOnStageStartComposer = 5017,
SnowStormIntializeGameArenaViewComposer = 5018,
SnowStormRejoinPreviousRoomComposer = 5019,
UnknownSnowstorm5020 = 5020,
SnowStormLevelDataComposer = 5021,
SnowStormOnGameEndingComposer = 5022,
SnowStormUserChatMessageComposer = 5023,
SnowStormOnStageRunningComposer = 5024,
SnowStormOnStageEndingComposer = 5025,
SnowStormIntializedPlayersComposer = 5026,
SnowStormOnPlayerExitedArenaComposer = 5027,
SnowStormGenericErrorComposer = 5028,
SnowStormUserRematchedComposer = 5029
} }

View File

@ -1,11 +1,11 @@
using Tiger.Communication.Messages.Interfaces; using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types; using Tiger.Communication.Messages.Types;
namespace Tiger.Communication.Messages.Outgoing.Handshake; namespace Tiger.Communication.Messages.Outgoing.Security;
public class AuthenticationOkMessageComposer : IMessageComposer public class AuthenticatedComposer : IMessageComposer
{ {
public OutgoingHeaders Header => OutgoingHeaders.AuthenticationOkMessageComposer; public OutgoingHeaders Header => OutgoingHeaders.Authenticated;
public void Compose(ServerMessage message) public void Compose(ServerMessage message)
{ {

View File

@ -0,0 +1,30 @@
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
namespace Tiger.Communication.Messages.Outgoing.User.Data;
public class UserCurrentBadgesComposer : IMessageComposer
{
private readonly int _habboId;
private readonly ICollection<Badge> _badges;
public UserCurrentBadgesComposer(int habboId, ICollection<Badge> badges)
{
_habboId = habboId;
_badges = badges;
}
public OutgoingHeaders Header => OutgoingHeaders.UserBadgesCurrent;
public void Compose(ServerMessage message)
{
message.AppendInt32(_habboId);
message.AppendInt32(_badges.Count);
foreach (var badge in _badges)
{
message.AppendInt32(badge.Slot);
message.AppendString(badge.Code);
}
}
}

View File

@ -3,21 +3,21 @@ using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types; using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos; using Tiger.Game.Habbos;
namespace Tiger.Communication.Messages.Outgoing.Handshake; namespace Tiger.Communication.Messages.Outgoing.User.Data;
public class UserObjectMessageComposer : IMessageComposer public class UserInfoComposer : IMessageComposer
{ {
private readonly Habbo _habbo; private readonly Habbo _habbo;
public UserObjectMessageComposer(Habbo habbo) public UserInfoComposer(Habbo habbo)
{ {
_habbo = habbo; _habbo = habbo;
} }
public OutgoingHeaders Header => OutgoingHeaders.UserObjectComposer; public OutgoingHeaders Header => OutgoingHeaders.UserInfo;
public void Compose(ServerMessage message) public void Compose(ServerMessage message)
{ {
message.AppendUInt32(_habbo.Id); message.AppendInt32(_habbo.Id);
message.AppendString(_habbo.Username); message.AppendString(_habbo.Username);
message.AppendString(_habbo.Figure); message.AppendString(_habbo.Figure);
message.AppendString(_habbo.Gender); message.AppendString(_habbo.Gender);

View File

@ -0,0 +1,34 @@
using System.Globalization;
using Tiger.Communication.Messages.Interfaces;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
namespace Tiger.Communication.Messages.Outgoing.User.Data;
public class UserProfileComposer : IMessageComposer
{
private readonly Habbo _habbo;
public UserProfileComposer(Habbo habbo)
{
_habbo = habbo;
}
public OutgoingHeaders Header => OutgoingHeaders.UserProfile;
public void Compose(ServerMessage message)
{
message.AppendInt32(_habbo.Id);
message.AppendString(_habbo.Username);
message.AppendString(_habbo.Figure);
message.AppendString(_habbo.Motto);
message.AppendString(_habbo.AccountCreated.ToString(CultureInfo.CurrentCulture));
message.AppendInt32(_habbo.AchievementScore);
message.AppendInt32(0); // friend count
message.AppendBoolean(false); // is friend
message.AppendBoolean(false); // friend request sent
message.AppendBoolean(_habbo.Online);
message.AppendInt32(0); // groups
message.AppendInt32((int)(_habbo.LastLogin == null ? 0 : (DateTime.Now - _habbo.LastLogin.Value).TotalSeconds));
message.AppendBoolean(true); // open but why would it not open?
}
}

View File

@ -8,7 +8,7 @@ public class ClientMessage
private readonly byte[] _packet; private readonly byte[] _packet;
private int _readerIndex; private int _readerIndex;
public short? Header { get; } public short Header { get; }
public ClientMessage(byte[] packet) public ClientMessage(byte[] packet)
{ {
@ -17,42 +17,42 @@ public class ClientMessage
Header = ReadInt16(); Header = ReadInt16();
} }
public short? ReadInt16() public short ReadInt16()
{ {
var raw = ReadBytes(2); var raw = ReadBytes(2);
if (raw.Length != 2) return null; if (raw.Length != 2) return -1;
return ByteUtils.GetInt16(raw); return ByteUtils.GetInt16(raw);
} }
public int? ReadInt32() public int ReadInt32()
{ {
var raw = ReadBytes(4); var raw = ReadBytes(4);
if (raw.Length != 4) return null; if (raw.Length != 4) return -1;
return ByteUtils.GetInt32(raw); return ByteUtils.GetInt32(raw);
} }
public bool? ReadBoolean() public bool ReadBoolean()
{ {
if (_packet.Length - _readerIndex == 0) return null; if (_packet.Length - _readerIndex == 0) return false;
var result = _packet[_readerIndex]; var result = _packet[_readerIndex];
_readerIndex++; _readerIndex++;
return result == 1; return result == 1;
} }
public string? ReadString() public string ReadString()
{ {
var strlen = ReadInt16(); var strlen = ReadInt16();
if (strlen == null) return null; if (strlen == -1) return string.Empty;
var raw = ReadBytes(strlen.Value); var raw = ReadBytes(strlen);
return raw.Length != strlen ? null : Encoding.UTF8.GetString(raw); return raw.Length != strlen ? string.Empty : Encoding.UTF8.GetString(raw);
} }
private byte[] ReadBytes(int amount) private byte[] ReadBytes(int amount)

View File

@ -22,11 +22,6 @@ public class ServerMessage
_packet.AddRange(ByteUtils.Int32ToArray(value)); _packet.AddRange(ByteUtils.Int32ToArray(value));
} }
public void AppendUInt32(uint value)
{
_packet.AddRange(ByteUtils.UInt32ToArray(value));
}
public void AppendBoolean(bool value) public void AppendBoolean(bool value)
{ {
_packet.Add((byte)(value ? 1 : 0)); _packet.Add((byte)(value ? 1 : 0));

1
FigureData.json Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,9 @@
namespace Tiger.Game.Achievements;
public class Achievement
{
public virtual int Id { get; set; }
public virtual string Badge { get; set; } = null!;
public virtual string Category { get; set; } = null!;
public virtual IDictionary<int, AchievementLevel> Levels { get; set; } = new Dictionary<int, AchievementLevel>();
}

View File

@ -0,0 +1,30 @@
namespace Tiger.Game.Achievements;
public class AchievementLevel
{
public virtual Achievement Achievement { get; set; } = null!;
public virtual int Level { get; set; }
public virtual int RewardAmount { get; set; }
public virtual int RewardType { get; set; }
public virtual int Points { get; set; }
public virtual int ProgressNeeded { get; set; }
public override bool Equals(object? obj)
{
if (obj is not AchievementLevel other)
return false;
return Achievement.Id == other.Achievement.Id && Level == other.Level;
}
public override int GetHashCode()
{
unchecked
{
var hash = 17;
hash = hash * 23 + Achievement.Id.GetHashCode();
hash = hash * 23 + Level.GetHashCode();
return hash;
}
}
}

View File

@ -0,0 +1,19 @@
using FluentNHibernate.Mapping;
namespace Tiger.Game.Achievements;
public class AchievementLevelMap : ClassMap<AchievementLevel>
{
public AchievementLevelMap()
{
Table("achievement_levels");
LazyLoad();
CompositeId()
.KeyProperty(al => al.Level, "level")
.KeyReference(al => al.Achievement, "achievement_id");
Map(al => al.RewardAmount).Column("reward_amount").Not.Nullable();
Map(al => al.RewardType).Column("reward_type").Not.Nullable();
Map(al => al.ProgressNeeded).Column("progress_needed").Not.Nullable();
Map(al => al.Points).Column("points").Not.Nullable();
}
}

View File

@ -0,0 +1,117 @@
using Microsoft.Extensions.Logging;
using Tiger.Communication.Messages.Outgoing.Inventory.Achievements;
using Tiger.Communication.Messages.Outgoing.Notifications;
using Tiger.Game.Habbos;
using Tiger.Networking.Game.Sessions;
using Tiger.Storage;
namespace Tiger.Game.Achievements;
public class AchievementManager : IAchievementManager
{
private readonly IRepository<Achievement> _achievementRepository;
private readonly ILogger<IAchievementManager> _logger;
private readonly IRepository<Badge> _badgesRepository;
private readonly IRepository<Habbo> _habboRepository;
public AchievementManager(IRepository<Achievement> achievementRepository, ILogger<IAchievementManager> logger, IRepository<Badge> badgesRepository, IRepository<Habbo> habboRepository)
{
_achievementRepository = achievementRepository;
_logger = logger;
_badgesRepository = badgesRepository;
_habboRepository = habboRepository;
}
public IDictionary<string, Achievement> Achievements { get; private set; } = new Dictionary<string, Achievement>();
public async Task LoadAchievementsAsync()
{
Achievements = (await _achievementRepository.FindByAsync()).ToDictionary(a => a.Badge, a => a);
_logger.LogInformation("Loaded {Count} Achievements", Achievements.Count);
}
public async Task UpdateAchievementAsync(string achievementName, int progress, GameSession session)
{
if (session.Habbo is null) return;
if (!Achievements.TryGetValue(achievementName, out var achievement)) return;
if (progress == 0) return;
if (!session.Habbo.Achievements.TryGetValue(achievement.Id, out var habboAchievement))
{
habboAchievement = new HabboAchievement()
{
Level = 0,
Progress = 0,
Achievement = achievement,
Habbo = session.Habbo
};
session.Habbo.Achievements.Add(achievement.Id, habboAchievement);
}
if (habboAchievement.Level == achievement.Levels.Count) return;
var targetLevel = habboAchievement.Level + 1;
var achievementLevel = achievement.Levels[targetLevel];
habboAchievement.Progress += progress;
if (habboAchievement.Progress >= achievementLevel.ProgressNeeded)
{
habboAchievement.Level++;
Badge badge;
if (habboAchievement.Level == 1)
{
badge = new Badge
{
Habbo = session.Habbo,
Code = $"{achievement.Badge}1"
};
session.Habbo.Badges.Add(badge);
}
else
{
var currentBadge =
session.Habbo.Badges.SingleOrDefault(b =>
b.Code == $"{achievement.Badge}{habboAchievement.Level - 1}");
if (currentBadge != null)
{
currentBadge.Code = $"{achievement.Badge}{habboAchievement.Level - 1}";
badge = currentBadge;
}
else
{
badge = new Badge
{
Habbo = session.Habbo,
Code = $"{achievement.Badge}1"
};
session.Habbo.Badges.Add(badge);
}
}
session.Habbo.AchievementScore += achievementLevel.Points;
if (achievementLevel.RewardAmount > 0)
{
session.Habbo.UpdateCurrency(achievementLevel.RewardType, achievementLevel.RewardAmount);
session.SendComposerAsync(new ActivityPointNotificationMessageComposer(session.Habbo.Activitypoints[achievementLevel.RewardType].Amount, achievementLevel.RewardAmount, achievementLevel.RewardType));
}
// session.CurrentRoom?.SendMessage(new UserChangeMessageComposer(session.RoomUser.VirtualId, session.User));
session.SendComposerAsync(new AchievementsScoreComposer(session.Habbo.AchievementScore));
session.SendComposerAsync(new AchievementNotificationMessageComposer(habboAchievement, badge.Id));
}
_habboRepository.SaveAsync(session.Habbo);
await session.SendComposerAsync(new AchievementComposer(achievement, habboAchievement));
}
}

View File

@ -0,0 +1,16 @@
using FluentNHibernate.Mapping;
namespace Tiger.Game.Achievements;
public class AchievementMap : ClassMap<Achievement>
{
public AchievementMap()
{
Table("achievements");
LazyLoad();
Id(a => a.Id).Column("id").GeneratedBy.Identity();
Map(a => a.Badge).Column("badge").Not.Nullable();
Map(a => a.Category).Column("category").Not.Nullable();
HasMany(a => a.Levels).AsMap(al => al.Level).Cascade.All();
}
}

View File

@ -0,0 +1,10 @@
using Tiger.Networking.Game.Sessions;
namespace Tiger.Game.Achievements;
public interface IAchievementManager
{
IDictionary<string, Achievement> Achievements { get; }
Task LoadAchievementsAsync();
Task UpdateAchievementAsync(string achievementName, int progress, GameSession session);
}

View File

@ -0,0 +1,11 @@
namespace Tiger.Game.Catalogue;
public class CatalogueFeaturedPage
{
public virtual int SlotId { get; set; }
public virtual string Image { get; set; } = null!;
public virtual string Caption { get; set; } = null!;
public virtual CatalogueFeaturedPageType Type { get; set; }
public virtual DateTime Expire { get; set; }
public virtual string Data { get; set; } = null!;
}

View File

@ -0,0 +1,17 @@
using FluentNHibernate.Mapping;
namespace Tiger.Game.Catalogue;
public class CatalogueFeaturedPageMap : ClassMap<CatalogueFeaturedPage>
{
public CatalogueFeaturedPageMap()
{
Table("catalogue_featured_pages");
Id(fp => fp.SlotId).Column("slot_id").GeneratedBy.Identity();
Map(fp => fp.Image).Column("image").Not.Nullable();
Map(fp => fp.Caption).Column("caption").Not.Nullable();
Map(fp => fp.Type).CustomType<int>().Column("type").Not.Nullable();
Map(fp => fp.Expire).Column("expire").Not.Nullable();
Map(fp => fp.Data).Column("data").Not.Nullable();
}
}

View File

@ -0,0 +1,8 @@
namespace Tiger.Game.Catalogue;
public enum CatalogueFeaturedPageType
{
PageName,
PageId,
ProductName
}

View File

@ -0,0 +1,122 @@
using Microsoft.Extensions.Logging;
using Tiger.Communication.Messages.Outgoing.Catalog;
using Tiger.Communication.Messages.Outgoing.Inventory.Currency;
using Tiger.Communication.Messages.Outgoing.Inventory.Subscription;
using Tiger.Communication.Messages.Outgoing.Notifications;
using Tiger.Game.Achievements;
using Tiger.Game.Habbos;
using Tiger.Networking.Game.Sessions;
using Tiger.Storage;
namespace Tiger.Game.Catalogue;
public class CatalogueManager : ICatalogueManager
{
private readonly IRepository<CataloguePage> _pagesRepository;
private readonly ILogger<ICatalogueManager> _logger;
private readonly IRepository<CatalogueFeaturedPage> _featuredPagesRepository;
private readonly IRepository<ClubOffer> _clubOfferRepository;
private readonly IRepository<HabboSubscription> _habboSubscriptionRepository;
private readonly IAchievementManager _achievementManager;
public IDictionary<int, CataloguePage> Pages { get; private set; }
public IDictionary<int, CatalogueFeaturedPage> FeaturedPages { get; private set; }
public IDictionary<int, ClubOffer> ClubOffers { get; private set; }
public CatalogueManager(IRepository<CataloguePage> pagesRepository, ILogger<ICatalogueManager> logger,
IRepository<CatalogueFeaturedPage> featuredPagesRepository, IRepository<ClubOffer> clubOfferRepository,
IRepository<HabboSubscription> habboSubscriptionRepository, IAchievementManager achievementManager)
{
_pagesRepository = pagesRepository;
_logger = logger;
_featuredPagesRepository = featuredPagesRepository;
_clubOfferRepository = clubOfferRepository;
_habboSubscriptionRepository = habboSubscriptionRepository;
_achievementManager = achievementManager;
Pages = new Dictionary<int, CataloguePage>();
FeaturedPages = new Dictionary<int, CatalogueFeaturedPage>();
ClubOffers = new Dictionary<int, ClubOffer>();
}
public async Task LoadPagesAsync()
{
Pages = (await _pagesRepository.FindByAsync()).ToDictionary(p => p.Id, p => p);
_logger.LogInformation("Loaded {Count} catalogue pages", Pages.Count);
}
public async Task LoadFeaturedPagesAsync()
{
FeaturedPages = (await _featuredPagesRepository.FindByAsync())
.ToDictionary(p => p.SlotId, p => p);
_logger.LogInformation("Loaded {Count} catalogue featured pages", FeaturedPages.Count);
}
public async Task LoadClubOffersAsync()
{
ClubOffers = (await _clubOfferRepository.FindByAsync())
.ToDictionary(co => co.Id);
_logger.LogInformation("Loaded {Count} club offers", ClubOffers.Count);
}
public async Task PurchaseClubOffer(int offerId, GameSession gameSession)
{
if (!ClubOffers.TryGetValue(offerId, out var clubOffer) || gameSession.Habbo == null)
{
return;
}
var tooShortOnCoins = clubOffer.PriceCredits > 0 && clubOffer.PriceCredits > gameSession.Habbo.Credits;
var tooShortOnActivityPoints = clubOffer.PriceActivitypoints > 0 && clubOffer.PriceActivitypoints >
gameSession.Habbo.GetActivityPoints(clubOffer.ActivitypointsType);
if (tooShortOnCoins || tooShortOnActivityPoints)
{
await gameSession.SendComposerAsync(new NotEnoughBalanceMessageComposer(tooShortOnCoins,
tooShortOnActivityPoints, clubOffer.ActivitypointsType));
return;
}
if (clubOffer.PriceCredits > 0)
{
gameSession.Habbo.Credits -= clubOffer.PriceCredits;
gameSession.SendComposerAsync(new UserCreditsComposer(gameSession.Habbo.Credits));
}
if (clubOffer.PriceActivitypoints > 0)
{
gameSession.Habbo.UpdateCurrency(clubOffer.ActivitypointsType, -clubOffer.PriceActivitypoints);
gameSession.SendComposerAsync(new ActivityPointNotificationMessageComposer(
gameSession.Habbo.GetActivityPoints(clubOffer.ActivitypointsType), -clubOffer.PriceActivitypoints,
clubOffer.ActivitypointsType));
}
var currentSubscription = gameSession.Habbo.GetActiveSubscription();
if (currentSubscription != null)
{
currentSubscription.Expires = currentSubscription.Expires.AddDays(clubOffer.Days);
currentSubscription.Habbo.Credits -= clubOffer.PriceCredits;
currentSubscription.Habbo.UpdateCurrency(clubOffer.ActivitypointsType, -clubOffer.PriceActivitypoints);
_habboSubscriptionRepository.SaveAsync(currentSubscription);
gameSession.SendComposerAsync(new UserSubscriptionComposer(currentSubscription,
gameSession.Habbo.GetPastSubscriptionDays()));
}
else
{
var subscription = new HabboSubscription
{
Expires = DateTime.Now.AddDays(clubOffer.Days),
SubscriptionType = "habbo_club",
Started = DateTime.Now,
Habbo = gameSession.Habbo
};
_habboSubscriptionRepository.SaveAsync(subscription);
gameSession.SendComposerAsync(new UserSubscriptionComposer(subscription,
gameSession.Habbo.GetPastSubscriptionDays()));
_achievementManager.UpdateAchievementAsync("ACH_HC", 1, gameSession);
}
}
}

View File

@ -0,0 +1,19 @@
namespace Tiger.Game.Catalogue;
public class CataloguePage
{
public virtual int Id { get; set; }
public virtual string Name { get; set; } = null!;
public virtual string InternalName { get; set; } = null!;
public virtual string Layout { get; set; } = null!;
public virtual bool Visible { get; set; }
public virtual bool Enabled { get; set; }
public virtual int Icon { get; set; }
public virtual int MinRank { get; set; }
public virtual CataloguePage? Parent { get; set; }
public virtual IList<CataloguePage> Children { get; set; } = new List<CataloguePage>();
public virtual IList<string> Images { get; set; } = new List<string>();
public virtual IList<string> Texts { get; set; } = new List<string>();
public virtual bool SeasonalCurrency { get; set; }
public virtual IList<string> Modes { get; set; } = new List<string>();
}

View File

@ -0,0 +1,27 @@
using FluentNHibernate.Mapping;
using Tiger.Storage;
namespace Tiger.Game.Catalogue;
public class CataloguePageMap : ClassMap<CataloguePage>
{
public CataloguePageMap()
{
Table("catalogue_pages");
LazyLoad();
Id(c => c.Id).Column("id").GeneratedBy.Identity();
Map(c => c.Name).Column("name").Not.Nullable();
Map(c => c.InternalName).Column("internal_name").Not.Nullable();
Map(c => c.Layout).Column("layout").Not.Nullable();
Map(c => c.Visible).Column("visible").Not.Nullable();
Map(c => c.Enabled).Column("enabled").Not.Nullable();
Map(c => c.Icon).Column("icon").Not.Nullable();
Map(c => c.MinRank).Column("min_rank").Not.Nullable();
References(x => x.Parent).Column("parent_id").Nullable();
HasMany(x => x.Children).KeyColumn("parent_id").Inverse().Cascade.AllDeleteOrphan();
Map(c => c.Images).CustomType<StringListTypeConverter>();
Map(c => c.Texts).CustomType<StringListTypeConverter>();
Map(c => c.SeasonalCurrency).Column("seasonal_currency").Not.Nullable();
Map(c => c.Modes).CustomType<StringListTypeConverter>();
}
}

View File

@ -0,0 +1,12 @@
namespace Tiger.Game.Catalogue;
public class ClubOffer
{
public virtual int Id { get; set; }
public virtual string Name { get; set; } = null!;
public virtual int PriceCredits { get; set; }
public virtual int PriceActivitypoints { get; set; }
public virtual int ActivitypointsType { get; set; }
public virtual int Days { get; set; }
public virtual bool DiscountExtension { get; set; }
}

View File

@ -0,0 +1,18 @@
using FluentNHibernate.Mapping;
namespace Tiger.Game.Catalogue;
public class ClubOfferMap : ClassMap<ClubOffer>
{
public ClubOfferMap()
{
Table("catalogue_club_offers");
Id(co => co.Id).Column("id").GeneratedBy.Identity();
Map(co => co.Name).Column("name").Not.Nullable();
Map(co => co.PriceCredits).Column("price_credits").Not.Nullable();
Map(co => co.PriceActivitypoints).Column("price_activitypoints").Not.Nullable();
Map(co => co.ActivitypointsType).Column("activitypoints_type").Not.Nullable();
Map(co => co.Days).Column("days").Not.Nullable();
Map(co => co.DiscountExtension).Column("discount_extension").Not.Nullable();
}
}

View File

@ -0,0 +1,14 @@
using Tiger.Networking.Game.Sessions;
namespace Tiger.Game.Catalogue;
public interface ICatalogueManager
{
public IDictionary<int, CataloguePage> Pages { get; }
public IDictionary<int, CatalogueFeaturedPage> FeaturedPages { get; }
public IDictionary<int, ClubOffer> ClubOffers { get; }
Task LoadPagesAsync();
Task LoadFeaturedPagesAsync();
Task LoadClubOffersAsync();
Task PurchaseClubOffer(int offerId, GameSession gameSession);
}

10
Game/Figuredata/Color.cs Normal file
View File

@ -0,0 +1,10 @@
namespace Tiger.Game.Figuredata;
public class Color
{
public int Id { get; set; }
public int Index { get; set; }
public int Club { get; set; }
public bool Selectable { get; set; }
public string HexCode { get; set; } = null!;
}

View File

@ -0,0 +1,7 @@
namespace Tiger.Game.Figuredata;
public class Figuredata
{
public List<Palette> Palettes { get; set; } = new();
public List<SetType> SetTypes { get; set; } = new();
}

View File

@ -0,0 +1,76 @@
using Newtonsoft.Json;
using Tiger.Game.Habbos;
namespace Tiger.Game.Figuredata;
public class FiguredataManager : IFigureDataManager
{
private readonly Figuredata? _figuredata;
public FiguredataManager()
{
try
{
_figuredata = JsonConvert.DeserializeObject<Figuredata>(File.ReadAllText("FigureData.json"));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public bool ValidateFigure(string newFigure, string newGender, Habbo habbo)
{
if (_figuredata is null)
return false;
var parts = newFigure.Split('.');
foreach (var part in parts)
{
if (!part.Contains('-'))
return false;
var subParts = part.Split('-');
var setType = _figuredata.SetTypes.SingleOrDefault(st => st.Type == subParts[0]);
if (setType is null)
return false;
var palette = _figuredata.Palettes.SingleOrDefault(p => p.Id == setType.PaletteId);
if (palette is null)
return false;
var set = setType.Sets.SingleOrDefault(s => s.Id == int.Parse(subParts.Length >= 2 ? subParts[1] : "-1"));
if (set is null)
return false;
// TODO: Check if is club
// TODO: Check for buyable clothes
if (set.Gender.ToUpper() != newGender)
return false;
if (set.Colorable && subParts.Length < 3)
return false;
if (!set.Colorable) continue;
var paletteColor1 = palette.Colors.SingleOrDefault(c => c.Id == int.Parse(subParts[2]));
if (paletteColor1 is null)
return false;
if (subParts.Length == 3) continue;
var paletteColor2 = palette.Colors.SingleOrDefault(c => c.Id == int.Parse(subParts[3]));
if (paletteColor2 is null)
return false;
}
return true;
}
}

View File

@ -0,0 +1,8 @@
using Tiger.Game.Habbos;
namespace Tiger.Game.Figuredata;
public interface IFigureDataManager
{
bool ValidateFigure(string newFigure, string newGender, Habbo habbo);
}

View File

@ -0,0 +1,7 @@
namespace Tiger.Game.Figuredata;
public class Palette
{
public int Id { get; set; }
public List<Color> Colors { get; set; } = new();
}

10
Game/Figuredata/Part.cs Normal file
View File

@ -0,0 +1,10 @@
namespace Tiger.Game.Figuredata;
public class Part
{
public bool Colorable { get; set; }
public int ColorIndex { get; set; }
public uint Id { get; set; }
public int Index { get; set; }
public string Type { get; set; } = null!;
}

13
Game/Figuredata/Set.cs Normal file
View File

@ -0,0 +1,13 @@
namespace Tiger.Game.Figuredata;
public class Set
{
public int Club { get; set; }
public bool Colorable { get; set; }
public string Gender { get; set; } = null!;
public int Id { get; set; }
public bool Preselectable { get; set; }
public bool Selectable { get; set; }
public bool Sellable { get; set; }
public List<Part> Parts { get; set; } = new();
}

View File

@ -0,0 +1,19 @@
using System.Text.Json.Serialization;
using Newtonsoft.Json;
namespace Tiger.Game.Figuredata;
public class SetType
{
public string Type { get; set; } = null!;
[JsonProperty("mandatory_f_0")]
public bool MandatoryF0 { get; set; }
[JsonProperty("mandatory_f_1")]
public bool MandatoryF1 { get; set; }
[JsonProperty("mandatory_m_0")]
public bool MandatoryM0 { get; set; }
[JsonProperty("mandatory_m_1")]
public bool MandatoryM1 { get; set; }
public int PaletteId { get; set; }
public List<Set> Sets { get; set; } = new();
}

View File

@ -0,0 +1,27 @@
namespace Tiger.Game.Habbos;
public class Activitypoints
{
public virtual Habbo Habbo { get; set; } = null!;
public virtual int Type { get; set; }
public virtual int Amount { get; set; }
public override bool Equals(object? obj)
{
if (obj is not Activitypoints other)
return false;
return Habbo.Id == other.Habbo.Id && Type == other.Type;
}
public override int GetHashCode()
{
unchecked
{
var hash = 17;
hash = hash * 23 + Habbo.Id.GetHashCode();
hash = hash * 23 + Type.GetHashCode();
return hash;
}
}
}

View File

@ -0,0 +1,16 @@
using FluentNHibernate.Mapping;
namespace Tiger.Game.Habbos;
public class ActivitypointsMap : ClassMap<Activitypoints>
{
public ActivitypointsMap()
{
Table("habbo_activitypoints");
LazyLoad();
CompositeId()
.KeyProperty(h => h.Type, "type")
.KeyReference(h => h.Habbo, "habbo_id");
Map(h => h.Amount).Column("amount").Not.Nullable();
}
}

9
Game/Habbos/Badge.cs Normal file
View File

@ -0,0 +1,9 @@
namespace Tiger.Game.Habbos;
public class Badge
{
public virtual int Id { get; set; }
public virtual Habbo Habbo { get; set; } = null!;
public virtual string Code { get; set; } = null!;
public virtual int Slot { get; set; }
}

16
Game/Habbos/BadgeMap.cs Normal file
View File

@ -0,0 +1,16 @@
using FluentNHibernate.Mapping;
namespace Tiger.Game.Habbos;
public class BadgeMap : ClassMap<Badge>
{
public BadgeMap()
{
Table("habbo_badges");
LazyLoad();
Id(b => b.Id).Column("id").GeneratedBy.Identity();
References(b => b.Habbo).Column("habbo_id").Not.Nullable();
Map(b => b.Code).Column("code").Not.Nullable();
Map(b => b.Slot).Column("slot").Not.Nullable();
}
}

View File

@ -2,7 +2,7 @@ namespace Tiger.Game.Habbos;
public class Habbo public class Habbo
{ {
public virtual uint Id { get; set; } public virtual int Id { get; set; }
public virtual string Username { get; set; } = null!; public virtual string Username { get; set; } = null!;
public virtual string Email { get; set; } = null!; public virtual string Email { get; set; } = null!;
public virtual DateTime AccountCreated { get; set; } public virtual DateTime AccountCreated { get; set; }
@ -10,11 +10,60 @@ public class Habbo
public virtual string Motto { get; set; } = null!; public virtual string Motto { get; set; } = null!;
public virtual string Figure { get; set; } = null!; public virtual string Figure { get; set; } = null!;
public virtual string Gender { get; set; } = null!; public virtual string Gender { get; set; } = null!;
public virtual byte Rank { get; set; } public virtual int Rank { get; set; }
public virtual uint Credits { get; set; } public virtual int Credits { get; set; }
public virtual bool Online { get; set; } public virtual bool Online { get; set; }
public virtual uint HomeRoom { get; set; } public virtual int HomeRoom { get; set; }
public virtual uint AchievementScore { get; set; } public virtual int AchievementScore { get; set; }
public virtual uint? GroupId { get; set; } public virtual int? GroupId { get; set; }
public virtual string? SsoTicket { get; set; } public virtual string? SsoTicket { get; set; }
public virtual IDictionary<int, Activitypoints> Activitypoints { get; set; } = new Dictionary<int, Activitypoints>();
public virtual ICollection<Badge> Badges { get; set; } = new List<Badge>();
public virtual IDictionary<int, HabboAchievement> Achievements { get; set; } = new Dictionary<int, HabboAchievement>();
public virtual ICollection<HabboSubscription> Subscriptions { get; set; } = new List<HabboSubscription>();
public virtual int GetActivityPoints(int type)
{
return Activitypoints.TryGetValue(type, out var activityPoints) ? activityPoints.Amount : 0;
}
public virtual void UpdateCurrency(int type, int amount)
{
if (!Activitypoints.ContainsKey(type))
{
Activitypoints.Add(type, new Activitypoints
{
Habbo = this,
Amount = amount,
Type = type
});
return;
}
Activitypoints[type].Amount += amount;
}
public virtual HabboSubscription? GetActiveSubscription()
{
return Subscriptions.Where(s => s.Expires > DateTime.Now).MaxBy(s => s.Expires);
}
public virtual int GetPastSubscriptionDays()
{
int totalDays = 0;
foreach (var subscription in Subscriptions)
{
if(subscription.Expires < DateTime.Now) // If subscription has ended
{
totalDays += (subscription.Expires - subscription.Started).Days;
}
else if(subscription.Started < DateTime.Now) // If subscription is ongoing
{
totalDays += (DateTime.Now - subscription.Started).Days;
}
}
return totalDays;
}
} }

View File

@ -0,0 +1,30 @@
using Tiger.Game.Achievements;
namespace Tiger.Game.Habbos;
public class HabboAchievement
{
public virtual Habbo Habbo { get; set; } = null!;
public virtual Achievement Achievement { get; set; } = null!;
public virtual int Level { get; set; }
public virtual int Progress { get; set; }
public override bool Equals(object? obj)
{
if (obj is not HabboAchievement other)
return false;
return Habbo.Id == other.Habbo.Id && Achievement.Id == other.Achievement.Id;
}
public override int GetHashCode()
{
unchecked
{
var hash = 17;
hash = hash * 23 + Habbo.Id.GetHashCode();
hash = hash * 23 + Achievement.Id.GetHashCode();
return hash;
}
}
}

View File

@ -0,0 +1,17 @@
using FluentNHibernate.Mapping;
namespace Tiger.Game.Habbos;
public class HabboAchievementMap : ClassMap<HabboAchievement>
{
public HabboAchievementMap()
{
Table("habbo_achievements");
LazyLoad();
CompositeId()
.KeyReference(ha => ha.Habbo, "habbo_id")
.KeyReference(ha => ha.Achievement, "achievement_id");
Map(ha => ha.Level).Column("level").Not.Nullable();
Map(ha => ha.Progress).Column("progress").Not.Nullable();
}
}

View File

@ -23,5 +23,18 @@ public class HabboMap : ClassMap<Habbo>
Map(h => h.AchievementScore).Column("achievement_score").Not.Nullable(); Map(h => h.AchievementScore).Column("achievement_score").Not.Nullable();
Map(h => h.GroupId).Column("group_id").Nullable(); Map(h => h.GroupId).Column("group_id").Nullable();
Map(h => h.SsoTicket).Column("sso_ticket").Nullable(); Map(h => h.SsoTicket).Column("sso_ticket").Nullable();
HasMany(h => h.Activitypoints).AsMap(a => a.Type).Inverse().Cascade.All();
HasMany(h => h.Badges).Inverse().Cascade.All();
HasMany(x => x.Achievements)
.Table("habbo_achievements")
.KeyColumn("habbo_id")
.Component(comp =>
{
comp.Map(x => x.Level);
comp.Map(x => x.Progress);
})
.AsMap("achievement_id")
.Cascade.All();
HasMany(h => h.Subscriptions).Cascade.All().Inverse();
} }
} }

View File

@ -0,0 +1,14 @@
namespace Tiger.Game.Habbos;
public class HabboSubscription
{
public virtual int Id { get; set; }
public virtual Habbo Habbo { get; set; } = null!;
public virtual string SubscriptionType { get; set; }= null!;
public virtual DateTime Started { get; set; }
public virtual DateTime Expires { get; set; }
public virtual int DaysInMonthLeft => (int)(Expires - DateTime.Now).TotalDays % 31;
public virtual int MonthsLeft => (int)(Expires - DateTime.Now).TotalDays / 31;
public virtual double MinutesLeft => (Expires - DateTime.Now).TotalMinutes;
}

View File

@ -0,0 +1,17 @@
using FluentNHibernate.Mapping;
namespace Tiger.Game.Habbos;
public class HabboSubscriptionMap : ClassMap<HabboSubscription>
{
public HabboSubscriptionMap()
{
Table("habbo_subscriptions");
LazyLoad();
Id(hs => hs.Id).Column("id").GeneratedBy.Identity();
Map(hs => hs.SubscriptionType).Column("subscription_type").Not.Nullable();
Map(hs => hs.Started).Column("started").Not.Nullable();
Map(hs => hs.Expires).Column("expires").Not.Nullable();
References(x => x.Habbo).Column("habbo_id").Not.Nullable();
}
}

View File

@ -0,0 +1,7 @@
namespace Tiger.Game.LandingView;
public interface ILandingViewManager
{
ICollection<PromoArticle> PromoArticles { get; }
Task LoadPromoArticlesAsync();
}

View File

@ -0,0 +1,25 @@
using Microsoft.Extensions.Logging;
using Tiger.Storage;
namespace Tiger.Game.LandingView;
public class LandingViewManager : ILandingViewManager
{
private readonly IRepository<PromoArticle> _promoArticleRepository;
private readonly ILogger<ILandingViewManager> _logger;
public LandingViewManager(IRepository<PromoArticle> promoArticleRepository, ILogger<ILandingViewManager> logger)
{
_promoArticleRepository = promoArticleRepository;
_logger = logger;
}
public ICollection<PromoArticle> PromoArticles { get; private set; } = new List<PromoArticle>();
public async Task LoadPromoArticlesAsync()
{
PromoArticles = (await _promoArticleRepository.FindByAsync()).ToList();
_logger.LogInformation("Loaded {Count} promo articles", PromoArticles.Count);
}
}

View File

@ -0,0 +1,12 @@
namespace Tiger.Game.LandingView;
public class PromoArticle
{
public virtual int Id { get; set; }
public virtual string Title { get; set; } = null!;
public virtual string BodyText { get; set; } = null!;
public virtual string ButtonText { get; set; } = null!;
public virtual PromoArticleLinkType LinkType { get; set; }
public virtual string LinkContent { get; set; } = null!;
public virtual string ImageUrl { get; set; } = null!;
}

View File

@ -0,0 +1,8 @@
namespace Tiger.Game.LandingView;
public enum PromoArticleLinkType
{
LinkTypeUrl = 0,
LinkTypeInternal = 1,
LinkTypeNoLink = 2
}

View File

@ -0,0 +1,18 @@
using FluentNHibernate.Mapping;
namespace Tiger.Game.LandingView;
public class PromoArticleMap : ClassMap<PromoArticle>
{
public PromoArticleMap()
{
Table("landing_promo_articles");
Id(pa => pa.Id).Column("id").GeneratedBy.Identity();
Map(pa => pa.Title).Column("title").Not.Nullable();
Map(pa => pa.BodyText).Column("body_text").Not.Nullable();
Map(pa => pa.ButtonText).Column("button_text").Not.Nullable();
Map(pa => pa.LinkType).CustomType<int>().Column("link_type").Not.Nullable();
Map(pa => pa.LinkContent).Column("link_content").Not.Nullable();
Map(pa => pa.ImageUrl).Column("image_url").Not.Nullable();
}
}

View File

@ -0,0 +1,8 @@
using Tiger.Game.Navigator.Views;
namespace Tiger.Game.Navigator;
public interface INavigatorManager
{
IDictionary<string, INavigatorView> NavigatorViews { get; }
}

View File

@ -0,0 +1,13 @@
using Tiger.Game.Navigator.Views;
namespace Tiger.Game.Navigator;
public class NavigatorManager : INavigatorManager
{
public IDictionary<string, INavigatorView> NavigatorViews { get; }
public NavigatorManager(IEnumerable<INavigatorView> navigatorViews)
{
NavigatorViews = navigatorViews.ToDictionary(n => n.Code);
}
}

View File

@ -0,0 +1,10 @@
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
namespace Tiger.Game.Navigator.Views;
public interface INavigatorView
{
string Code { get; }
Task Compose(ServerMessage message, Habbo habbo, string query);
}

View File

@ -0,0 +1,69 @@
using System.Collections;
using System.Collections.ObjectModel;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
using Tiger.Game.Rooms;
using Tiger.Storage;
namespace Tiger.Game.Navigator.Views;
public class MyWorldView : INavigatorView
{
private readonly IRepository<Room> _roomRepository;
private const int OwnRoomsType = 0;
private const int FavoriteRoomsType = 1;
private const int GroupRoomsType = 2;
private const int VisitedRoomsType = 3;
private const int FriendRoomsType = 4;
private const int RightsRoomType = 5;
public string Code => "myworld_view";
private readonly IDictionary<string, int> _categories = new Dictionary<string, int>
{
{"My Rooms", OwnRoomsType},
{"My Favorite Rooms", FavoriteRoomsType},
{"My Groups", GroupRoomsType},
{"My Room Visit History", VisitedRoomsType},
{"My Friends' Rooms", FriendRoomsType},
{"Rooms Where I Have Rights", RightsRoomType}
};
public MyWorldView(IRepository<Room> roomRepository)
{
_roomRepository = roomRepository;
}
public async Task Compose(ServerMessage message, Habbo habbo, string query)
{
message.AppendInt32(_categories.Count);
foreach (var (category, type) in _categories)
{
message.AppendString(category);
message.AppendString(category);
message.AppendInt32(0); // action?
message.AppendBoolean(false); // closed?
message.AppendInt32(0); // mode?
var rooms = await GetRoomsByType(habbo, type);
message.AppendInt32(rooms.Count);
foreach (var room in rooms)
{
room.Serialize(message);
}
}
}
private async Task<ICollection<Room>> GetRoomsByType(Habbo habbo, int type)
{
return type switch
{
OwnRoomsType => (await _roomRepository.FindByAsync(r => r.Owner == habbo)).ToList(),
_ => new Collection<Room>()
};
}
}

View File

@ -0,0 +1,14 @@
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
namespace Tiger.Game.Navigator.Views;
public class OfficialView : INavigatorView
{
public string Code => "official_view";
public async Task Compose(ServerMessage message, Habbo habbo, string query)
{
message.AppendInt32(0);
await Task.CompletedTask;
}
}

View File

@ -0,0 +1,9 @@
namespace Tiger.Game.Rooms;
public interface IRoomManager
{
IDictionary<int, RoomPrivateCategory> PrivateCategories { get; }
IDictionary<int, RoomModel> RoomModels { get; }
Task LoadPrivateCategoriesAsync();
Task LoadRoomModels();
}

View File

@ -0,0 +1,17 @@
namespace Tiger.Game.Rooms.Mapping.Tiles;
public class RoomTile
{
public int X { get; set; }
public int Y { get; set; }
public double Height { get; set; }
public RoomTileState TileState { get; set; }
public RoomTile(int x, int y, double height, RoomTileState tileState)
{
X = x;
Y = y;
Height = height;
TileState = tileState;
}
}

View File

@ -0,0 +1,17 @@
namespace Tiger.Game.Rooms.Mapping.Tiles;
/// <summary>
/// Empty and Unavailable can be set in both the RoomTile and RoomPoint.
/// RoomTile belongs to the Model (the tile is either unavailable or empty)
/// RoomPoint belongs to the Grid (the tile has multiple states based on once actors and items are added)
/// </summary>
public enum RoomTileState
{
Empty,
Unavailable,
HasWalkableStackableItem,
WalkBlockedByItem,
StackBlockedByItem,
TileLockedByItem,
BlockedByUser
}

131
Game/Rooms/Room.cs Normal file
View File

@ -0,0 +1,131 @@
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
namespace Tiger.Game.Rooms;
public class Room
{
public virtual int Id { get; set; }
public virtual string Name { get; set; } = null!;
public virtual string Description { get; set; } = null!;
public virtual int ModelId { get; set; }
public virtual string Password { get; set; } = null!;
public virtual string State { get; set; } = null!;
public virtual int UsersIn { get; set; }
public virtual int UsersMax { get; set; }
public virtual int Score { get; set; }
public virtual string Floor { get; set; } = null!;
public virtual string Wallpaper { get; set; } = null!;
public virtual string Landscape { get; set; } = null!;
public virtual int WallThickness { get; set; }
public virtual int WallHeight { get; set; }
public virtual int FloorThickness { get; set; }
public virtual string MoodlightData { get; set; } = null!;
public virtual IList<string> Tags { get; set; } = new List<string>();
public virtual bool IsPublic { get; set; }
public virtual bool IsStaffPicked { get; set; }
public virtual bool AllowOtherPets { get; set; }
public virtual bool AllowOtherPetsEat { get; set; }
public virtual bool AllowWalkthrough { get; set; }
public virtual bool HideWalls { get; set; }
public virtual int ChatMode { get; set; }
public virtual int ChatWeight { get; set; }
public virtual int ChatSpeed { get; set; }
public virtual int ChatHearingDistance { get; set; }
public virtual int ChatProtection { get; set; }
public virtual bool OverrideModel { get; set; }
public virtual int WhoCanMute { get; set; }
public virtual int WhoCanKick { get; set; }
public virtual int WhoCanBan { get; set; }
public virtual int RollerSpeed { get; set; }
public virtual bool Promoted { get; set; }
public virtual int TradeMode { get; set; }
public virtual bool MoveDiagonally { get; set; }
public virtual bool JukeboxActive { get; set; }
public virtual bool HideWired { get; set; }
public virtual bool IsForSale { get; set; }
public virtual Habbo? Owner { get; set; }
public virtual RoomPrivateCategory Category { get; set; } = null!;
public virtual int StateNumber => State switch
{
"locked" => 1,
"password" => 2,
"invisible" => 3,
_ => 0
};
public virtual int Base
{
get
{
var @base = 0;
// if (Guild != null)
// {
// @base += 2;
// }
// if (Promoted)
// {
// @base += 4;
// }
if (!IsPublic)
{
@base += 8;
}
if (!IsPublic && AllowOtherPets)
{
@base += 16;
}
return @base;
}
}
public virtual void Serialize(ServerMessage response)
{
response.AppendInt32(Id);
response.AppendString(Name);
if (IsPublic)
{
response.AppendInt32(0);
response.AppendString(string.Empty);
}
else
{
response.AppendInt32(Owner?.Id ?? 0);
response.AppendString(Owner?.Username ?? string.Empty);
}
response.AppendInt32(StateNumber);
response.AppendInt32(UsersIn);
response.AppendInt32(UsersMax);
response.AppendString(Description);
response.AppendInt32(0);
response.AppendInt32(Score);
response.AppendInt32(0);
response.AppendInt32(Category.Id);
response.AppendInt32(Tags.Count);
foreach (var tag in Tags)
{
response.AppendString(tag);
}
response.AppendInt32(Base);
// if (Guild != null)
// {
// response.AppendInt32(Guild.Id);
// response.WriteString(Guild.Name);
// response.WriteString(Guild.Badge);
// }
// TODO: Promotion
}
}

45
Game/Rooms/RoomManager.cs Normal file
View File

@ -0,0 +1,45 @@
using Microsoft.Extensions.Logging;
using Tiger.Storage;
namespace Tiger.Game.Rooms;
public class RoomManager : IRoomManager
{
private readonly IRepository<RoomPrivateCategory> _roomPrivateCategoryRepository;
private readonly IRepository<RoomModel> _roomModelRepository;
private readonly ILogger<IRoomManager> _logger;
public IDictionary<int, RoomPrivateCategory> PrivateCategories { get; private set; }
public IDictionary<int, RoomModel> RoomModels { get; private set; }
public RoomManager(IRepository<RoomPrivateCategory> roomPrivateCategoryRepository,
IRepository<RoomModel> roomModelRepository, ILogger<IRoomManager> logger)
{
_roomPrivateCategoryRepository = roomPrivateCategoryRepository;
_roomModelRepository = roomModelRepository;
_logger = logger;
PrivateCategories = new Dictionary<int, RoomPrivateCategory>();
RoomModels = new Dictionary<int, RoomModel>();
}
public async Task LoadPrivateCategoriesAsync()
{
PrivateCategories =
(await _roomPrivateCategoryRepository.FindByAsync()).ToDictionary(rpc => rpc.Id);
_logger.LogInformation("Loaded {Count} private room categories", PrivateCategories.Count);
}
public async Task LoadRoomModels()
{
RoomModels = (await _roomModelRepository.FindByAsync()).ToDictionary(rpc => rpc.Id);
foreach (var model in RoomModels.Values)
{
model.Parse();
}
_logger.LogInformation("Loaded and parsed {Count} room models", RoomModels.Count);
}
}

53
Game/Rooms/RoomMap.cs Normal file
View File

@ -0,0 +1,53 @@
using FluentNHibernate.Mapping;
using Tiger.Storage;
namespace Tiger.Game.Rooms;
public class RoomMap : ClassMap<Room>
{
public RoomMap()
{
Table("rooms");
Id(x => x.Id).Column("id").GeneratedBy.Identity();
Map(x => x.Name).Column("name").Not.Nullable();
Map(x => x.Description).Column("description").Not.Nullable();
Map(x => x.ModelId).Column("model_id").Not.Nullable();
Map(x => x.Password).Column("password").Nullable();
Map(x => x.State).Column("state").Not.Nullable();
Map(x => x.UsersIn).Column("users_in").Not.Nullable();
Map(x => x.UsersMax).Column("users_max").Not.Nullable();
Map(x => x.Score).Column("score").Not.Nullable();
Map(x => x.Floor).Column("floor").Not.Nullable();
Map(x => x.Wallpaper).Column("wallpaper").Not.Nullable();
Map(x => x.Landscape).Column("landscape").Not.Nullable();
Map(x => x.WallThickness).Column("wall_thickness").Not.Nullable();
Map(x => x.WallHeight).Column("wall_height").Not.Nullable();
Map(x => x.FloorThickness).Column("floor_thickness").Not.Nullable();
Map(x => x.MoodlightData).Column("moodlight_data").Nullable();
Map(x => x.Tags).Column("tags").CustomType<StringListTypeConverter>().Nullable();
Map(x => x.IsPublic).Column("is_public").Not.Nullable();
Map(x => x.IsStaffPicked).Column("is_staff_picked").Not.Nullable();
Map(x => x.AllowOtherPets).Column("allow_other_pets").Not.Nullable();
Map(x => x.AllowOtherPetsEat).Column("allow_other_pets_eat").Not.Nullable();
Map(x => x.AllowWalkthrough).Column("allow_walkthrough").Not.Nullable();
Map(x => x.HideWalls).Column("hide_walls").Not.Nullable();
Map(x => x.ChatMode).Column("chat_mode").Not.Nullable();
Map(x => x.ChatWeight).Column("chat_weight").Not.Nullable();
Map(x => x.ChatSpeed).Column("chat_speed").Not.Nullable();
Map(x => x.ChatHearingDistance).Column("chat_hearing_distance").Not.Nullable();
Map(x => x.ChatProtection).Column("chat_protection").Not.Nullable();
Map(x => x.OverrideModel).Column("override_model").Not.Nullable();
Map(x => x.WhoCanMute).Column("who_can_mute").Not.Nullable();
Map(x => x.WhoCanKick).Column("who_can_kick").Not.Nullable();
Map(x => x.WhoCanBan).Column("who_can_ban").Not.Nullable();
Map(x => x.RollerSpeed).Column("roller_speed").Not.Nullable();
Map(x => x.Promoted).Column("promoted").Not.Nullable();
Map(x => x.TradeMode).Column("trade_mode").Not.Nullable();
Map(x => x.MoveDiagonally).Column("move_diagonally").Not.Nullable();
Map(x => x.JukeboxActive).Column("jukebox_active").Not.Nullable();
Map(x => x.HideWired).Column("hide_wired").Not.Nullable();
Map(x => x.IsForSale).Column("is_for_sale").Not.Nullable();
References(x => x.Owner).Column("owner_id").Nullable();
References(x => x.Category).Column("category_id").Not.Nullable();
}
}

41
Game/Rooms/RoomModel.cs Normal file
View File

@ -0,0 +1,41 @@
using Tiger.Game.Rooms.Mapping.Tiles;
namespace Tiger.Game.Rooms;
public class RoomModel
{
public virtual int Id { get; set; }
public virtual string Name { get; set; } = null!;
public virtual int DoorX { get; set; }
public virtual int DoorY { get; set; }
public virtual int DoorDirection { get; set; }
public virtual string Heightmap { get; set; } = null!;
public virtual (int X, int Y) MapSize { get; set; }
public virtual RoomTile[,] RoomTiles { get; set; }
public virtual void Parse()
{
var raw = Heightmap.Replace("\r\n", "\r").Split('\r');
MapSize = (raw[0].Length, raw.Length);
RoomTiles = new RoomTile[MapSize.X, MapSize.Y];
for (var y = 0; y < MapSize.Y; y++)
{
for (var x = 0; x < MapSize.X; x++)
{
if (double.TryParse(raw[y][x].ToString(), out var height))
{
RoomTiles[x, y] = new RoomTile(x, y, height, RoomTileState.Empty);
}
else
{
RoomTiles[x, y] = new RoomTile(x, y, 0, RoomTileState.Unavailable);
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More