Initial commit
						commit
						d5efddd10d
					
				| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
.idea/
 | 
			
		||||
vendor/
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
{
 | 
			
		||||
    "require": {
 | 
			
		||||
        "react/event-loop": "^1.5",
 | 
			
		||||
        "react/http": "^1.9",
 | 
			
		||||
        "react/stream": "^1.3",
 | 
			
		||||
        "react/async": "^4.2",
 | 
			
		||||
        "react/promise": "^3.1",
 | 
			
		||||
        "react/socket": "^1.15",
 | 
			
		||||
        "cboden/ratchet": "^0.4.4"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
require_once 'vendor/autoload.php';
 | 
			
		||||
 | 
			
		||||
spl_autoload_register(function(string $class) {
 | 
			
		||||
    require_once str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
use Emulator\HabboEnvironment;
 | 
			
		||||
 | 
			
		||||
HabboEnvironment::getInstance()->initialize();
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Core\Logging;
 | 
			
		||||
 | 
			
		||||
enum LogLevel {
 | 
			
		||||
    case Debug;
 | 
			
		||||
    case Info;
 | 
			
		||||
    case Warn;
 | 
			
		||||
    case Fatal;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Core\Logging;
 | 
			
		||||
 | 
			
		||||
class Logger {
 | 
			
		||||
    private const array colorCodes = [
 | 
			
		||||
        'r' => 31,
 | 
			
		||||
        'b' => 34
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    public static function log(LogLevel $level, string $text): void {
 | 
			
		||||
        if (preg_match_all('/\[([a-z]{1,2})]/', $text, $matches)) {
 | 
			
		||||
            foreach ($matches[1] as $code) {
 | 
			
		||||
                $colorCode = self::colorCodes[$code];
 | 
			
		||||
                $text = str_replace(["[$code]", "[/$code]"], ["\033[{$colorCode}m", "\033[0m"], $text);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        echo "[$level->name] $text" . PHP_EOL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function debug(string $text): void {
 | 
			
		||||
        self::log(LogLevel::Debug, $text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function info(string $text): void {
 | 
			
		||||
        self::log(LogLevel::Info, $text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function warn(string $text): void {
 | 
			
		||||
        self::log(LogLevel::Warn, $text);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function fatal(string $text): void {
 | 
			
		||||
        self::log(LogLevel::Fatal, $text);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Encoding;
 | 
			
		||||
 | 
			
		||||
class ByteEncoding {
 | 
			
		||||
    public static function getInt32(array $raw): int{
 | 
			
		||||
 | 
			
		||||
        return ($raw[0] << 24) | ($raw[1] << 16) | ($raw[2] << 8) | $raw[3];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function getInt16(array $raw): int {
 | 
			
		||||
        return (($raw[0] << 8) | $raw[1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function int32ToArray(int $value): array {
 | 
			
		||||
        return [$value >> 24, $value >> 16, $value >> 8, $value];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function int16ToArray(int $value): array {
 | 
			
		||||
        return [$value >> 8, $value];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator;
 | 
			
		||||
 | 
			
		||||
use Emulator\Core\Logging\Logger;
 | 
			
		||||
use Emulator\Messages\MessageHandler;
 | 
			
		||||
use Emulator\Network\Game\GameNetworkServer;
 | 
			
		||||
 | 
			
		||||
class HabboEnvironment {
 | 
			
		||||
    private static ?HabboEnvironment $instance = null;
 | 
			
		||||
 | 
			
		||||
    public function initialize(): void {
 | 
			
		||||
        Logger::info("Starting up [b]HabboEmulator[/b] (PHP Edition) for [r]$_SERVER[USER][/r]");
 | 
			
		||||
 | 
			
		||||
        MessageHandler::getInstance();
 | 
			
		||||
 | 
			
		||||
        GameNetworkServer::getInstance()->start(2096);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function getInstance(): HabboEnvironment {
 | 
			
		||||
        if (self::$instance === null)
 | 
			
		||||
            self::$instance = new self();
 | 
			
		||||
 | 
			
		||||
        return self::$instance;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Messages\Incoming;
 | 
			
		||||
 | 
			
		||||
use Emulator\Encoding\ByteEncoding;
 | 
			
		||||
 | 
			
		||||
class ClientMessage {
 | 
			
		||||
    private readonly array $packet;
 | 
			
		||||
    private readonly int $header;
 | 
			
		||||
    private int $readerIndex;
 | 
			
		||||
 | 
			
		||||
    public function __construct(array $packet) {
 | 
			
		||||
        $this->packet = $packet;
 | 
			
		||||
        $this->readerIndex = 0;
 | 
			
		||||
        $this->header = $this->readInt16();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function readBytes(int $amount): array {
 | 
			
		||||
        $bytes = [];
 | 
			
		||||
        for ($i = 0; $i < $amount && $this->readerIndex < count($this->packet); $i++) {
 | 
			
		||||
            $bytes[$i] = $this->packet[$this->readerIndex++];
 | 
			
		||||
        }
 | 
			
		||||
        return $bytes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function readInt16(): int {
 | 
			
		||||
        return ByteEncoding::getInt16($this->readBytes(2));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function readInt32(): int {
 | 
			
		||||
        return ByteEncoding::getInt32($this->readBytes(4));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function readBoolean(): bool {
 | 
			
		||||
        return $this->packet[$this->readerIndex++] === 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function readString(): string {
 | 
			
		||||
        return call_user_func_array('pack', array_merge(['C*'], $this->readBytes($this->readInt16())));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getHeader(): int{
 | 
			
		||||
        return $this->header;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Messages\Incoming\Handshake;
 | 
			
		||||
 | 
			
		||||
use Emulator\Messages\Incoming\ClientMessage;
 | 
			
		||||
use Emulator\Messages\Incoming\Header;
 | 
			
		||||
use Emulator\Messages\Incoming\IMessageEvent;
 | 
			
		||||
use Emulator\Network\Game\Sessions\Session;
 | 
			
		||||
use Override;
 | 
			
		||||
 | 
			
		||||
class ReleaseVersionMessageEvent implements IMessageEvent {
 | 
			
		||||
    #[Override] function handle(Session $session, ClientMessage $clientMessage): void {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[Override] function getHeader(): Header {
 | 
			
		||||
        return Header::ReleaseVersion;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Messages\Incoming\Handshake;
 | 
			
		||||
 | 
			
		||||
use Emulator\Messages\Incoming\ClientMessage;
 | 
			
		||||
use Emulator\Messages\Incoming\Header;
 | 
			
		||||
use Emulator\Messages\Incoming\IMessageEvent;
 | 
			
		||||
use Emulator\Messages\Outgoing\Handshake\AuthenticatedComposer;
 | 
			
		||||
use Emulator\Network\Game\Sessions\Session;
 | 
			
		||||
use Override;
 | 
			
		||||
 | 
			
		||||
class SecurityTicketMessageEvent implements IMessageEvent {
 | 
			
		||||
    #[Override] function handle(Session $session, ClientMessage $clientMessage): void {
 | 
			
		||||
        $session->sendComposer(new AuthenticatedComposer());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[Override] function getHeader(): Header {
 | 
			
		||||
        return Header::ReleaseVersion;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,471 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Messages\Incoming;
 | 
			
		||||
 | 
			
		||||
enum Header : int
 | 
			
		||||
{
 | 
			
		||||
    case AchievementList = 219;
 | 
			
		||||
    case Authentication = -1;
 | 
			
		||||
    case BotConfiguration = 1986;
 | 
			
		||||
    case BotPickup = 3323;
 | 
			
		||||
    case BotPlace = 1592;
 | 
			
		||||
    case BotSkillSave = 2624;
 | 
			
		||||
    case GetClubOffers = 3285;
 | 
			
		||||
    case GetClubGiftInfo = 487;
 | 
			
		||||
    case GetCatalogIndex = 1195;
 | 
			
		||||
    case GetCatalogPage = 412;
 | 
			
		||||
    case CatalogPurchase = 3492;
 | 
			
		||||
    case CatalogPurchaseGift = 1411;
 | 
			
		||||
    case GetProductOffer = 2594;
 | 
			
		||||
    case ClientLatency = 295;
 | 
			
		||||
    case ClientLatencyMeasure = 96;
 | 
			
		||||
    case ClientPolicy = 26979;
 | 
			
		||||
    case ClientPong = 2596;
 | 
			
		||||
    case ClientToolbarToggle = 2313;
 | 
			
		||||
    case ClientVariables = 1053;
 | 
			
		||||
    case GetCurrentTimingCode = 2912;
 | 
			
		||||
    case DesktopView = 105;
 | 
			
		||||
    case GetBundleDiscountRuleset = 223;
 | 
			
		||||
    case EventTracker = 3457;
 | 
			
		||||
    case FindNewFriends = 516;
 | 
			
		||||
    case FurnitureAliases = 3898;
 | 
			
		||||
    case FurnitureFloorUpdate = 248;
 | 
			
		||||
    case FurnitureMultistate = 99;
 | 
			
		||||
    case FurniturePickup = 3456;
 | 
			
		||||
    case FurniturePlace = 1258;
 | 
			
		||||
    case FurniturePostitPlace = 2248;
 | 
			
		||||
    case FurniturePostitSaveStickyPole = 3283;
 | 
			
		||||
    case FurnitureRandomstate = 3617;
 | 
			
		||||
    case FurnitureWallMultistate = 210;
 | 
			
		||||
    case FurnitureWallUpdate = 168;
 | 
			
		||||
    case GamesInit = 2914;
 | 
			
		||||
    case GamesList = 741;
 | 
			
		||||
    case Acceptgameinvite = 3802;
 | 
			
		||||
    case Gameunloadedmessage = 3207;
 | 
			
		||||
    case Getgameachievementsmessage = 2399;
 | 
			
		||||
    case Getgamestatusmessage = 3171;
 | 
			
		||||
    case Getusergameachievementsmessage = 389;
 | 
			
		||||
    case Joinqueuemessage = 1458;
 | 
			
		||||
    case Leavequeuemessage = 2384;
 | 
			
		||||
    case Resetresolutionachievementmessage = 3144;
 | 
			
		||||
    case Getweeklygamerewardwinners = 1054;
 | 
			
		||||
    case Game2Getaccountgamestatusmessage = 11;
 | 
			
		||||
    case Game2Checkgamedirectorystatusmessage = 3259;
 | 
			
		||||
    case Game2Exitgamemessage = 1445;
 | 
			
		||||
    case Game2Gamechatmessage = 2502;
 | 
			
		||||
    case Game2Loadstagereadymessage = 2415;
 | 
			
		||||
    case Game2Playagainmessage = 3196;
 | 
			
		||||
    case Game2Requestfullstatusupdatemessage = 1598;
 | 
			
		||||
    case Game2Getweeklyfriendsleaderboard = 1232;
 | 
			
		||||
    case Game2Getweeklyleaderboard = 2565;
 | 
			
		||||
    case GetGiftWrappingConfig = 418;
 | 
			
		||||
    case GroupAdminAdd = 2894;
 | 
			
		||||
    case GroupAdminRemove = 722;
 | 
			
		||||
    case GroupCreateOptions = 798;
 | 
			
		||||
    case GroupFavorite = 3549;
 | 
			
		||||
    case GetForumStats = 3149;
 | 
			
		||||
    case GetForumThreads = 873;
 | 
			
		||||
    case GetForumsList = 436;
 | 
			
		||||
    case GetForumMessages = 232;
 | 
			
		||||
    case GetForumThread = 3900;
 | 
			
		||||
    case GetUnreadForumsCount = 2908;
 | 
			
		||||
    case ForumModerateMessage = 286;
 | 
			
		||||
    case ForumModerateThread = 1397;
 | 
			
		||||
    case ForumPostMessage = 3529;
 | 
			
		||||
    case UpdateForumReadMarker = 1855;
 | 
			
		||||
    case UpdateForumSettings = 2214;
 | 
			
		||||
    case ForumUpdateThread = 3045;
 | 
			
		||||
    case GroupInfo = 2991;
 | 
			
		||||
    case GroupDelete = 1134;
 | 
			
		||||
    case GroupMemberRemoveConfirm = 3593;
 | 
			
		||||
    case GroupMemberRemove = 593;
 | 
			
		||||
    case GroupMembers = 312;
 | 
			
		||||
    case GroupMemberships = 367;
 | 
			
		||||
    case GroupRequest = 998;
 | 
			
		||||
    case GroupRequestAccept = 3386;
 | 
			
		||||
    case GroupRequestDecline = 1894;
 | 
			
		||||
    case GroupSettings = 1004;
 | 
			
		||||
    case GroupParts = 813;
 | 
			
		||||
    case GroupBuy = 230;
 | 
			
		||||
    case GroupSaveInformation = 3137;
 | 
			
		||||
    case GroupSaveBadge = 1991;
 | 
			
		||||
    case GroupSaveColors = 1764;
 | 
			
		||||
    case GroupSavePreferences = 3435;
 | 
			
		||||
    case GroupBadges = 21;
 | 
			
		||||
    case GroupUnblockMember = 2864;
 | 
			
		||||
    case GetBadgePointsLimits = 1371;
 | 
			
		||||
    case Requestabadge = 3077;
 | 
			
		||||
    case Getisbadgerequestfulfilled = 1364;
 | 
			
		||||
    case ItemClothingRedeem = 3374;
 | 
			
		||||
    case ItemColorWheelClick = 2144;
 | 
			
		||||
    case ItemDiceClick = 1990;
 | 
			
		||||
    case ItemDiceClose = 1533;
 | 
			
		||||
    case ItemDimmerSave = 1648;
 | 
			
		||||
    case ItemDimmerSettings = 2813;
 | 
			
		||||
    case ItemDimmerToggle = 2296;
 | 
			
		||||
    case ItemExchangeRedeem = 3115;
 | 
			
		||||
    case ItemPaint = 711;
 | 
			
		||||
    case SetObjectData = 3608;
 | 
			
		||||
    case ItemStackHelper = 3839;
 | 
			
		||||
    case MarketplaceConfig = 2597;
 | 
			
		||||
    case AcceptFriend = 137;
 | 
			
		||||
    case MessengerChat = 3567;
 | 
			
		||||
    case DeclineFriend = 2890;
 | 
			
		||||
    case FollowFriend = 3997;
 | 
			
		||||
    case MessengerFriends = 1523;
 | 
			
		||||
    case MessengerInit = 2781;
 | 
			
		||||
    case MessengerRelationships = 2138;
 | 
			
		||||
    case SetRelationshipStatus = 3768;
 | 
			
		||||
    case RemoveFriend = 1689;
 | 
			
		||||
    case RequestFriend = 3157;
 | 
			
		||||
    case GetFriendRequests = 2448;
 | 
			
		||||
    case SendRoomInvite = 1276;
 | 
			
		||||
    case HabboSearch = 1210;
 | 
			
		||||
    case FriendListUpdate = 1419;
 | 
			
		||||
    case ModToolUserInfo = 3295;
 | 
			
		||||
    case GetUserFlatCats = 3027;
 | 
			
		||||
    case NavigatorInit = 2110;
 | 
			
		||||
    case NavigatorSearch = 249;
 | 
			
		||||
    case NavigatorSearchClose = 1834;
 | 
			
		||||
    case NavigatorSearchOpen = 637;
 | 
			
		||||
    case NavigatorSearchSave = 2226;
 | 
			
		||||
    case GetUserEventCats = 1782;
 | 
			
		||||
    case NavigatorSettingsSave = 3159;
 | 
			
		||||
    case NavigatorCategoryListMode = 1202;
 | 
			
		||||
    case NavigatorDeleteSavedSearch = 1954;
 | 
			
		||||
    case PetInfo = 2934;
 | 
			
		||||
    case PetPickup = 1581;
 | 
			
		||||
    case PetPlace = 2647;
 | 
			
		||||
    case PetRespect = 3202;
 | 
			
		||||
    case PetRide = 1036;
 | 
			
		||||
    case PetMove = 3449;
 | 
			
		||||
    case PetOpenPackage = 3698;
 | 
			
		||||
    case PetSelected = 549;
 | 
			
		||||
    case PetsBreed = 1638;
 | 
			
		||||
    case PetCancelBreeding = 2713;
 | 
			
		||||
    case PetConfirmBreeding = 3382;
 | 
			
		||||
    case GetPetTrainingPanel = 2161;
 | 
			
		||||
    case RecyclerPrizes = 398;
 | 
			
		||||
    case RecyclerStatus = 1342;
 | 
			
		||||
    case RecyclerItems = 2771;
 | 
			
		||||
    case ReleaseVersion = 4000;
 | 
			
		||||
    case CallForHelp = 1691;
 | 
			
		||||
    case RoomAmbassadorAlert = 2996;
 | 
			
		||||
    case RoomBanGive = 1477;
 | 
			
		||||
    case RoomBanList = 2267;
 | 
			
		||||
    case RoomBanRemove = 992;
 | 
			
		||||
    case RoomCreate = 2752;
 | 
			
		||||
    case RoomDelete = 532;
 | 
			
		||||
    case RoomDoorbell = 1644;
 | 
			
		||||
    case RoomEnter = 2312;
 | 
			
		||||
    case RoomFavorite = 3817;
 | 
			
		||||
    case RoomFavoriteRemove = 309;
 | 
			
		||||
    case CanCreateRoom = 2128;
 | 
			
		||||
    case CancelRoomEvent = 2725;
 | 
			
		||||
    case EditRoomEvent = 3991;
 | 
			
		||||
    case CompetitionRoomSearch = 433;
 | 
			
		||||
    case ForwardToRandomPromotedRoom = 10;
 | 
			
		||||
    case ForwardToSomeRoom = 1703;
 | 
			
		||||
    case GetCategoriesWithUserCount = 3782;
 | 
			
		||||
    case GetGuestRoom = 2230;
 | 
			
		||||
    case GetOfficialRooms = 1229;
 | 
			
		||||
    case GetPopularRoomTags = 826;
 | 
			
		||||
    case GuildBaseSearch = 2930;
 | 
			
		||||
    case MyFavouriteRoomsSearch = 2578;
 | 
			
		||||
    case MyFrequentRoomHistorySearch = 1002;
 | 
			
		||||
    case MyFriendsRoomSearch = 2266;
 | 
			
		||||
    case MyGuildBasesSearch = 39;
 | 
			
		||||
    case MyRecommendedRooms = 2537;
 | 
			
		||||
    case MyRoomHistorySearch = 2264;
 | 
			
		||||
    case MyRoomRightsSearch = 272;
 | 
			
		||||
    case MyRoomsSearch = 2277;
 | 
			
		||||
    case PopularRoomsSearch = 2758;
 | 
			
		||||
    case RoomAdEventTabClicked = 2412;
 | 
			
		||||
    case RoomAdEventTabViewed = 2668;
 | 
			
		||||
    case RoomAdSearch = 2809;
 | 
			
		||||
    case RoomTextSearch = 3943;
 | 
			
		||||
    case RoomsWhereMyFriendsAre = 1786;
 | 
			
		||||
    case RoomsWithHighestScoreSearch = 2939;
 | 
			
		||||
    case SetRoomSessionTags = 3305;
 | 
			
		||||
    case UpdateRoomThumbnail = 2468;
 | 
			
		||||
    case RoomKick = 1320;
 | 
			
		||||
    case RoomLike = 3582;
 | 
			
		||||
    case RoomModel = 2300;
 | 
			
		||||
    case GetOccupiedTiles = 1687;
 | 
			
		||||
    case GetRoomEntryTile = 3559;
 | 
			
		||||
    case RoomModelSave = 875;
 | 
			
		||||
    case RoomMute = 3637;
 | 
			
		||||
    case RoomMuteUser = 3485;
 | 
			
		||||
    case RoomRightsGive = 808;
 | 
			
		||||
    case RoomRightsList = 3385;
 | 
			
		||||
    case RoomRightsRemove = 2064;
 | 
			
		||||
    case RoomRightsRemoveAll = 2683;
 | 
			
		||||
    case RoomRightsRemoveOwn = 3182;
 | 
			
		||||
    case RoomSettings = 3129;
 | 
			
		||||
    case RoomSettingsSave = 1969;
 | 
			
		||||
    case RoomSettingsUpdateRoomCategoryAndTrade = 1265;
 | 
			
		||||
    case RoomStaffPick = 1918;
 | 
			
		||||
    case RoomFilterWords = 1911;
 | 
			
		||||
    case RoomFilterWordsModify = 3001;
 | 
			
		||||
    case Mysteryboxwaitingcanceledmessage = 2012;
 | 
			
		||||
    case MysteryboxOpenTrophy = 3074;
 | 
			
		||||
    case SecurityMachine = 2490;
 | 
			
		||||
    case SecurityTicket = 2419;
 | 
			
		||||
    case Trade = 1481;
 | 
			
		||||
    case TradeAccept = 3863;
 | 
			
		||||
    case TradeCancel = 2341;
 | 
			
		||||
    case TradeClose = 2551;
 | 
			
		||||
    case TradeConfirm = 2760;
 | 
			
		||||
    case TradeItem = 3107;
 | 
			
		||||
    case TradeItemRemove = 3845;
 | 
			
		||||
    case TradeItems = 1263;
 | 
			
		||||
    case TradeUnaccept = 1444;
 | 
			
		||||
    case UnitAction = 2456;
 | 
			
		||||
    case UnitChat = 1314;
 | 
			
		||||
    case UnitChatShout = 2085;
 | 
			
		||||
    case UnitChatWhisper = 1543;
 | 
			
		||||
    case UnitDance = 2080;
 | 
			
		||||
    case UnitDropHandItem = 2814;
 | 
			
		||||
    case UnitGiveHanditem = 2941;
 | 
			
		||||
    case UnitLook = 3301;
 | 
			
		||||
    case UnitPosture = 2235;
 | 
			
		||||
    case UnitSign = 1975;
 | 
			
		||||
    case UnitTyping = 1597;
 | 
			
		||||
    case UnitTypingStop = 1474;
 | 
			
		||||
    case UnitWalk = 3320;
 | 
			
		||||
    case UserBadges = 2769;
 | 
			
		||||
    case UserBadgesCurrent = 2091;
 | 
			
		||||
    case UserBadgesCurrentUpdate = 644;
 | 
			
		||||
    case UserBots = 3848;
 | 
			
		||||
    case UserCurrency = 273;
 | 
			
		||||
    case UserEffectActivate = 2959;
 | 
			
		||||
    case UserEffectEnable = 1752;
 | 
			
		||||
    case UserFigure = 2730;
 | 
			
		||||
    case UserFurniture = 3150; // sent when in room
 | 
			
		||||
    case Requestfurniinventorywhennotinroom = 3500; // sent when not in room
 | 
			
		||||
    case UserHomeRoom = 1740;
 | 
			
		||||
    case UserInfo = 357;
 | 
			
		||||
    case UserMotto = 2228;
 | 
			
		||||
    case UserIgnored = 3878;
 | 
			
		||||
    case UserPets = 3095;
 | 
			
		||||
    case UserProfile = 3265;
 | 
			
		||||
    case UserProfileByName = 2249;
 | 
			
		||||
    case UserRespect = 2694;
 | 
			
		||||
    case GetSoundSettings = 2388;
 | 
			
		||||
    case UserSettingsCamera = 1461;
 | 
			
		||||
    case UserSettingsChatStyle = 1030;
 | 
			
		||||
    case UserSettingsInvites = 1086;
 | 
			
		||||
    case UserSettingsOldChat = 1262;
 | 
			
		||||
    case UserSettingsVolume = 1367;
 | 
			
		||||
    case UserSubscription = 3166;
 | 
			
		||||
    case GetWardrobe = 2742;
 | 
			
		||||
    case SaveWardrobeOutfit = 800;
 | 
			
		||||
    case UserTags = 17;
 | 
			
		||||
    case PeerUsersClassification = 1160;
 | 
			
		||||
    case UserClassification = 2285;
 | 
			
		||||
    case VisitUser = 2970;
 | 
			
		||||
    case WiredActionSave = 2281;
 | 
			
		||||
    case WiredApplySnapshot = 3373;
 | 
			
		||||
    case WiredConditionSave = 3203;
 | 
			
		||||
    case WiredOpen = 768;
 | 
			
		||||
    case WiredTriggerSave = 1520;
 | 
			
		||||
    case GetItemData = 3964;
 | 
			
		||||
    case OneWayDoorClick = 2765;
 | 
			
		||||
    case RemoveWallItem = 3336;
 | 
			
		||||
    case SetItemData = 3666;
 | 
			
		||||
    case CatalogRedeemVoucher = 339;
 | 
			
		||||
    case RoomTonerApply = 2880;
 | 
			
		||||
    case FriendFurniConfirmLock = 3775;
 | 
			
		||||
    case MannequinSaveName = 2850;
 | 
			
		||||
    case MannequinSaveLook = 2209;
 | 
			
		||||
    case PresentOpenPresent = 3558;
 | 
			
		||||
    case CatalogSelectVipGift = 2276;
 | 
			
		||||
    case UserIgnoreId = 3314;
 | 
			
		||||
    case UserIgnore = 1117;
 | 
			
		||||
    case UserUnignore = 2061;
 | 
			
		||||
    case ModtoolRequestRoomInfo = 707;
 | 
			
		||||
    case ModtoolChangeRoomSettings = 3260;
 | 
			
		||||
    case ModtoolRequestUserChatlog = 1391;
 | 
			
		||||
    case ModtoolRequestRoomChatlog = 2587;
 | 
			
		||||
    case ModtoolSanctionAlert = 229;
 | 
			
		||||
    case ModtoolSanctionBan = 2766;
 | 
			
		||||
    case ModtoolSanctionKick = 2582;
 | 
			
		||||
    case ModtoolSanctionTradelock = 3742;
 | 
			
		||||
    case ModtoolAlertevent = 1840;
 | 
			
		||||
    case ModtoolSanctionMute = 1945;
 | 
			
		||||
    case ModtoolRequestUserRooms = 3526;
 | 
			
		||||
    case ModtoolRoomAlert = 3842;
 | 
			
		||||
    case ModtoolPreferences = 31;
 | 
			
		||||
    case CloseIssueDefaultAction = 2717;
 | 
			
		||||
    case CloseIssues = 2067;
 | 
			
		||||
    case DefaultSanction = 1681;
 | 
			
		||||
    case GetCfhChatlog = 211;
 | 
			
		||||
    case ModtoolSanction = 1392;
 | 
			
		||||
    case PickIssues = 15;
 | 
			
		||||
    case ReleaseIssues = 1572;
 | 
			
		||||
    case ConvertGlobalRoomId = 314;
 | 
			
		||||
    case RequestSellItem = 848;
 | 
			
		||||
    case RequestMarketplaceItemStats = 3288;
 | 
			
		||||
    case MarketplaceSellItem = 3447;
 | 
			
		||||
    case MarketplaceRequestOwnItems = 2105;
 | 
			
		||||
    case MarketplaceTakeBackItem = 434;
 | 
			
		||||
    case MarketplaceRedeemCredits = 2650;
 | 
			
		||||
    case MarketplaceRequestOffers = 2407;
 | 
			
		||||
    case MarketplaceBuyOffer = 1603;
 | 
			
		||||
    case MarketplaceBuyTokens = 1866;
 | 
			
		||||
    case CatalogRequesetPetBreeds = 1756;
 | 
			
		||||
    case ApproveName = 2109;
 | 
			
		||||
    case UnitGiveHanditemPet = 2768;
 | 
			
		||||
    case PetSupplement = 749;
 | 
			
		||||
    case FurnitureGroupInfo = 2651;
 | 
			
		||||
    case AchievementResolutionOpen = 359;
 | 
			
		||||
    case UsePetProduct = 1328;
 | 
			
		||||
    case RemovePetSaddle = 186;
 | 
			
		||||
    case TogglePetRiding = 1472;
 | 
			
		||||
    case TogglePetBreeding = 3379;
 | 
			
		||||
    case UnseenResetCategory = 3493;
 | 
			
		||||
    case UnseenResetItems = 2343;
 | 
			
		||||
    case CommunityGoalVoteComposer = 3536;
 | 
			
		||||
    case GetPromoArticles = 1827;
 | 
			
		||||
    case AcceptQuest = 3604;
 | 
			
		||||
    case ActivateQuest = 793;
 | 
			
		||||
    case CancelQuest = 3133;
 | 
			
		||||
    case FriendRequestQuestComplete = 1148;
 | 
			
		||||
    case GetCommunityGoalEarnedPrizes = 2688;
 | 
			
		||||
    case GetCommunityGoalHallOfFame = 2167;
 | 
			
		||||
    case GetCommunityGoalProgress = 1145;
 | 
			
		||||
    case GetConcurrentUsersGoalProgress = 1343;
 | 
			
		||||
    case GetConcurrentUsersReward = 3872;
 | 
			
		||||
    case GetDailyQuest = 2486;
 | 
			
		||||
    case GetQuests = 3333;
 | 
			
		||||
    case GetSeasonalQuestsOnly = 1190;
 | 
			
		||||
    case OpenQuestTracker = 2750;
 | 
			
		||||
    case RedeemCommunityGoalPrize = 90;
 | 
			
		||||
    case RejectQuest = 2397;
 | 
			
		||||
    case StartCampaign = 1697;
 | 
			
		||||
    case GetBonusRareInfo = 957;
 | 
			
		||||
    case Craft = 3591;
 | 
			
		||||
    case CraftSecret = 1251;
 | 
			
		||||
    case GetCraftableProducts = 633;
 | 
			
		||||
    case GetCraftingRecipe = 1173;
 | 
			
		||||
    case GetCraftingRecipesAvailable = 3086;
 | 
			
		||||
    case PhotoCompetition = 3959;
 | 
			
		||||
    case PublishPhoto = 2068;
 | 
			
		||||
    case PurchasePhoto = 2408;
 | 
			
		||||
    case RenderRoom = 3226;
 | 
			
		||||
    case RenderRoomThumbnail = 1982;
 | 
			
		||||
    case RequestCameraConfiguration = 796;
 | 
			
		||||
    case AddJukeboxDisk = 753;
 | 
			
		||||
    case GetJukeboxPlaylist = 1435;
 | 
			
		||||
    case GetNowPlaying = 1325;
 | 
			
		||||
    case GetOfficialSongId = 3189;
 | 
			
		||||
    case GetSongInfo = 3082;
 | 
			
		||||
    case GetSoundMachinePlaylist = 3498;
 | 
			
		||||
    case GetUserSongDisks = 2304;
 | 
			
		||||
    case RemoveJukeboxDisk = 3050;
 | 
			
		||||
    case InterstitialShown = 1109;
 | 
			
		||||
    case GetInterstitial = 2519;
 | 
			
		||||
    case ChangeUsername = 2977;
 | 
			
		||||
    case CheckUsername = 3950;
 | 
			
		||||
    case OpenCampaignCalendarDoorStaff = 3889;
 | 
			
		||||
    case OpenCampaignCalendarDoor = 2257;
 | 
			
		||||
    case BuildersClubPlaceRoomItem = 1051;
 | 
			
		||||
    case BuildersClubPlaceWallItem = 462;
 | 
			
		||||
    case BuildersClubQueryFurniCount = 2529;
 | 
			
		||||
    case GetCatalogPageExpiration = 742;
 | 
			
		||||
    case GetCatalogPageWithEarliestExp = 3135;
 | 
			
		||||
    case GetDirectClubBuyAvailable = 801;
 | 
			
		||||
    case GetHabboBasicMembershipExtendOffer = 603;
 | 
			
		||||
    case GetHabboClubExtendOffer = 2462;
 | 
			
		||||
    case GetIsOfferGiftable = 1347;
 | 
			
		||||
    case GetLimitedOfferAppearingNext = 410;
 | 
			
		||||
    case GetNextTargetedOffer = 596;
 | 
			
		||||
    case GetRoomAdPurchaseInfo = 1075;
 | 
			
		||||
    case GetSeasonalCalendarDailyOffer = 3257;
 | 
			
		||||
    case GetTargetedOffer = 2487;
 | 
			
		||||
    case MarkCatalogNewAdditionsPageOpened = 2150;
 | 
			
		||||
    case PurchaseBasicMembershipExtension = 2735;
 | 
			
		||||
    case PurchaseRoomAd = 777;
 | 
			
		||||
    case PurchaseTargetedOffer = 1826;
 | 
			
		||||
    case PurchaseVipMembershipExtension = 3407;
 | 
			
		||||
    case RoomAdPurchaseInitiated = 2283;
 | 
			
		||||
    case SetTargettedOfferState = 2041;
 | 
			
		||||
    case ShopTargetedOfferViewed = 3483;
 | 
			
		||||
    case HelperTalentTrack = 196;
 | 
			
		||||
    case TalentTrackGetLevel = 2127;
 | 
			
		||||
    case ForwardToACompetitionRoom = 172;
 | 
			
		||||
    case ForwardToASubmittableRoom = 1450;
 | 
			
		||||
    case ForwardToRandomCompetitionRoom = 865;
 | 
			
		||||
    case GetIsUserPartOfCompetition = 2077;
 | 
			
		||||
    case GetSecondsUntil = 271;
 | 
			
		||||
    case RoomCompetitionInit = 1334;
 | 
			
		||||
    case SubmitRoomToCompetition = 2595;
 | 
			
		||||
    case VoteForRoom = 143;
 | 
			
		||||
    case GetGift = 2436;
 | 
			
		||||
    case ResetPhoneNumberState = 2741;
 | 
			
		||||
    case SetPhoneNumberVerificationStatus = 1379;
 | 
			
		||||
    case TryPhoneNumber = 790;
 | 
			
		||||
    case VerifyCode = 2721;
 | 
			
		||||
    case ControlYoutubeDisplayPlayback = 3005;
 | 
			
		||||
    case GetYoutubeDisplayStatus = 336;
 | 
			
		||||
    case SetYoutubeDisplayPlaylist = 2069;
 | 
			
		||||
    case GoToFlat = 685;
 | 
			
		||||
    case ChangeQueue = 3093;
 | 
			
		||||
    case CallForHelpFromForumMessage = 1412;
 | 
			
		||||
    case CallForHelpFromForumThread = 534;
 | 
			
		||||
    case CallForHelpFromIm = 2950;
 | 
			
		||||
    case CallForHelpFromPhoto = 2492;
 | 
			
		||||
    case CallForHelpFromSelfie = 2755;
 | 
			
		||||
    case ChatReviewGuideDecides = 3365;
 | 
			
		||||
    case ChatReviewGuideDetached = 2501;
 | 
			
		||||
    case ChatReviewGuideVote = 3961;
 | 
			
		||||
    case ChatReviewSessionCreate = 3060;
 | 
			
		||||
    case DeletePendingCallsForHelp = 3605;
 | 
			
		||||
    case GetCfhStatus = 2746;
 | 
			
		||||
    case GetFaqCategory = 3445;
 | 
			
		||||
    case GetFaqText = 1849;
 | 
			
		||||
    case GetGuideReportingStatus = 3786;
 | 
			
		||||
    case GetPendingCallsForHelp = 3267;
 | 
			
		||||
    case GetQuizQuestions = 1296;
 | 
			
		||||
    case GuideSessionCreate = 3338;
 | 
			
		||||
    case GuideSessionFeedback = 477;
 | 
			
		||||
    case GuideSessionGetRequesterRoom = 1052;
 | 
			
		||||
    case GuideSessionGuideDecides = 1424;
 | 
			
		||||
    case GuideSessionInviteRequester = 234;
 | 
			
		||||
    case GuideSessionIsTyping = 519;
 | 
			
		||||
    case GuideSessionMessage = 3899;
 | 
			
		||||
    case GuideSessionOnDutyUpdate = 1922;
 | 
			
		||||
    case GuideSessionReport = 3969;
 | 
			
		||||
    case GuideSessionRequesterCancels = 291;
 | 
			
		||||
    case GuideSessionResolved = 887;
 | 
			
		||||
    case PostQuizAnswers = 3720;
 | 
			
		||||
    case SearchFaqs = 2031;
 | 
			
		||||
    case PollAnswer = 3505;
 | 
			
		||||
    case PollReject = 1773;
 | 
			
		||||
    case PollStart = 109;
 | 
			
		||||
    case PollVoteCounter = 6200;
 | 
			
		||||
    case Disconnect = 2445;
 | 
			
		||||
    case ScrGetKickbackInfo = 869;
 | 
			
		||||
    case CompostPlant = 3835;
 | 
			
		||||
    case HarvestPet = 1521;
 | 
			
		||||
    case SetClothingChangeData = 924;
 | 
			
		||||
    case GroupUnfavorite = 1820;
 | 
			
		||||
    case NewUserExperienceGetGifts = 1822;
 | 
			
		||||
    case NewUserExperienceScriptProceed = 1299;
 | 
			
		||||
    case HandshakeInitDiffie = 3110;
 | 
			
		||||
    case HandshakeCompleteDiffie = 773;
 | 
			
		||||
    case WelcomeOpenGift = 2638;
 | 
			
		||||
    case WelcomeGiftChangeEmail = 66;
 | 
			
		||||
    case EmailGetStatus = 2557;
 | 
			
		||||
    case EmailChange = 3965;
 | 
			
		||||
    case ApproveAllMembershipRequests = 882;
 | 
			
		||||
    case RentableSpaceCancelRent = 1667;
 | 
			
		||||
    case RentableSpaceRent = 2946;
 | 
			
		||||
    case RentableSpaceStatus = 872;
 | 
			
		||||
    case TrackingPerformanceLog = 3230;
 | 
			
		||||
    case TrackingLagWarningReport = 3847;
 | 
			
		||||
    case RoomDirectoryRoomNetworkOpenConnection = 3736;
 | 
			
		||||
    case RentableExtendRentOrBuyoutStripItem = 2115;
 | 
			
		||||
    case RentableExtendRentOrBuyoutFurni = 1071;
 | 
			
		||||
    case RentableGetRentOrBuyoutOffer = 2518;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Messages\Incoming;
 | 
			
		||||
 | 
			
		||||
use Emulator\Network\Game\Sessions\Session;
 | 
			
		||||
 | 
			
		||||
interface IMessageEvent {
 | 
			
		||||
    function handle(Session $session, ClientMessage $clientMessage): void;
 | 
			
		||||
    function getHeader(): Header;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Messages;
 | 
			
		||||
 | 
			
		||||
use Emulator\Core\Logging\Logger;
 | 
			
		||||
use Emulator\Messages\Incoming\ClientMessage;
 | 
			
		||||
use Emulator\Messages\Incoming\Handshake\ReleaseVersionMessageEvent;
 | 
			
		||||
use Emulator\Messages\Incoming\Handshake\SecurityTicketMessageEvent;
 | 
			
		||||
use Emulator\Messages\Incoming\Header;
 | 
			
		||||
use Emulator\Network\Game\Sessions\Session;
 | 
			
		||||
use SplObjectStorage;
 | 
			
		||||
 | 
			
		||||
class MessageHandler {
 | 
			
		||||
    private static ?MessageHandler $instance = null;
 | 
			
		||||
    private SplObjectStorage $handlers;
 | 
			
		||||
 | 
			
		||||
    public function __construct() {
 | 
			
		||||
        $this->handlers = new SplObjectStorage();
 | 
			
		||||
        $this->handlers[Header::ReleaseVersion] = new ReleaseVersionMessageEvent();
 | 
			
		||||
        $this->handlers[Header::SecurityTicket] = new SecurityTicketMessageEvent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function handlePacket(Session $session, ClientMessage $request): void {
 | 
			
		||||
        if (($header = Header::tryFrom($request->getHeader()))) {
 | 
			
		||||
            if ($this->handlers->contains($header)) {
 | 
			
		||||
                $this->handlers[$header]->handle($session, $request);
 | 
			
		||||
            } else {
 | 
			
		||||
                Logger::warn("[{$request->getHeader()}] [$header->name] - Unregistered!");
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            Logger::warn("[{$request->getHeader()}] - Unregistered!");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function getInstance(): MessageHandler {
 | 
			
		||||
        if (self::$instance === null)
 | 
			
		||||
            self::$instance = new self();
 | 
			
		||||
 | 
			
		||||
        return self::$instance;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Messages\Outgoing\Handshake;
 | 
			
		||||
 | 
			
		||||
use Emulator\Messages\Outgoing\Header;
 | 
			
		||||
use Emulator\Messages\Outgoing\IMessageComposer;
 | 
			
		||||
use Emulator\Messages\Outgoing\ServerMessage;
 | 
			
		||||
use Override;
 | 
			
		||||
 | 
			
		||||
class AuthenticatedComposer implements IMessageComposer
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    #[Override] function compose(ServerMessage $message): void {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[Override] function getHeader(): Header {
 | 
			
		||||
        return Header::Authenticated;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,467 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Messages\Outgoing;
 | 
			
		||||
 | 
			
		||||
enum Header : int {
 | 
			
		||||
case AchievementList = 305;
 | 
			
		||||
case Authenticated = 2491;
 | 
			
		||||
case Authentication = -1;
 | 
			
		||||
case AvailabilityStatus = 2033;
 | 
			
		||||
case ClubOffers = 2405;
 | 
			
		||||
case CatalogPage = 804;
 | 
			
		||||
case CatalogPageList = 1032;
 | 
			
		||||
case CatalogPurchaseOk = 869;
 | 
			
		||||
case CatalogPurchaseError = 1404;
 | 
			
		||||
case CatalogPurchaseNotAllowed = 3770;
 | 
			
		||||
case ProductOffer = 3388;
 | 
			
		||||
case LimitedSoldOut = 377;
 | 
			
		||||
case CatalogPublished = 1866;
 | 
			
		||||
case CfhResultMessage = 3635;
 | 
			
		||||
case ClientLatency = 10;
 | 
			
		||||
case ClientPing = 3928;
 | 
			
		||||
case DesktopView = 122;
 | 
			
		||||
case BundleDiscountRuleset = 2347;
 | 
			
		||||
case FirstLoginOfDay = 793;
 | 
			
		||||
case FurnitureAliases = 1723;
 | 
			
		||||
case FurnitureData = 2547;
 | 
			
		||||
case FurnitureFloor = 1778;
 | 
			
		||||
case FurnitureFloorAdd = 1534;
 | 
			
		||||
case FurnitureFloorRemove = 2703;
 | 
			
		||||
case FurnitureFloorUpdate = 3776;
 | 
			
		||||
case FurnitureItemdata = 2202;
 | 
			
		||||
case FurnitureState = 2376;
 | 
			
		||||
case FurnitureGroupContextMenuInfo = 3293;
 | 
			
		||||
case FurniturePostitStickyPoleOpen = 2366;
 | 
			
		||||
case GameCenterAchievements = 2265;
 | 
			
		||||
case GameCenterGameList = 222;
 | 
			
		||||
case GameCenterStatus = 2893;
 | 
			
		||||
case GameCenterInArenaQueue = 872;
 | 
			
		||||
case GameCenterStopCounter = 3191;
 | 
			
		||||
case GameCenterUserLeftGame = 3138;
 | 
			
		||||
case GameCenterDirectoryStatus = 2246;
 | 
			
		||||
case GameCenterStartingGameFailed = 2142;
 | 
			
		||||
case GameCenterJoiningFailed = 1730;
 | 
			
		||||
case Gamestatusmessage = 3805;
 | 
			
		||||
case Gameachievements = 1689;
 | 
			
		||||
case Gameinvite = 904;
 | 
			
		||||
case Joiningqueuefailed = 3035;
 | 
			
		||||
case Joinedqueuemessage = 2260;
 | 
			
		||||
case Leftqueue = 1477;
 | 
			
		||||
case LoadGameUrl = 2624;
 | 
			
		||||
case Loadgame = 3654;
 | 
			
		||||
case Unloadgame = 1715;
 | 
			
		||||
case Achievementresolutioncompleted = 740;
 | 
			
		||||
case Achievementresolutionprogress = 3370;
 | 
			
		||||
case Achievementresolutions = 66;
 | 
			
		||||
case GenericAlert = 3801;
 | 
			
		||||
case ModeratorMessage = 2030;
 | 
			
		||||
case GenericError = 1600;
 | 
			
		||||
case GiftWrapperConfig = 2234;
 | 
			
		||||
case GroupBadges = 2402;
 | 
			
		||||
case GroupCreateOptions = 2159;
 | 
			
		||||
case GroupForumData = 3011;
 | 
			
		||||
case GroupForumList = 3001;
 | 
			
		||||
case GroupForumThreads = 1073;
 | 
			
		||||
case GroupForumPost = 2049;
 | 
			
		||||
case GroupForumPostThread = 1862;
 | 
			
		||||
case GroupForumThreadMessages = 509;
 | 
			
		||||
case GroupForumUnreadCount = 2379;
 | 
			
		||||
case GroupForumUpdateMessage = 324;
 | 
			
		||||
case GroupForumUpdateThread = 2528;
 | 
			
		||||
case GroupInfo = 1702;
 | 
			
		||||
case GroupList = 420;
 | 
			
		||||
case GroupMember = 265;
 | 
			
		||||
case GroupMembers = 1200;
 | 
			
		||||
case GroupMembersRefresh = 2445;
 | 
			
		||||
case GroupMemberRemoveConfirm = 1876;
 | 
			
		||||
case GroupPurchased = 2808;
 | 
			
		||||
case GroupSettings = 3965;
 | 
			
		||||
case GroupBadgeParts = 2238;
 | 
			
		||||
case GroupMembershipRequested = 1180;
 | 
			
		||||
case GroupDetailsChanged = 1459;
 | 
			
		||||
case GroupHabboJoinFailed = 762;
 | 
			
		||||
case GuildEditFailed = 3988;
 | 
			
		||||
case GuildMemberMgmtFailed = 818;
 | 
			
		||||
case ItemDimmerSettings = 2710;
 | 
			
		||||
case ItemStackHelper = 2816;
 | 
			
		||||
case ItemWall = 1369;
 | 
			
		||||
case ItemWallAdd = 2187;
 | 
			
		||||
case ItemWallRemove = 3208;
 | 
			
		||||
case ItemWallUpdate = 2009;
 | 
			
		||||
case MarketplaceConfig = 1823;
 | 
			
		||||
case MessengerAcceptFriends = 896;
 | 
			
		||||
case MessengerChat = 1587;
 | 
			
		||||
case MessengerFindFriends = 1210;
 | 
			
		||||
case MessengerFollowFailed = 3048;
 | 
			
		||||
case MessengerFriendNotification = 3082;
 | 
			
		||||
case MessengerFriends = 3130;
 | 
			
		||||
case MessengerInit = 1605;
 | 
			
		||||
case MessengerInstanceMessageError = 3359;
 | 
			
		||||
case MessengerInvite = 3870;
 | 
			
		||||
case MessengerInviteError = 462;
 | 
			
		||||
case MessengerMinimailCount = 2803;
 | 
			
		||||
case MessengerMinimailNew = 1911;
 | 
			
		||||
case MessengerRelationships = 2016;
 | 
			
		||||
case MessengerRequest = 2219;
 | 
			
		||||
case MessengerRequestError = 892;
 | 
			
		||||
case MessengerRequests = 280;
 | 
			
		||||
case MessengerSearch = 973;
 | 
			
		||||
case MessengerUpdate = 2800;
 | 
			
		||||
case ModerationTool = 2696;
 | 
			
		||||
case ModerationUserInfo = 2866;
 | 
			
		||||
case MotdMessages = 2035;
 | 
			
		||||
case NavigatorCategories = 1562;
 | 
			
		||||
case NavigatorCollapsed = 1543;
 | 
			
		||||
case NavigatorEventCategories = 3244;
 | 
			
		||||
case NavigatorLifted = 3104;
 | 
			
		||||
case NavigatorMetadata = 3052;
 | 
			
		||||
case NavigatorOpenRoomCreator = 2064;
 | 
			
		||||
case NavigatorSearch = 2690;
 | 
			
		||||
case NavigatorSearches = 3984;
 | 
			
		||||
case NavigatorSettings = 518;
 | 
			
		||||
case ThumbnailUpdateResult = 1927;
 | 
			
		||||
case CanCreateRoom = 378;
 | 
			
		||||
case CategoriesWithVisitorCount = 1455;
 | 
			
		||||
case CompetitionRoomsData = 3954;
 | 
			
		||||
case ConvertedRoomId = 1331;
 | 
			
		||||
case GuestRoomSearchResult = 52;
 | 
			
		||||
case NotificationList = 1992;
 | 
			
		||||
case NotificationOfferRewardDelivered = 2125;
 | 
			
		||||
case NotificationSimpleAlert = 5100;
 | 
			
		||||
case NotificationElementPointer = 1787;
 | 
			
		||||
case PetFigureUpdate = 1924;
 | 
			
		||||
case PetInfo = 2901;
 | 
			
		||||
case PetTrainingPanel = 1164;
 | 
			
		||||
case PetLevelUpdate = 2824;
 | 
			
		||||
case PetScratchFailed = 1130;
 | 
			
		||||
case PetOpenPackageRequested = 2380;
 | 
			
		||||
case PetOpenPackageResult = 546;
 | 
			
		||||
case PetBreeding = 1746;
 | 
			
		||||
case PetConfirmBreedingResult = 1625;
 | 
			
		||||
case PetGoToBreedingNestFailure = 2621;
 | 
			
		||||
case PetNestBreedingSuccess = 2527;
 | 
			
		||||
case PetConfirmBreedingRequest = 634;
 | 
			
		||||
case PetBreedingResult = 1553;
 | 
			
		||||
case RecyclerPrizes = 3164;
 | 
			
		||||
case RecyclerStatus = 3433;
 | 
			
		||||
case RecyclerFinished = 468;
 | 
			
		||||
case RoomBanList = 1869;
 | 
			
		||||
case RoomBanRemove = 3429;
 | 
			
		||||
case RoomCreated = 1304;
 | 
			
		||||
case RoomDoorbell = 2309;
 | 
			
		||||
case RoomDoorbellAccepted = 3783;
 | 
			
		||||
case RoomDoorbellRejected = 878;
 | 
			
		||||
case RoomEnter = 758;
 | 
			
		||||
case RoomEnterError = 899;
 | 
			
		||||
case RoomForward = 160;
 | 
			
		||||
case RoomHeightMap = 2753;
 | 
			
		||||
case RoomHeightMapUpdate = 558;
 | 
			
		||||
case RoomInfo = 687;
 | 
			
		||||
case RoomInfoOwner = 749;
 | 
			
		||||
case RoomModel = 1301;
 | 
			
		||||
case RoomModelBlockedTiles = 3990;
 | 
			
		||||
case RoomModelDoor = 1664;
 | 
			
		||||
case RoomModelName = 2031;
 | 
			
		||||
case RoomMuted = 2533;
 | 
			
		||||
case RoomPaint = 2454;
 | 
			
		||||
case RoomPromotion = 2274;
 | 
			
		||||
case RoomQueueStatus = 2208;
 | 
			
		||||
case RoomRights = 780;
 | 
			
		||||
case RoomRightsClear = 2392;
 | 
			
		||||
case RoomRightsList = 1284;
 | 
			
		||||
case RoomRightsListAdd = 2088;
 | 
			
		||||
case RoomRightsListRemove = 1327;
 | 
			
		||||
case RoomRightsOwner = 339;
 | 
			
		||||
case RoomRolling = 3207;
 | 
			
		||||
case RoomScore = 482;
 | 
			
		||||
case RoomSettings = 1498;
 | 
			
		||||
case RoomSettingsChat = 1191;
 | 
			
		||||
case RoomSettingsSave = 948;
 | 
			
		||||
case RoomSettingsSaveError = 1555;
 | 
			
		||||
case RoomInfoUpdated = 3297;
 | 
			
		||||
case RoomSpectator = 1033;
 | 
			
		||||
case RoomThickness = 3547;
 | 
			
		||||
case RoomGetFilterWords = 2937;
 | 
			
		||||
case RoomMessageNotification = 1634;
 | 
			
		||||
case RoomPopularTagsResult = 2012;
 | 
			
		||||
case InfoFeedEnable = 3284;
 | 
			
		||||
case SecurityMachine = 1488;
 | 
			
		||||
case MysteryBoxKeys = 2833;
 | 
			
		||||
case Gotmysteryboxprizemessage = 3712;
 | 
			
		||||
case Cancelmysteryboxwaitmessage = 596;
 | 
			
		||||
case Showmysteryboxwaitmessage = 3201;
 | 
			
		||||
case TradeAccepted = 2568;
 | 
			
		||||
case TradeClosed = 1373;
 | 
			
		||||
case TradeCompleted = 1001;
 | 
			
		||||
case TradeConfirmation = 2720;
 | 
			
		||||
case TradeListItem = 2024;
 | 
			
		||||
case TradeNotOpen = 3128;
 | 
			
		||||
case TradeOpen = 2505;
 | 
			
		||||
case TradeOpenFailed = 217;
 | 
			
		||||
case TradeOtherNotAllowed = 1254;
 | 
			
		||||
case TradeYouNotAllowed = 3058;
 | 
			
		||||
case TradeNoSuchItem = 2873;
 | 
			
		||||
case Unit = 374;
 | 
			
		||||
case UnitChangeName = 2182;
 | 
			
		||||
case UnitChat = 1446;
 | 
			
		||||
case UnitChatShout = 1036;
 | 
			
		||||
case UnitChatWhisper = 2704;
 | 
			
		||||
case UnitDance = 2233;
 | 
			
		||||
case UnitEffect = 1167;
 | 
			
		||||
case UnitExpression = 1631;
 | 
			
		||||
case UnitHandItem = 1474;
 | 
			
		||||
case UnitIdle = 1797;
 | 
			
		||||
case UnitInfo = 3920;
 | 
			
		||||
case UnitNumber = 2324;
 | 
			
		||||
case UnitRemove = 2661;
 | 
			
		||||
case UnitStatus = 1640;
 | 
			
		||||
case UnitTyping = 1717;
 | 
			
		||||
case UnseenItems = 2103;
 | 
			
		||||
case UserAchievementScore = 1968;
 | 
			
		||||
case UserBadges = 717;
 | 
			
		||||
case UserBadgesAdd = 2493;
 | 
			
		||||
case UserBadgesCurrent = 1087;
 | 
			
		||||
case UserBots = 3086;
 | 
			
		||||
case UserChangeName = 118;
 | 
			
		||||
case UserClothing = 1450;
 | 
			
		||||
case UserCredits = 3475;
 | 
			
		||||
case UserCurrency = 2018;
 | 
			
		||||
case ActivityPointNotification = 2275;
 | 
			
		||||
case UserFavoriteRoom = 2524;
 | 
			
		||||
case UserFavoriteRoomCount = 151;
 | 
			
		||||
case UserFigure = 2429;
 | 
			
		||||
case UserFurniture = 994;
 | 
			
		||||
case UserFurnitureAdd = 104;
 | 
			
		||||
case UserFurniturePostitPlaced = 1501;
 | 
			
		||||
case UserFurnitureRefresh = 3151;
 | 
			
		||||
case UserFurnitureRemove = 159;
 | 
			
		||||
case UserHomeRoom = 2875;
 | 
			
		||||
case RoomEventCancel = 3479;
 | 
			
		||||
case RoomEvent = 1840;
 | 
			
		||||
case UserIgnored = 126;
 | 
			
		||||
case UserIgnoredResult = 207;
 | 
			
		||||
case UserInfo = 2725;
 | 
			
		||||
case UserPerks = 2586;
 | 
			
		||||
case UserPermissions = 411;
 | 
			
		||||
case UserPetAdd = 2101;
 | 
			
		||||
case UserPetRemove = 3253;
 | 
			
		||||
case UserPets = 3522;
 | 
			
		||||
case UserProfile = 3898;
 | 
			
		||||
case UserRespect = 2815;
 | 
			
		||||
case UserSanctionStatus = 3679;
 | 
			
		||||
case UserSettings = 513;
 | 
			
		||||
case UserSubscription = 954;
 | 
			
		||||
case UserWardrobePage = 3315;
 | 
			
		||||
case UserClassification = 966;
 | 
			
		||||
case GetUserTags = 1255;
 | 
			
		||||
case WiredAction = 1434;
 | 
			
		||||
case WiredCondition = 1108;
 | 
			
		||||
case WiredError = 156;
 | 
			
		||||
case WiredOpen = 1830;
 | 
			
		||||
case WiredReward = 178;
 | 
			
		||||
case WiredSave = 1155;
 | 
			
		||||
case WiredTrigger = 383;
 | 
			
		||||
case PlayingGame = 448;
 | 
			
		||||
case FurnitureState2 = 3431;
 | 
			
		||||
case RemoveBotFromInventory = 233;
 | 
			
		||||
case AddBotToInventory = 1352;
 | 
			
		||||
case AchievementProgressed = 2107;
 | 
			
		||||
case ModtoolRoomInfo = 1333;
 | 
			
		||||
case ModtoolUserChatlog = 3377;
 | 
			
		||||
case ModtoolRoomChatlog = 3434;
 | 
			
		||||
case ModtoolVisitedRoomsUser = 1752;
 | 
			
		||||
case ModeratorActionResult = 2335;
 | 
			
		||||
case IssueDeleted = 3192;
 | 
			
		||||
case IssueInfo = 3609;
 | 
			
		||||
case IssuePickFailed = 3150;
 | 
			
		||||
case CfhChatlog = 607;
 | 
			
		||||
case ModeratorToolPreferences = 1576;
 | 
			
		||||
case LovelockFurniStart = 3753;
 | 
			
		||||
case LovelockFurniFriendComfirmed = 382;
 | 
			
		||||
case LovelockFurniFinished = 770;
 | 
			
		||||
case GiftReceiverNotFound = 1517;
 | 
			
		||||
case GiftOpened = 56;
 | 
			
		||||
case FloodControl = 566;
 | 
			
		||||
case RemainingMute = 826;
 | 
			
		||||
case UserEffectList = 340;
 | 
			
		||||
case UserEffectListAdd = 2867;
 | 
			
		||||
case UserEffectListRemove = 2228;
 | 
			
		||||
case UserEffectActivate = 1959;
 | 
			
		||||
case AvatarEffectSelected = 3473;
 | 
			
		||||
case ClubGiftInfo = 619;
 | 
			
		||||
case RedeemVoucherError = 714;
 | 
			
		||||
case RedeemVoucherOk = 3336;
 | 
			
		||||
case InClientLink = 2023;
 | 
			
		||||
case BotCommandConfiguration = 1618;
 | 
			
		||||
case BotSkillListUpdate = 69;
 | 
			
		||||
case BotForceOpenContextMenu = 296;
 | 
			
		||||
case HandItemReceived = 354;
 | 
			
		||||
case PetPlacingError = 2913;
 | 
			
		||||
case BotError = 639;
 | 
			
		||||
case MarketplaceSellItem = 54;
 | 
			
		||||
case MarketplaceItemStats = 725;
 | 
			
		||||
case MarketplaceOwnItems = 3884;
 | 
			
		||||
case MarketplaceCancelSale = 3264;
 | 
			
		||||
case MarketplaceItemPosted = 1359;
 | 
			
		||||
case MarketplaceItemsSearched = 680;
 | 
			
		||||
case MarketplaceAfterOrderStatus = 2032;
 | 
			
		||||
case CatalogReceivePetBreeds = 3331;
 | 
			
		||||
case CatalogApproveNameResult = 1503;
 | 
			
		||||
case ObjectsDataUpdate = 1453;
 | 
			
		||||
case PetExperience = 2156;
 | 
			
		||||
case CommunityGoalVoteEvent = 1435;
 | 
			
		||||
case PromoArticles = 286;
 | 
			
		||||
case CommunityGoalEarnedPrizes = 3319;
 | 
			
		||||
case CommunityGoalProgress = 2525;
 | 
			
		||||
case ConcurrentUsersGoalProgress = 2737;
 | 
			
		||||
case QuestDaily = 1878;
 | 
			
		||||
case QuestCancelled = 3027;
 | 
			
		||||
case QuestCompleted = 949;
 | 
			
		||||
case CommunityGoalHallOfFame = 3005;
 | 
			
		||||
case EpicPopup = 3945;
 | 
			
		||||
case SeasonalQuests = 1122;
 | 
			
		||||
case Quests = 3625;
 | 
			
		||||
case Quest = 230;
 | 
			
		||||
case BonusRareInfo = 1533;
 | 
			
		||||
case CraftableProducts = 1000;
 | 
			
		||||
case CraftingRecipe = 2774;
 | 
			
		||||
case CraftingRecipesAvailable = 2124;
 | 
			
		||||
case CraftingResult = 618;
 | 
			
		||||
case CameraPublishStatus = 2057;
 | 
			
		||||
case CameraPurchaseOk = 2783;
 | 
			
		||||
case CameraStorageUrl = 3696;
 | 
			
		||||
case CameraSnapshot = 463;
 | 
			
		||||
case CompetitionStatus = 133;
 | 
			
		||||
case InitCamera = 3878;
 | 
			
		||||
case ThumbnailStatus = 3595;
 | 
			
		||||
case AchievementNotification = 806;
 | 
			
		||||
case ClubGiftNotification = 2188;
 | 
			
		||||
case InterstitialMessage = 1808;
 | 
			
		||||
case RoomAdError = 1759;
 | 
			
		||||
case AvailabilityTime = 600;
 | 
			
		||||
case HotelClosedAndOpens = 3728;
 | 
			
		||||
case HotelClosesAndOpensAt = 2771;
 | 
			
		||||
case HotelWillCloseMinutes = 1050;
 | 
			
		||||
case HotelMaintenance = 1350;
 | 
			
		||||
case JukeboxPlaylistFull = 105;
 | 
			
		||||
case JukeboxSongDisks = 34;
 | 
			
		||||
case NowPlaying = 469;
 | 
			
		||||
case OfficialSongId = 1381;
 | 
			
		||||
case Playlist = 1748;
 | 
			
		||||
case PlaylistSongAdded = 1140;
 | 
			
		||||
case TraxSongInfo = 3365;
 | 
			
		||||
case UserSongDisksInventory = 2602;
 | 
			
		||||
case CheckUserName = 563;
 | 
			
		||||
case CfhSanction = 2782;
 | 
			
		||||
case CfhTopics = 325;
 | 
			
		||||
case CfhSanctionStatus = 2221;
 | 
			
		||||
case CampaignCalendarData = 2531;
 | 
			
		||||
case CampaignCalendarDoorOpened = 2551;
 | 
			
		||||
case BuildersClubFurniCount = 3828;
 | 
			
		||||
case BuildersClubSubscription = 1452;
 | 
			
		||||
case CatalogPageExpiration = 2668;
 | 
			
		||||
case CatalogEarliestExpiry = 2515;
 | 
			
		||||
case ClubGiftSelected = 659;
 | 
			
		||||
case TargetOfferNotFound = 1237;
 | 
			
		||||
case TargetOffer = 119;
 | 
			
		||||
case DirectSmsClubBuy = 195;
 | 
			
		||||
case RoomAdPurchase = 2468;
 | 
			
		||||
case NotEnoughBalance = 3914;
 | 
			
		||||
case LimitedOfferAppearingNext = 44;
 | 
			
		||||
case IsOfferGiftable = 761;
 | 
			
		||||
case ClubExtendedOffer = 3964;
 | 
			
		||||
case SeasonalCalendarOffer = 1889;
 | 
			
		||||
case CompetitionEntrySubmit = 1177;
 | 
			
		||||
case CompetitionVotingInfo = 3506;
 | 
			
		||||
case CompetitionTimingCode = 1745;
 | 
			
		||||
case CompetitionUserPartOf = 3841;
 | 
			
		||||
//case CompetitionNoOwnedRooms = 2064;
 | 
			
		||||
case CompetitionSecondsUntil = 3926;
 | 
			
		||||
case BadgePointLimits = 2501;
 | 
			
		||||
case BadgeRequestFulfilled = 2998;
 | 
			
		||||
case HelperTalentTrack = 3406;
 | 
			
		||||
case TalentTrackLevel = 1203;
 | 
			
		||||
case TalentTrackLevelUp = 638;
 | 
			
		||||
case UserBanned = 1683;
 | 
			
		||||
case BotReceived = 3684;
 | 
			
		||||
case PetLevelNotification = 859;
 | 
			
		||||
case PetReceived = 1111;
 | 
			
		||||
case ModerationCaution = 1890;
 | 
			
		||||
case YoutubeControlVideo = 1554;
 | 
			
		||||
case YoutubeDisplayPlaylists = 1112;
 | 
			
		||||
case YoutubeDisplayVideo = 1411;
 | 
			
		||||
case CfhDisabledNotify = 1651;
 | 
			
		||||
case Question = 2665;
 | 
			
		||||
case PollContents = 2997;
 | 
			
		||||
case PollError = 662;
 | 
			
		||||
case PollOffer = 3785;
 | 
			
		||||
case PollRoomResult = 5201;
 | 
			
		||||
case PollStartRoom = 5200;
 | 
			
		||||
case QuestionAnswered = 2589;
 | 
			
		||||
case QuestionFinished = 1066;
 | 
			
		||||
case CfhPendingCalls = 1121;
 | 
			
		||||
case GuideOnDutyStatus = 1548;
 | 
			
		||||
case GuideSessionAttached = 1591;
 | 
			
		||||
case GuideSessionDetached = 138;
 | 
			
		||||
case GuideSessionEnded = 1456;
 | 
			
		||||
case GuideSessionError = 673;
 | 
			
		||||
case GuideSessionInvitedToGuideRoom = 219;
 | 
			
		||||
case GuideSessionMessage = 841;
 | 
			
		||||
case GuideSessionPartnerIsTyping = 1016;
 | 
			
		||||
case GuideSessionRequesterRoom = 1847;
 | 
			
		||||
case GuideSessionStarted = 3209;
 | 
			
		||||
case GuideTicketCreationResult = 3285;
 | 
			
		||||
case GuideTicketResolution = 2674;
 | 
			
		||||
case GuideReportingStatus = 3463;
 | 
			
		||||
case HotelMergeNameChange = 1663;
 | 
			
		||||
case IssueCloseNotification = 934;
 | 
			
		||||
case QuizData = 2927;
 | 
			
		||||
case QuizResults = 2772;
 | 
			
		||||
case CfhPendingCallsDeleted = 77;
 | 
			
		||||
case CfhReply = 3796;
 | 
			
		||||
case ChatReviewSessionDetached = 30;
 | 
			
		||||
case ChatReviewSessionOfferedToGuide = 735;
 | 
			
		||||
case ChatReviewSessionResults = 3276;
 | 
			
		||||
case ChatReviewSessionStarted = 143;
 | 
			
		||||
case ChatReviewSessionVotingStatus = 1829;
 | 
			
		||||
case ScrSendKickbackInfo = 3277;
 | 
			
		||||
case PetStatus = 1907;
 | 
			
		||||
case GroupDeactivate = 3129;
 | 
			
		||||
case PetRespected = 2788;
 | 
			
		||||
case PetSupplement = 3441;
 | 
			
		||||
case NoobnessLevel = 3738;
 | 
			
		||||
case DisconnectReason = 4000;
 | 
			
		||||
case CanCreateRoomEvent = 2599;
 | 
			
		||||
case FavoriteGroupUdpate = 3403;
 | 
			
		||||
case NoSuchFlat = 84;
 | 
			
		||||
case RoomSettingsError = 2897;
 | 
			
		||||
case ShowEnforceRoomCategory = 3896;
 | 
			
		||||
case CustomUserNotification = 909;
 | 
			
		||||
case NewUserExperienceGiftOffer = 3575;
 | 
			
		||||
case RestoreClient = 426;
 | 
			
		||||
case FireworkChargeData = 5210;
 | 
			
		||||
case NewUserExperienceNotComplete = 3639;
 | 
			
		||||
case ConnectionError = 1004;
 | 
			
		||||
case AccountSafetyLockStatusChange = 1243;
 | 
			
		||||
case PhoneCollectionState = 2890;
 | 
			
		||||
case PhoneTryNumberResult = 800;
 | 
			
		||||
case PhoneTryVerificationCodeResult = 91;
 | 
			
		||||
case ExtendedProfileChanged = 876;
 | 
			
		||||
case WelcomeGiftChangeEmailResult = 2293;
 | 
			
		||||
case WelcomeGiftStatus = 2707;
 | 
			
		||||
case HandshakeInitDiffie = 1347;
 | 
			
		||||
case HandshakeCompleteDiffie = 3885;
 | 
			
		||||
case RentableSpaceRentOk = 2046;
 | 
			
		||||
case RentableSpaceStatus = 3559;
 | 
			
		||||
case RentableSpaceRentFailed = 1868;
 | 
			
		||||
case EmailStatus = 612;
 | 
			
		||||
case ChangeEmailResult = 1815;
 | 
			
		||||
case WeeklyGameReward = 2641;
 | 
			
		||||
case WeeklyGameRewardWinners = 3097;
 | 
			
		||||
case WeeklyCompetitiveLeaderboard = 3512;
 | 
			
		||||
case WeeklyCompetitiveFriendsLeaderboard = 3560;
 | 
			
		||||
case WeeklyGame2FriendsLeaderboard = 2270;
 | 
			
		||||
case WeeklyGame2Leaderboard = 2196;
 | 
			
		||||
case RentableFurniRentOrBuyoutOffer = 35;
 | 
			
		||||
case HandshakeIdentityAccount = 3523;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Messages\Outgoing;
 | 
			
		||||
 | 
			
		||||
interface IMessageComposer {
 | 
			
		||||
    function compose(ServerMessage $message): void;
 | 
			
		||||
    function getHeader(): Header;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Messages\Outgoing;
 | 
			
		||||
 | 
			
		||||
use Emulator\Encoding\ByteEncoding;
 | 
			
		||||
 | 
			
		||||
class ServerMessage {
 | 
			
		||||
    private array $packet = [];
 | 
			
		||||
 | 
			
		||||
    function __construct(int $header) {
 | 
			
		||||
        $this->writeInt16($header);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function writeInt16(int $value): void {
 | 
			
		||||
        $this->packet = array_merge($this->packet, ByteEncoding::int16ToArray($value));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function writeInt32(int $value): void {
 | 
			
		||||
        $this->packet = array_merge($this->packet, ByteEncoding::int32ToArray($value));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function writeBoolean(bool $value): void {
 | 
			
		||||
        $this->packet[] = ($value ? 1 : 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function writeString(string $value): void {
 | 
			
		||||
        $this->writeInt16(strlen($value));
 | 
			
		||||
        $this->packet = array_merge($this->packet, unpack('C*', $value));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getPacket(): array {
 | 
			
		||||
        return $this->packet;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Network\Game;
 | 
			
		||||
 | 
			
		||||
use Emulator\Core\Logging\Logger;
 | 
			
		||||
use Emulator\Encoding\ByteEncoding;
 | 
			
		||||
use Emulator\Messages\Incoming\ClientMessage;
 | 
			
		||||
use Emulator\Messages\MessageHandler;
 | 
			
		||||
use Emulator\Network\Game\Sessions\Session;
 | 
			
		||||
use Override;
 | 
			
		||||
use Ratchet\ConnectionInterface;
 | 
			
		||||
use Ratchet\Http\HttpServer;
 | 
			
		||||
use Ratchet\RFC6455\Messaging\MessageInterface;
 | 
			
		||||
use Ratchet\Server\IoServer;
 | 
			
		||||
use Ratchet\WebSocket\MessageComponentInterface;
 | 
			
		||||
use Ratchet\WebSocket\WsConnection;
 | 
			
		||||
use Ratchet\WebSocket\WsServer;
 | 
			
		||||
use React\EventLoop\Loop;
 | 
			
		||||
use React\Socket\SocketServer;
 | 
			
		||||
 | 
			
		||||
class GameNetworkServer implements MessageComponentInterface {
 | 
			
		||||
    private static ?GameNetworkServer $instance = null;
 | 
			
		||||
    private array $sessions;
 | 
			
		||||
 | 
			
		||||
    public function start(int $port): void {
 | 
			
		||||
        $loop = Loop::get();
 | 
			
		||||
 | 
			
		||||
        $this->sessions = [];
 | 
			
		||||
        $socketServer = new SocketServer("127.0.0.1:{$port}", loop: $loop);
 | 
			
		||||
        new IoServer(
 | 
			
		||||
            new HttpServer(
 | 
			
		||||
                new WsServer($this)
 | 
			
		||||
            ),
 | 
			
		||||
            $socketServer,
 | 
			
		||||
            $loop
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function getInstance(): GameNetworkServer {
 | 
			
		||||
        if (self::$instance === null) {
 | 
			
		||||
            self::$instance = new self();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return self::$instance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[Override] function onOpen(ConnectionInterface $conn): void {
 | 
			
		||||
        $this->sessions[$conn->resourceId] = new Session(new WsConnection($conn));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[Override] function onClose(ConnectionInterface $conn): void {
 | 
			
		||||
        unset($this->sessions[$conn->resourceId]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[Override] function onError(ConnectionInterface $conn, \Exception $e): void {
 | 
			
		||||
        Logger::fatal($e->getMessage());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[Override] public function onMessage(ConnectionInterface $conn, MessageInterface $msg): void {
 | 
			
		||||
        $raw = $msg->getPayload();
 | 
			
		||||
        $data = unpack('C*', $raw);
 | 
			
		||||
 | 
			
		||||
        if (count($data) >= 6) {
 | 
			
		||||
            $length = ByteEncoding::getInt32(array_slice($data, 1, 4));
 | 
			
		||||
            $packet = array_slice($data, 4, $length);
 | 
			
		||||
 | 
			
		||||
            MessageHandler::getInstance()->handlePacket($this->sessions[$conn->resourceId], new ClientMessage($packet));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Emulator\Network\Game\Sessions;
 | 
			
		||||
 | 
			
		||||
use Emulator\Encoding\ByteEncoding;
 | 
			
		||||
use Emulator\Messages\Outgoing\IMessageComposer;
 | 
			
		||||
use Emulator\Messages\Outgoing\ServerMessage;
 | 
			
		||||
use Ratchet\RFC6455\Messaging\Frame;
 | 
			
		||||
use Ratchet\RFC6455\Messaging\Message;
 | 
			
		||||
use Ratchet\WebSocket\WsConnection;
 | 
			
		||||
 | 
			
		||||
readonly class Session {
 | 
			
		||||
    private WsConnection $connection;
 | 
			
		||||
 | 
			
		||||
    public function __construct(WsConnection $connection) {
 | 
			
		||||
        $this->connection = $connection;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function sendComposer(IMessageComposer $composer): void {
 | 
			
		||||
        $headerData = pack('n', 2491);
 | 
			
		||||
        $length = strlen($headerData);
 | 
			
		||||
        $lengthData = pack('N', $length);
 | 
			
		||||
        $binaryMessage = $lengthData . $headerData;
 | 
			
		||||
        $frame = new Frame($binaryMessage, true, Frame::OP_BINARY);
 | 
			
		||||
        $this->connection->send($frame);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function encode($text) {
 | 
			
		||||
        $b1 = 0x80 | (0x1 & 0x0f);
 | 
			
		||||
        $length = strlen($text);
 | 
			
		||||
        if ($length <= 125)
 | 
			
		||||
            $header = pack('CC', $b1, $length);
 | 
			
		||||
        elseif($length > 125 && $length < 65536)
 | 
			
		||||
            $header = pack('CCn', $b1, 126, $length);
 | 
			
		||||
        elseif($length >= 65536)
 | 
			
		||||
            $header = pack('CCNN', $b1, 127, $length);
 | 
			
		||||
 | 
			
		||||
        return $header.$text;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue