UNPKG

@jsprismarine/prismarine

Version:

Dedicated Minecraft Bedrock Edition server written in TypeScript

164 lines (159 loc) • 14.6 kB
'use strict'; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } }); require('node:fs'); require('confbox'); require('@jsprismarine/errors'); require('@jsprismarine/jsbinaryutils'); require('node:assert'); require('node:path'); require('node:process'); require('../../block/BlockToolType.cjs.cjs'); require('@jsprismarine/bedrock-data'); require('@jsprismarine/nbt'); require('zlib'); require('@jsprismarine/math'); require('@jsprismarine/minecraft'); require('../packet/AddActorPacket.cjs.cjs'); require('../packet/MoveActorAbsolutePacket.cjs.cjs'); require('../packet/RemoveActorPacket.cjs.cjs'); require('node:crypto'); require('../packet/ActorFallPacket.cjs.cjs'); require('../packet/AddItemActorPacket.cjs.cjs'); require('../packet/AddPlayerPacket.cjs.cjs'); require('../packet/AnimatePacket.cjs.cjs'); require('../packet/AvailableActorIdentifiersPacket.cjs.cjs'); require('../packet/AvailableCommandsPacket.cjs.cjs'); require('../CompressionProvider.cjs.cjs'); require('../packet/NetworkSettingsPacket.cjs.cjs'); require('../packet/BiomeDefinitionListPacket.cjs.cjs'); require('../packet/ChangeDimensionPacket.cjs.cjs'); require('../packet/ChunkRadiusUpdatedPacket.cjs.cjs'); require('../packet/CommandRequestPacket.cjs.cjs'); require('../packet/ContainerClosePacket.cjs.cjs'); require('../packet/ContainerOpenPacket.cjs.cjs'); require('../packet/CreativeContentPacket.cjs.cjs'); require('../packet/DisconnectPacket.cjs.cjs'); require('../packet/EmoteListPacket.cjs.cjs'); require('../packet/InteractPacket.cjs.cjs'); require('../packet/InventoryContentPacket.cjs.cjs'); require('../packet/InventoryTransactionPacket.cjs.cjs'); require('../packet/ItemComponentPacket.cjs.cjs'); require('../packet/ItemStackRequestPacket.cjs.cjs'); require('../packet/ItemStackResponsePacket.cjs.cjs'); require('../packet/LevelChunkPacket.cjs.cjs'); require('../packet/LevelSoundEventPacket.cjs.cjs'); require('../packet/LoginPacket.cjs.cjs'); require('../packet/MobEquipmentPacket.cjs.cjs'); require('../packet/MovePlayerPacket.cjs.cjs'); require('../packet/NetworkChunkPublisherUpdatePacket.cjs.cjs'); require('../packet/OnScreenTextureAnimationPacket.cjs.cjs'); require('../packet/PacketViolationWarningPacket.cjs.cjs'); require('../packet/PlaySoundPacket.cjs.cjs'); const network_packet_PlayStatusPacket = require('../packet/PlayStatusPacket.cjs.cjs'); require('../packet/PlayerActionPacket.cjs.cjs'); require('../packet/PlayerListPacket.cjs.cjs'); require('../packet/PlayerSkinPacket.cjs.cjs'); require('../packet/RequestChunkRadiusPacket.cjs.cjs'); require('../packet/RequestNetworkSettingsPacket.cjs.cjs'); require('../packet/ResourcePackResponsePacket.cjs.cjs'); require('../packet/ResourcePackStackPacket.cjs.cjs'); const network_packet_ResourcePacksInfoPacket = require('../packet/ResourcePacksInfoPacket.cjs.cjs'); require('../packet/ServerSettingsRequestPacket.cjs.cjs'); require('../packet/SetActorDataPacket.cjs.cjs'); require('../packet/SetDefaultGametypePacket.cjs.cjs'); require('../packet/SetHealthPacket.cjs.cjs'); require('../packet/SetLocalPlayerAsInitializedPacket.cjs.cjs'); require('../packet/SetPlayerGametypePacket.cjs.cjs'); require('../packet/SetTimePacket.cjs.cjs'); require('../packet/ShowProfilePacket.cjs.cjs'); require('../packet/StartGamePacket.cjs.cjs'); require('../packet/TextPacket.cjs.cjs'); require('../packet/TickSyncPacket.cjs.cjs'); require('../packet/TransferPacket.cjs.cjs'); require('../packet/UpdateAdventureSettingsPacket.cjs.cjs'); require('../packet/UpdateAttributesPacket.cjs.cjs'); require('../packet/UpdateBlockPacket.cjs.cjs'); require('../packet/WorldEventPacket.cjs.cjs'); require('@jsprismarine/brigadier'); const network_Identifiers = require('../Identifiers.cjs.cjs'); require('../../config/Config.cjs.cjs'); require('./AnimateHandler.cjs.cjs'); require('./CommandRequestHandler.cjs.cjs'); require('./ContainerCloseHandler.cjs.cjs'); require('./EmoteListHandler.cjs.cjs'); require('./InteractHandler.cjs.cjs'); require('./InventoryTransactionHandler.cjs.cjs'); require('./LevelSoundEventHandler.cjs.cjs'); require('./MobEquipmentHandler.cjs.cjs'); require('./MovePlayerHandler.cjs.cjs'); require('./PacketViolationWarningHandler.cjs.cjs'); require('./PlayerActionHandler.cjs.cjs'); require('./RequestChunkRadiusHandler.cjs.cjs'); require('./RequestNetworkSettingsHandler.cjs.cjs'); require('./ResourcePackResponseHandler.cjs.cjs'); require('./ServerSettingsRequestHandler.cjs.cjs'); require('./SetDefaultGametypeHandler.cjs.cjs'); require('./SetLocalPlayerAsInitializedHandler.cjs.cjs'); require('./SetPlayerGametypeHandler.cjs.cjs'); require('./TextHandler.cjs.cjs'); require('./TickSyncHandler.cjs.cjs'); require('node:readline'); const Player = require('../../Player.cjs.cjs'); require('@jsprismarine/raknet'); require('evt'); require('assert'); require('heap'); require('../packet/UpdateAbilitiesPacket.cjs.cjs'); const network_type_PlayStatusType = require('../type/PlayStatusType.cjs.cjs'); class LoginHandler { static NetID = network_Identifiers.default.LoginPacket; /** * @TODO: Check if player count >= max players * @TODO: encryption handshake. */ async handle(packet, server, connection) { const playStatus = new network_packet_PlayStatusPacket.default(); if (packet.protocol !== network_Identifiers.default.Protocol) { playStatus.status = packet.protocol < network_Identifiers.default.Protocol ? network_type_PlayStatusType.default.LoginFailedClient : network_type_PlayStatusType.default.LoginFailedServer; await connection.sendDataPacket(playStatus, true); return; } if (!packet.displayName) { connection.disconnect("Invalid username!", false); return; } const player = new Player.default({ connection, world: server.getWorldManager().getDefaultWorld(), server, uuid: packet.identity }); player.setName(packet.displayName); player.xuid = packet.XUID; player.randomId = packet.clientRandomId; player.locale = packet.languageCode; player.skin = packet.skin; player.device = packet.device; await server.getSessionManager().findPlayer({ name: packet.displayName, xuid: packet.XUID })?.kick("Logged in from another location"); if (!player.xuid && server.getConfig().getOnlineMode()) { await player.kick("Server is in online-mode!"); return; } const reason = server.getBanManager().isBanned(player); if (reason !== false) { await player.kick(`You have been banned${reason ? ` for reason: ${reason}` : ""}!`); return; } await player.enable(); const session = connection.initPlayerConnection(server, player); await session.sendPlayStatus(network_type_PlayStatusType.default.LoginSuccess); const resourcePacksInfo = new network_packet_ResourcePacksInfoPacket.default(); resourcePacksInfo.resourcePackRequired = false; resourcePacksInfo.forceServerPacksEnabled = false; resourcePacksInfo.hasScripts = false; resourcePacksInfo.hasAddonPacks = false; await connection.sendDataPacket(resourcePacksInfo, true); } } exports.default = LoginHandler; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTG9naW5IYW5kbGVyLmNqcy5janMiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9uZXR3b3JrL2hhbmRsZXIvTG9naW5IYW5kbGVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFBsYXllciB9IGZyb20gJy4uLy4uLyc7XG5pbXBvcnQgdHlwZSBTZXJ2ZXIgZnJvbSAnLi4vLi4vU2VydmVyJztcbmltcG9ydCB0eXBlIENsaWVudENvbm5lY3Rpb24gZnJvbSAnLi4vQ2xpZW50Q29ubmVjdGlvbic7XG5pbXBvcnQgSWRlbnRpZmllcnMgZnJvbSAnLi4vSWRlbnRpZmllcnMnO1xuaW1wb3J0IHsgUGxheVN0YXR1c1BhY2tldCB9IGZyb20gJy4uL1BhY2tldHMnO1xuaW1wb3J0IHR5cGUgTG9naW5QYWNrZXQgZnJvbSAnLi4vcGFja2V0L0xvZ2luUGFja2V0JztcbmltcG9ydCBSZXNvdXJjZVBhY2tzSW5mb1BhY2tldCBmcm9tICcuLi9wYWNrZXQvUmVzb3VyY2VQYWNrc0luZm9QYWNrZXQnO1xuaW1wb3J0IFBsYXlTdGF0dXNUeXBlIGZyb20gJy4uL3R5cGUvUGxheVN0YXR1c1R5cGUnO1xuaW1wb3J0IHR5cGUgUHJlTG9naW5QYWNrZXRIYW5kbGVyIGZyb20gJy4vUHJlTG9naW5QYWNrZXRIYW5kbGVyJztcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTG9naW5IYW5kbGVyIGltcGxlbWVudHMgUHJlTG9naW5QYWNrZXRIYW5kbGVyPExvZ2luUGFja2V0PiB7XG4gICAgcHVibGljIHN0YXRpYyBOZXRJRCA9IElkZW50aWZpZXJzLkxvZ2luUGFja2V0O1xuXG4gICAgLyoqXG4gICAgICogQFRPRE86IENoZWNrIGlmIHBsYXllciBjb3VudCA+PSBtYXggcGxheWVyc1xuICAgICAqIEBUT0RPOiBlbmNyeXB0aW9uIGhhbmRzaGFrZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgYXN5bmMgaGFuZGxlKHBhY2tldDogTG9naW5QYWNrZXQsIHNlcnZlcjogU2VydmVyLCBjb25uZWN0aW9uOiBDbGllbnRDb25uZWN0aW9uKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IHBsYXlTdGF0dXMgPSBuZXcgUGxheVN0YXR1c1BhY2tldCgpO1xuXG4gICAgICAgIC8vIEtpY2sgY2xpZW50IGlmIGhhcyBuZXdlciAvIG9sZGVyIGNsaWVudCB2ZXJzaW9uXG4gICAgICAgIGlmIChwYWNrZXQucHJvdG9jb2wgIT09IElkZW50aWZpZXJzLlByb3RvY29sKSB7XG4gICAgICAgICAgICBwbGF5U3RhdHVzLnN0YXR1cyA9XG4gICAgICAgICAgICAgICAgcGFja2V0LnByb3RvY29sIDwgSWRlbnRpZmllcnMuUHJvdG9jb2xcbiAgICAgICAgICAgICAgICAgICAgPyBQbGF5U3RhdHVzVHlwZS5Mb2dpbkZhaWxlZENsaWVudFxuICAgICAgICAgICAgICAgICAgICA6IFBsYXlTdGF0dXNUeXBlLkxvZ2luRmFpbGVkU2VydmVyO1xuICAgICAgICAgICAgYXdhaXQgY29ubmVjdGlvbi5zZW5kRGF0YVBhY2tldChwbGF5U3RhdHVzLCB0cnVlKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEtpY2sgdGhlIHBsYXllciBpZiB0aGVpciB1c2VybmFtZSBpcyBpbnZhbGlkXG4gICAgICAgIGlmICghcGFja2V0LmRpc3BsYXlOYW1lKSB7XG4gICAgICAgICAgICBjb25uZWN0aW9uLmRpc2Nvbm5lY3QoJ0ludmFsaWQgdXNlcm5hbWUhJywgZmFsc2UpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgcGxheWVyID0gbmV3IFBsYXllcih7XG4gICAgICAgICAgICBjb25uZWN0aW9uLFxuICAgICAgICAgICAgd29ybGQ6IHNlcnZlci5nZXRXb3JsZE1hbmFnZXIoKS5nZXREZWZhdWx0V29ybGQoKSEsXG4gICAgICAgICAgICBzZXJ2ZXIsXG4gICAgICAgICAgICB1dWlkOiBwYWNrZXQuaWRlbnRpdHlcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcGxheWVyLnNldE5hbWUocGFja2V0LmRpc3BsYXlOYW1lKTtcbiAgICAgICAgcGxheWVyLnh1aWQgPSBwYWNrZXQuWFVJRDtcbiAgICAgICAgcGxheWVyLnJhbmRvbUlkID0gcGFja2V0LmNsaWVudFJhbmRvbUlkO1xuICAgICAgICBwbGF5ZXIubG9jYWxlID0gcGFja2V0Lmxhbmd1YWdlQ29kZTtcbiAgICAgICAgcGxheWVyLnNraW4gPSBwYWNrZXQuc2tpbjtcbiAgICAgICAgcGxheWVyLmRldmljZSA9IHBhY2tldC5kZXZpY2U7XG5cbiAgICAgICAgLy8gUGxheWVyIHdpdGggc2FtZSBuYW1lIG9yIHh1aWQgaXMgYWxyZWFkeSBjb25uZWN0ZWQsXG4gICAgICAgIC8vIHNvIGtpY2sgdGhlIG9sZCBwbGF5ZXIgYW5kIGxldCB0aGUgbmV3IHBsYXllciBjb25uZWN0LlxuICAgICAgICBhd2FpdCBzZXJ2ZXJcbiAgICAgICAgICAgIC5nZXRTZXNzaW9uTWFuYWdlcigpXG4gICAgICAgICAgICAuZmluZFBsYXllcih7IG5hbWU6IHBhY2tldC5kaXNwbGF5TmFtZSwgeHVpZDogcGFja2V0LlhVSUQgfSlcbiAgICAgICAgICAgID8ua2ljaygnTG9nZ2VkIGluIGZyb20gYW5vdGhlciBsb2NhdGlvbicpO1xuXG4gICAgICAgIGlmICghcGxheWVyLnh1aWQgJiYgc2VydmVyLmdldENvbmZpZygpLmdldE9ubGluZU1vZGUoKSkge1xuICAgICAgICAgICAgYXdhaXQgcGxheWVyLmtpY2soJ1NlcnZlciBpcyBpbiBvbmxpbmUtbW9kZSEnKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJlYXNvbiA9IHNlcnZlci5nZXRCYW5NYW5hZ2VyKCkuaXNCYW5uZWQocGxheWVyKTtcbiAgICAgICAgaWYgKHJlYXNvbiAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgIGF3YWl0IHBsYXllci5raWNrKGBZb3UgaGF2ZSBiZWVuIGJhbm5lZCR7cmVhc29uID8gYCBmb3IgcmVhc29uOiAke3JlYXNvbn1gIDogJyd9IWApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgcGxheWVyLmVuYWJsZSgpO1xuXG4gICAgICAgIC8vIFVwZGF0ZSB0aGUgcGxheWVyIGNvbm5lY3Rpb24gdG8gYmUgcmVjb2duaXplZCBhcyBhIGNvbm5lY3RlZCBwbGF5ZXJcbiAgICAgICAgY29uc3Qgc2Vzc2lvbiA9IGNvbm5lY3Rpb24uaW5pdFBsYXllckNvbm5lY3Rpb24oc2VydmVyLCBwbGF5ZXIpO1xuICAgICAgICBhd2FpdCBzZXNzaW9uLnNlbmRQbGF5U3RhdHVzKFBsYXlTdGF0dXNUeXBlLkxvZ2luU3VjY2Vzcyk7XG5cbiAgICAgICAgLy8gRmluYWxpemUgY29ubmVjdGlvbiBoYW5kc2hha2VcbiAgICAgICAgY29uc3QgcmVzb3VyY2VQYWNrc0luZm8gPSBuZXcgUmVzb3VyY2VQYWNrc0luZm9QYWNrZXQoKTtcbiAgICAgICAgcmVzb3VyY2VQYWNrc0luZm8ucmVzb3VyY2VQYWNrUmVxdWlyZWQgPSBmYWxzZTtcbiAgICAgICAgcmVzb3VyY2VQYWNrc0luZm8uZm9yY2VTZXJ2ZXJQYWNrc0VuYWJsZWQgPSBmYWxzZTtcbiAgICAgICAgcmVzb3VyY2VQYWNrc0luZm8uaGFzU2NyaXB0cyA9IGZhbHNlO1xuICAgICAgICByZXNvdXJjZVBhY2tzSW5mby5oYXNBZGRvblBhY2tzID0gZmFsc2U7XG4gICAgICAgIGF3YWl0IGNvbm5lY3Rpb24uc2VuZERhdGFQYWNrZXQocmVzb3VyY2VQYWNrc0luZm8sIHRydWUpO1xuICAgIH1cbn1cbiJdLCJuYW1lcyI6WyJJZGVudGlmaWVycyIsIlBsYXlTdGF0dXNQYWNrZXQiLCJQbGF5U3RhdHVzVHlwZSIsIlBsYXllciIsIlJlc291cmNlUGFja3NJbmZvUGFja2V0Il0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7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