async def listenForPackets(self,
                               packetDict: dict = {},
                               headerSize: int = 1,
                               ignoreUnknownPackets: bool = False,
                               timeout: int = NET_TIMEOUT):
        try:
            # Reading First Byte For Packet Header
            rawData = await asyncio.wait_for(
                self.handler.reader.readexactly(
                    headerSize  # Size of packet header
                ),
                timeout)
            Logger.verbose(
                f"CLIENT -> SERVER | CLIENT: {self.handler.ip} | Incoming Player Loop Packet Id {rawData}",
                module="network")

            # Convert Packet Header to Int
            packetHeader = int.from_bytes(rawData, byteorder="big")

            # Check if packet is to be expected
            if packetHeader not in packetDict.keys():
                # Ignore if ignoreUnknownPackets flag is set
                if not ignoreUnknownPackets:
                    Logger.debug(
                        f"Player Sent Unknown Packet Header {rawData} ({packetHeader})",
                        module="network")
                    raise ClientError(f"Unknown Packet {packetHeader}")

            # Get packet using packetId
            packet = PacketManager.Request.getPacketById(packetHeader)

            # Reading and Appending Rest Of Packet Data (Packet Body)
            rawData += await asyncio.wait_for(
                self.handler.reader.readexactly(
                    packet.SIZE -
                    headerSize  # Size of packet body (packet minus header size)
                ),
                timeout)
            Logger.verbose(
                f"CLIENT -> SERVER | CLIENT: {self.handler.ip} | DATA: {rawData}",
                module="network")

            # Attempting to Deserialize Packets
            try:
                # Deserialize Packet
                serializedData = await packet.deserialize(
                    self.handler.player, rawData)
                return packetHeader, serializedData

            except Exception as e:
                if packet.CRITICAL or type(e) in CRITICAL_REQUEST_ERRORS:
                    raise e  # Pass Down Exception To Lower Layer
                else:
                    # TODO: Remove Hacky Type Ignore
                    return packetHeader, packet.onError(e)  # type: ignore

        except asyncio.TimeoutError:
            raise ClientError("Did Not Receive Packet In Time!")
        except Exception as e:
            raise e  # Pass Down Exception To Lower Layer
    async def sendPacket(self,
                         packet: Type[AbstractResponsePacket],
                         *args,
                         timeout: int = NET_TIMEOUT,
                         **kwargs):
        try:
            # Generate Packet
            rawData = await packet.serialize(*args, **kwargs)

            # Send Packet
            Logger.verbose(
                f"SERVER -> CLIENT | CLIENT: {self.handler.ip} | ID: {packet.ID} {packet.NAME} | SIZE: {packet.SIZE} | DATA: {rawData}",
                module="network")
            if self.handler.isConnected:
                self.handler.writer.write(bytes(rawData))
                await self.handler.writer.drain()
            else:
                Logger.debug(
                    f"Packet {packet.NAME} Skipped Due To Closed Connection!",
                    module="network")
        except Exception as e:
            # Making Sure These Errors Always Gets Raised (Ignore onError)
            if packet.CRITICAL or type(e) in CRITICAL_RESPONSE_ERRORS:
                raise e  # Pass Down Exception To Lower Layer
            else:
                # TODO: Remove Hacky Type Ignore
                return packet.onError(e)  # type: ignore
    def register(self, name: str, description: str, author: str, version: str,
                 dependencies: Optional[list], module: Type[AbstractModule]):
        Logger.info(f"Discovered Module {name}.", module="module-import")
        Logger.debug(f"Registering Module {name}", module="module-import")

        # Lowercase Name
        name = name.lower()
        # Checking If Module Is Already In Modules List
        if name in self._module_list.keys():
            raise InitRegisterError(
                f"Module {name} Has Already Been Registered!")
        # Check If Module Is Blacklisted
        if name in self._module_blacklist:
            return  # Skip
        # Format Empty Dependencies
        if dependencies is None:
            dependencies = []
        # Checking If Core Is Required
        if self._ensure_core:
            if "core" not in [m.NAME for m in dependencies] and name != "core":
                dependencies.append(Dependency("core"))

        # Attach Values As Attribute
        module.NAME = name
        module.DESCRIPTION = description
        module.AUTHOR = author
        module.VERSION = version
        module.DEPENDENCIES = dependencies
        self._module_list[name] = module
Example #4
0
    def register(self, mapGenClass: Type[AbstractMapGenerator],
                 module: AbstractModule):
        Logger.debug(
            f"Registering Map Generator {mapGenClass.NAME} From Module {module.NAME}",
            module=f"{module.NAME}-submodule-init")
        mapGen: AbstractMapGenerator = super()._initSubmodule(
            mapGenClass, module)

        # Handling Special Cases if OVERRIDE is Set
        if mapGen.OVERRIDE:
            # Check If Override Is Going To Do Anything
            # If Not, Warn
            if mapGen.NAME not in self._generator_list.keys():
                Logger.warn(
                    f"Map Generator {mapGen.NAME} From Module {mapGen.MODULE.NAME} Is Trying To Override A Map Generator That Does Not Exist! If This Is An Accident, Remove The 'override' Flag.",
                    module=f"{module.NAME}-submodule-init")
            else:
                Logger.debug(
                    f"Map Generator {mapGen.NAME} Is Overriding Map Generator {self._generator_list[mapGen.NAME].NAME}",
                    module=f"{module.NAME}-submodule-init")

        # Checking If Map Generator Name Is Already In Generators List
        # Ignoring if OVERRIDE is set
        if mapGen.NAME in self._generator_list.keys() and not mapGen.OVERRIDE:
            raise InitRegisterError(
                f"Map Generator {mapGen.NAME} Has Already Been Registered! If This Is Intentional, Set the 'override' Flag to True"
            )

        # Add Map Generator to Map Generators List
        self._generator_list[mapGen.NAME] = mapGen
Example #5
0
    def register(self, worldFormatClass: Type[AbstractWorldFormat],
                 module: AbstractModule):
        Logger.debug(
            f"Registering World Format {worldFormatClass.NAME} From Module {module.NAME}",
            module=f"{module.NAME}-submodule-init")
        worldFormat: AbstractWorldFormat = super()._initSubmodule(
            worldFormatClass, module)

        # Handling Special Cases if OVERRIDE is Set
        if worldFormat.OVERRIDE:
            # Check If Override Is Going To Do Anything
            # If Not, Warn
            if worldFormat.NAME not in self._format_list.keys():
                Logger.warn(
                    f"World Format {worldFormat.NAME} From Module {worldFormat.MODULE.NAME} Is Trying To Override A World Format That Does Not Exist! If This Is An Accident, Remove The 'override' Flag.",
                    module=f"{module.NAME}-submodule-init")
            else:
                Logger.debug(
                    f"World Format {worldFormat.NAME} Is Overriding World Format {self._format_list[worldFormat.NAME].NAME}",
                    module=f"{module.NAME}-submodule-init")

        # Checking If World Format Name Is Already In Formats List
        # Ignoring if OVERRIDE is set
        if worldFormat.NAME in self._format_list.keys(
        ) and not worldFormat.OVERRIDE:
            raise InitRegisterError(
                f"World Format {worldFormat.NAME} Has Already Been Registered! If This Is Intentional, Set the 'override' Flag to True"
            )

        # Add World Format to World Formats List
        self._format_list[worldFormat.NAME] = worldFormat
Example #6
0
 def saveWorlds(self):
     Logger.debug("Starting Attempt to Save All Worlds",
                  module="world-save")
     if self.persistant and (self.server.config.worldSaveLocation
                             is not None):
         Logger.info("Saving All Worlds...", module="world-save")
         # Loop through all worlds and attempt to save!
         for worldName, world in self.worlds.items():
             Logger.debug(f"Trying To Save World {worldName}",
                          module="world-save")
             # Check persistance
             if world.persistant:
                 try:
                     # Saving World
                     Logger.info(f"Saving World {worldName}",
                                 module="world-save")
                     world.saveMap()
                 except Exception as e:
                     Logger.error(
                         f"Error While Saving World {worldName} - {type(e).__name__}: {e}",
                         module="world-save")
             else:
                 Logger.warn(
                     f"World {worldName} Is Non Persistant! Skipping World Save!",
                     module="world-save")
     else:
         Logger.warn(
             "World Manager Is Non Persistant! Skipping World Save!",
             module="world-save")
Example #7
0
    async def setBlock(self,
                       blockX: int,
                       blockY: int,
                       blockZ: int,
                       blockId: int,
                       player: Optional[Player] = None,
                       sendPacket: bool = True):
        # Handles Block Updates In Server + Checks If Block Placement Is Allowed
        Logger.debug(
            f"Setting World Block {blockX}, {blockY}, {blockZ} to {blockId}",
            module="world")

        # Check If Block Is Out Of Range
        if blockX >= self.sizeX or blockY >= self.sizeY or blockZ >= self.sizeZ:
            raise BlockError(
                f"Block Placement Is Out Of Range ({blockX}, {blockY}, {blockZ})"
            )

        # Setting Block in MapArray
        self.mapArray[blockX + self.sizeX *
                      (blockZ + self.sizeZ * blockY)] = blockId

        if sendPacket:
            # Sending Block Update Update Packet To All Players
            await self.playerManager.sendWorldPacket(
                Packets.Response.SetBlock,
                blockX,
                blockY,
                blockZ,
                blockId,
                # not sending to self as that may cause some de-sync issues
                ignoreList=[player] if player is not None else [])
Example #8
0
    def createWorldFile(self,
                        savePath,
                        worldName,
                        worldFormat: AbstractWorldFormat = None):
        Logger.debug(f"Attempting to create world file with name {worldName}",
                     module="world-gen")
        # Checking if World is Persistant
        if self.server.config.worldSaveLocation is None or not self.persistant:
            raise WorldSaveError(
                "Trying To Create World File When Server Is Not Persistant")

        # Checking if World Format was Passed In (Setting as default if not)
        if worldFormat is None:
            worldFormat = self.worldFormat  # type: ignore

        # Generating File Path
        worldPath = os.path.join(
            SERVERPATH,
            savePath,
            worldName + "." + worldFormat.EXTENTIONS[
                0]  # Gets the first value in the valid extentions list
        )
        Logger.debug(f"File world path is {worldPath}", module="world-gen")

        # Check if file already exists
        if os.path.isfile(worldPath):
            raise WorldSaveError(
                f"Trying To Create World File {worldPath} That Already Exists")

        return open(worldPath, "wb+")
    async def handlePlayerMessage(self, message: str):
        # Format, Process, and Handle incoming player message requests.
        Logger.debug(f"Handling Player Message From Player {self.name}", module="player")

        # Checking If Player Is Joined To A World
        if self.worldPlayerManager is None:
            Logger.debug(f"Player {self.name} Trying To handleBlockUpdate When No World Is Joined", module="player")
            return None  # Skip Rest

        # Checking If Message Is A Command
        if message[0] == "/":
            try:
                await self.handlePlayerCommand(message[1:])
            except CommandError as e:
                Logger.info(f"Command From Player {self.name} Failed With {str(e)}", module="command")
                await self.sendMessage(f"&c{str(e)}")
            return None  # Skip Rest

        # Check If Last Character Is '&' (Crashes All Clients)
        if message[-1:] == "&":
            message = message[:-1]  # Cut Last Character

        if len(message) > 32:  # Cut Message If Too Long
            # Cut Message In Half, then print each half
            await self.worldPlayerManager.sendWorldMessage(message[:32] + " - ", author=self)
            await self.worldPlayerManager.sendWorldMessage(" - " + message[32:], author=self)
            await self.sendMessage("&eWARN: Message Was Cut To Fit On Screen&f")
        else:
            await self.worldPlayerManager.sendWorldMessage(message, author=self)
 def _postInit(self):
     for module_name, module_obj in list(self._module_list.items()):
         try:
             Logger.debug(
                 f"Running Post-Initialization for Module {module_name}",
                 module=f"{module_name}-postinit")
             # Calling the Final Init function
             module_obj.postInit()
         except FatalError as e:
             # Pass Down Fatal Error To Base Server
             raise e
         except Exception as e:
             # Handle Exception if Error Occurs
             self._error_list.append(
                 (module_name, "Init-Final"))  # Module Loaded WITH Errors
             # If the Error is an Postinit Error (raised on purpose), Don't print out TB
             if type(e) is PostInitError:
                 printTb = False
             else:
                 printTb = True
             Logger.error(
                 f"Error While Running Post-Initialization For {module_name} - {type(e).__name__}: {e}\n",
                 module="postinit",
                 printTb=printTb)
             Logger.warn(
                 "!!! Module Errors May Cause Compatibility Issues And/Or Data Corruption !!!\n",
                 module="postinit")
             Logger.warn(f"Skipping Module {module_name}?",
                         module="postinit")
             Logger.askConfirmation()
             # Remove Module
             Logger.warn(f"Removing Module {module_name} From Loader!",
                         module="postinit")
             del self._module_list[module_name]
    async def handleBlockUpdate(self, blockX: int, blockY: int, blockZ: int, blockType: AbstractBlock):
        # Format, Process, and Handle incoming block update requests.
        Logger.debug(f"Handling Block Placement From Player {self.name}", module="player")

        # Checking If Player Is Joined To A World
        if self.worldPlayerManager is None:
            Logger.error(f"Player {self.name} Trying To handleBlockUpdate When No World Is Joined", module="player")
            return None  # Skip Rest

        # Trying To Update Block On Player World
        try:
            await blockType.placeBlock(self, blockX, blockY, blockZ)
        except ClientError as e:
            # Setting Player-Attempted Block Back To Original
            originalBlock = self.worldPlayerManager.world.getBlock(blockX, blockY, blockZ)
            await self.networkHandler.dispacher.sendPacket(
                Packets.Response.SetBlock,
                blockX,
                blockY,
                blockZ,
                originalBlock.ID
            )

            # Send Error Message To
            await self.sendMessage(f"&c{e}&f")
    def deallocateId(self, playerId: int):
        # Check If Id Is Already Deallocated
        if self.players[playerId] is None:
            Logger.error(f"Trying To Deallocate Non Allocated Id {playerId}", module="id-allocator", printTb=False)
        self.players[playerId] = None

        Logger.debug(f"Deallocated Id {playerId}", module="id-allocator")
    async def joinPlayer(self, player: Player):
        # Trying To Allocate Id
        # Fails If All Slots Are Taken
        try:
            playerId = self.allocateId()
        except WorldError:
            raise ClientError(f"World {self.world.name} Is Full")

        # Adding Player To Players List Using Id
        Logger.debug(f"Player {player.networkHandler.ip} Username {player.name} Id {playerId} Is Joining World {self.world.name}", module="world-player")
        player.playerId = playerId
        self.players[playerId] = player

        # Solve rare edge case where Spawn coords may not be set!
        if (
            self.world.spawnX is not None and
            self.world.spawnY is not None and
            self.world.spawnZ is not None and
            self.world.spawnYaw is not None and
            self.world.spawnPitch is not None
        ):
            # Set Player Location
            # TODO saving player location
            await player.setLocation(
                self.world.spawnX,
                self.world.spawnY,
                self.world.spawnZ,
                self.world.spawnYaw,
                self.world.spawnPitch,
                notifyPlayers=False
            )
        else:
            raise ServerError("Attempted To Spawn Player to a Location That Is Not Set!")

        # Send Player Join Packet To All Players (Except Joining User)
        await self.sendWorldPacket(
            Packets.Response.SpawnPlayer,
            player.playerId,
            player.name,
            player.posX,
            player.posY,
            player.posZ,
            player.posYaw,
            player.posPitch,
            ignoreList=[player]  # Don't send packet to self!
        )

        # Update User On Currently Connected Players
        await self.spawnCurrentPlayers(player)

        Logger.debug(f"Finished Handling Player Join For {player.name} Id {player.playerId} Joined World {self.world.name}", module="world-player")

        # Sending Join Chat Message
        await self.sendWorldMessage(f"&e{player.name} Joined The World &9(ID {player.playerId})&f")

        # Sending Warning If World Is Non-Persistant
        if not self.world.persistant:
            await player.sendMessage("&cWARNING: This world is Non-Persistant!&f")
            await player.sendMessage("&cAny changes WILL NOT be saved!!&f")
 def _importModules(self):
     # Initialize Temporary List of Files Imported
     _module_files = []
     # Walk Through All Packages And Import Library
     for _, module_name, _ in pkgutil.walk_packages(
         [os.path.join(SERVERPATH, MODULESFOLDER)]):
         # Load Modules
         Logger.debug(f"Detected Module {module_name}",
                      module="module-import")
         if module_name not in self._module_blacklist:
             try:
                 Logger.verbose(
                     f"Module {module_name} Not In Blacklist. Adding!",
                     module="module-import")
                 # Import Module
                 _module = importlib.import_module(MODULESIMPORT +
                                                   module_name)
                 # Appending To A List of Module Files to be Used Later
                 _module_files.append(module_name)
                 # Set the Imported Module into the Global Scope
                 globals()[module_name] = _module
             except FatalError as e:
                 # Pass Down Fatal Error To Base Server
                 raise e
             except Exception as e:
                 # Handle Exception if Error Occurs
                 self._error_list.append(
                     (module_name,
                      "PreInit-Import"))  # Module Loaded WITH Errors
                 # If the Error is a Register Error (raised on purpose), Don't print out TB
                 if type(e) is InitRegisterError:
                     printTb = False
                 else:
                     printTb = True
                 Logger.error(
                     f"Error While Importing Module {module_name} - {type(e).__name__}: {e}\n",
                     module="module-import",
                     printTb=printTb)
                 Logger.warn(
                     "!!! Fatal Module Errors May Cause Compatibility Issues And/Or Data Corruption !!!\n",
                     module="module-import")
                 Logger.askConfirmation()
         else:
             Logger.verbose(
                 f"Skipping Module {module_name} Due To Blacklist",
                 module="module-import")
     Logger.verbose(f"Detected and Imported Module Files {_module_files}",
                    module="module-import")
     # Check If Core Was Loaded
     if self._ensure_core:
         if "core" not in self._module_list.keys():
             self._error_list.append(
                 ("core",
                  "PreInit-EnsureCore"))  # Module Loaded WITH Errors
             raise FatalError(
                 "Error While Loading Module core - Critical Module Not Found"
             )
    def allocateId(self):
        # Loop Through All Ids, Return Id That Is Not Free
        Logger.debug("Trying To Allocate Id", module="id-allocator")
        for idIndex, playerObj in enumerate(self.players):
            if playerObj is None:
                # Return Free ID
                return idIndex

        raise WorldError("Id Allocator Failed To Allocate Open Id")
    async def sendMessage(self, message: Union[str, list]):
        Logger.debug(f"Sending Player {self.name} Message {message}", module="player")
        # If Message Is A List, Recursively Send All Messages Within
        if type(message) is list:
            Logger.debug("Sending List Of Messages To Player!")
            for msg in message:
                await self.sendMessage(msg)
            return None  # Break Out of Function

        await self.networkHandler.dispacher.sendPacket(Packets.Response.SendMessage, str(message))
 async def createPlayer(self, network: NetworkHandler, username: str, verificationKey: str):
     Logger.debug(f"Creating Player For Ip {network.ip}", module="player-manager")
     # Creating Player Class
     player = Player(self, network, username, verificationKey)
     # Checking if server is full
     if len(self.players) >= self.maxSize:
         raise ClientError("Server Is Full!")
     # Adding Player Class
     self.players.append(player)
     return player
Example #18
0
 def _ensureFileStructure(self, folders: Union[str, List[str]]):
     # Check Type, If Str Put In List
     if type(folders) is str:
         folders = [folders]
     Logger.debug(f"Ensuring Folders {folders}", module="init")
     # Ensure All Folders
     for folder in folders:
         folder = os.path.join(SERVERPATH, folder)
         if not os.path.exists(folder):
             Logger.debug(f"Creating Folder Structure {folder}", module="init")
             os.makedirs(folder)
    def _resolveDependencyCycles(self):
        # Helper Function To Run Down Module Dependency Tree To Check For Cycles
        def _ensureNoCycles(current: Type[AbstractModule],
                            previous: List[str]):
            Logger.verbose(
                f"Travelling Down Dependency Tree. CUR: {current} PREV: {previous}",
                module="cycle-check")
            # If Current Name Appears In Any Previous Dependency, There Is An Infinite Cycle
            if current.NAME in previous:
                raise DependencyError(
                    f"Circular dependency Detected: {' -> '.join([*previous, current.NAME])}"
                )

            Logger.verbose(
                f"Current Modules Has Dependencies {current.DEPENDENCIES}",
                module="cycle-check")
            # Run DFS through All Dependencies
            for dependency in current.DEPENDENCIES:
                _ensureNoCycles(dependency.MODULE, [*previous, current.NAME])

        for module_name, module_obj in list(self._module_list.items()):
            try:
                Logger.debug(
                    f"Ensuring No Circular Dependencies For Module {module_name}",
                    module="module-verify")
                # Run DFS Through All Decencies To Check If Cycle Exists
                _ensureNoCycles(module_obj, [])
            except FatalError as e:
                # Pass Down Fatal Error To Base Server
                raise e
            except Exception as e:
                # Handle Exception if Error Occurs
                self._error_list.append(
                    (module_name,
                     "PreInit-Dependency"))  # Module Loaded WITH Errors
                # If the Error is a Dependency Error (raised on purpose), Don't print out TB
                if type(e) is DependencyError:
                    printTb = False
                else:
                    printTb = True
                Logger.error(
                    f"Error While Resolving Dependency Cycles For {module_name} - {type(e).__name__}: {e}\n",
                    module="module-verify",
                    printTb=printTb)
                Logger.warn(
                    "!!! Module Errors May Cause Compatibility Issues And/Or Data Corruption !!!\n",
                    module="module-verify")
                Logger.warn(f"Skipping Module {module_name}?",
                            module="module-verify")
                Logger.askConfirmation()
                # Remove Module
                Logger.warn(f"Removing Module {module_name} From Loader!",
                            module="module-verify")
                del self._module_list[module_name]
    async def _initConnection(self):
        # Log Connection
        Logger.info(f"New Connection From {self.ip}", module="network")

        # Check if user is IP banned
        if self.ip[0] in self.server.config.ipBlacklist:
            Logger.info(f"IP {self.ip} Is Blacklisted. Kicking!",
                        module="network")
            raise ClientError("Your IP Has Been Blacklisted From The Server!")

        # Start the server <-> client login protocol
        Logger.debug(f"{self.ip} | Starting Client <-> Server Handshake",
                     module="network")
        await self._handleInitialHandshake()
    def register(self, commandClass: Type[AbstractCommand],
                 module: AbstractModule):
        Logger.debug(
            f"Registering Command {commandClass.NAME} From Module {module.NAME}",
            module=f"{module.NAME}-submodule-init")
        command: AbstractCommand = super()._initSubmodule(commandClass, module)

        # Handling Special Cases if OVERRIDE is Set
        if command.OVERRIDE:
            # Check If Override Is Going To Do Anything
            # If Not, Warn
            if command.NAME not in self._command_list.keys():
                Logger.warn(
                    f"Command {command.NAME}  From Module {command.MODULE.NAME} Is Trying To Override A Command That Does Not Exist! If This Is An Accident, Remove The 'override' Flag.",
                    module=f"{module.NAME}-submodule-init")
            else:
                Logger.debug(
                    f"Command {command.NAME} Is Overriding Command {self._command_list[command.NAME].NAME}",
                    module=f"{module.NAME}-submodule-init")
                # Un-registering All Activators for the Command Being Overwritten. Prevents Issues!
                Logger.debug(
                    f"Un-registering Activators for Command {self._command_list[command.NAME].NAME}",
                    module=f"{module.NAME}-submodule-init")
                for activator in list(
                        self._command_list[command.NAME].ACTIVATORS.keys()):
                    # Deleting from Cache
                    del self._activators[activator]

        # Checking If Command Name Is Already In Commands List
        # Ignoring if OVERRIDE is set
        if command.NAME in self._command_list.keys() and not command.OVERRIDE:
            raise InitRegisterError(
                f"Command {command.NAME} Has Already Been Registered! If This Is Intentional, Set the 'override' Flag to True"
            )

        # Setting Activators To Default If None
        if command.ACTIVATORS is None:
            command.ACTIVATORS = []
        if len(command.ACTIVATORS) == 0:
            Logger.warn(
                f"Command {command.NAME} Was Registered Without Any Activators. Using Name As Command Activator.",
                module=f"{module.NAME}-submodule-init")
            command.ACTIVATORS = [command.NAME.lower()]
        # Add Activators To Command Cache
        Logger.debug(
            f"Adding Activators {command.ACTIVATORS} To Activator Cache",
            module=f"{module.NAME}-submodule-init")
        for activator in command.ACTIVATORS:
            Logger.verbose(f"Adding Activator {activator}",
                           module=f"{module.NAME}-submodule-init")
            # If Activator Already Exists, Error
            if activator not in self._activators:
                self._activators[activator] = command
            else:
                raise InitRegisterError(
                    f"Another Command Has Already Registered Command Activator {activator}"
                )

        # Add Command to Commands List
        self._command_list[command.NAME] = command
    async def sendWorldData(self, world: World):
        # Send Level Initialize Packet
        Logger.debug(f"{self.ip} | Sending Level Initialize Packet",
                     module="network")
        await self.dispacher.sendPacket(Packets.Response.LevelInitialize)

        # Preparing To Send Map
        Logger.debug(f"{self.ip} | Preparing To Send Map", module="network")
        worldGzip = world.gzipMap(includeSizeHeader=True)  # Generate GZIP
        # World Data Needs To Be Sent In Chunks Of 1024 Characters
        chunks = [
            worldGzip[i:i + 1024] for i in range(0, len(worldGzip), 1024)
        ]

        # Looping Through All Chunks And Sending Data
        Logger.debug(f"{self.ip} | Sending Chunk Data", module="network")
        for chunkCount, chunk in enumerate(chunks):
            # Sending Chunk Data
            Logger.verbose(
                f"{self.ip} | Sending Chunk Data {chunkCount + 1} of {len(chunks)}",
                module="network")
            await self.dispacher.sendPacket(
                Packets.Response.LevelDataChunk,
                chunk,
                percentComplete=int((100 / len(chunks)) * chunkCount))

        # Send Level Finalize Packet
        Logger.debug(f"{self.ip} | Sending Level Finalize Packet",
                     module="network")
        await self.dispacher.sendPacket(Packets.Response.LevelFinalize,
                                        world.sizeX, world.sizeY, world.sizeZ)
    def _initSubmodule(self, submodule: Any, module: AbstractModule):
        Logger.debug(
            f"Initializing {submodule.MANAGER.NAME} {submodule.NAME} From Module {module.NAME}",
            module=f"{module.NAME}-submodule-init")
        # Create Object
        obj = submodule()
        # Initialize and Transfer Object Variables
        obj.NAME = submodule.NAME
        obj.DESCRIPTION = submodule.DESCRIPTION
        obj.VERSION = submodule.VERSION
        obj.OVERRIDE = submodule.OVERRIDE
        obj.MANAGER = submodule.MANAGER
        obj.MODULE = module

        return obj
    def register(self, packetClass: Type[AbstractPacket],
                 module: AbstractModule):
        Logger.debug(
            f"Registering Packet {packetClass.NAME} From Module {module.NAME}",
            module=f"{module.NAME}-submodule-init")
        packet: AbstractPacket = super()._initSubmodule(packetClass, module)

        # Handling Special Cases if OVERRIDE is Set
        if packet.OVERRIDE:
            # Check If Override Is Going To Do Anything
            # If Not, Warn
            if (packet.ID not in self._packet_list.keys()) and (
                    packet.NAME not in self.getAllPacketIds()):
                Logger.warn(
                    f"Packet {packet.NAME} (ID: {packet.ID}) From Module {packet.MODULE.NAME} Is Trying To Override A Packet That Does Not Exist! If This Is An Accident, Remove The 'override' Flag.",
                    module=f"{module.NAME}-submodule-init")
            else:
                Logger.debug(
                    f"Packet {packet.NAME} Is Overriding Packet {self._packet_list[packet.NAME].NAME} (ID: {packet.ID})",
                    module=f"{module.NAME}-submodule-init")

        # Checking If Packet And PacketId Is Already In Packets List
        # Ignoring if OVERRIDE is set
        if packet.NAME in self._packet_list.keys() and not packet.OVERRIDE:
            raise InitRegisterError(
                f"Packet {packet.NAME} Has Already Been Registered! If This Is Intentional, Set the 'override' Flag to True"
            )
        if packet.ID in self.getAllPacketIds() and not packet.OVERRIDE:
            raise InitRegisterError(
                f"Packet Id {packet.ID} Has Already Been Registered! If This Is Intentional, Set the 'override' Flag to True"
            )

        # Only Used If Request
        if self.direction is PacketDirections.REQUEST:
            # Cast Packet into Request Packet Type
            requestPacket: AbstractRequestPacket = packet  # type: ignore
            # Add To Packet Cache If Packet Is Used In Main Player Loop
            if requestPacket.PLAYERLOOP:
                Logger.verbose(
                    f"Adding Packet {requestPacket.ID} To Main Player Loop Request Packet Cache",
                    module=f"{module.NAME}-submodule-init")
                self.loopPackets[requestPacket.ID] = requestPacket

        # Add Packet to Packets List
        self._packet_list[packet.NAME] = packet
Example #25
0
 def _load(self, fileIO: io.TextIOWrapper):
     Logger.debug(f"Loading Config With FileIO {fileIO}", "config-load")
     # Set Internal Attributes If It Exists
     configData = json.load(fileIO)
     Logger.verbose(f"Config data Is {configData}", "config-load")
     for configKey, configValue in configData.items():
         Logger.verbose(f"Checking Config Attribute {configKey}",
                        "config-load")
         # Checking If Key Exists In Config AND If Its Not Part Of The Overrides
         if hasattr(self,
                    configKey) and configKey not in self.configOverrides:
             Logger.verbose(
                 f"Setting Config Attribute {configKey} to {configValue}",
                 "config-load")
             setattr(self, configKey, configValue)
         else:
             Logger.warn(f"Ignoring Unknown Config Attribute {configKey}",
                         "config-load")
    async def removePlayer(self, player: Player):
        Logger.debug(f"Removing Player {player.name} From World {self.world.name}", module="world-player")
        # Delete User From Player List + Deallocate ID
        if player.playerId is not None:
            self.deallocateId(player.playerId)
        else:
            raise ServerError(f"Trying to Remove Player {player.name} With No Player Id")

        # Send Player Disconnect Packet To All Players (Except Joining User)
        await self.sendWorldPacket(
            Packets.Response.DespawnPlayer,
            player.playerId,
            ignoreList=[player]  # Don't send packet to self!
        )

        Logger.debug(f"Removed Player {player.networkHandler.ip} Username {player.name} Id {player.playerId} Joined World {self.world.name}", module="world-player")

        # Sending Leave Chat Message
        await self.sendWorldMessage(f"&e{player.name} Left The World &9(ID {player.playerId})&f")
 def _initSubmodules(self):
     # Loop through all the submodules in the order of the sorted graph
     for module in self._sorted_module_graph:
         try:
             # Loop Through All Items within Module
             Logger.debug(f"Checking All Items in {module.NAME}",
                          module=f"{module.NAME}-submodule-init")
             # Loop Through All Items In Class
             for _, item in module.__dict__.items():
                 # Check If Item Has "obsidian_submodule" Flag
                 if hasattr(item, "obsidian_submodule"):
                     Logger.verbose(
                         f"{item} Is A Submodule! Adding As {module.NAME} Submodule.",
                         module=f"{module.NAME}-submodule-init")
                     # Register Submodule Using information Provided by Submodule Class
                     item.MANAGER.register(item, module)
         except FatalError as e:
             # Pass Down Fatal Error To Base Server
             raise e
         except Exception as e:
             # Handle Exception if Error Occurs
             self._error_list.append(
                 (module.NAME,
                  "Init-Submodule"))  # Module Loaded WITH Errors
             # If the Error is an Init Error (raised on purpose), Don't print out TB
             if type(e) is InitError:
                 printTb = False
             else:
                 printTb = True
             Logger.error(
                 f"Error While Initializing Submodules For {module.NAME} - {type(e).__name__}: {e}\n",
                 module="submodule-init",
                 printTb=printTb)
             Logger.warn(
                 "!!! Module Errors May Cause Compatibility Issues And/Or Data Corruption !!!\n",
                 module="submodule-init")
             Logger.warn(f"Skipping Module {module.NAME}?",
                         module="submodule-init")
             Logger.askConfirmation()
             # Remove Module
             Logger.warn(f"Removing Module {module.NAME} From Loader!",
                         module="submodule-init")
             del self._module_list[module.NAME]
Example #28
0
    def generateMap(self, sizeX, sizeY, sizeZ, generator: AbstractMapGenerator,
                    *args, **kwargs):
        Logger.debug(
            f"Generating World With Size {sizeX}, {sizeY}, {sizeX} With Generator {generator.NAME}",
            module="init-world")
        # Call Generate Map Function From Generator
        generatedMap = generator.generateMap(sizeX, sizeY, sizeZ, *args,
                                             **kwargs)

        # Verify Map Data Size
        expectedSize = sizeX * sizeY * sizeZ
        if len(generatedMap) != expectedSize:
            raise MapGenerationError(
                f"Expected Map Size {expectedSize} While Generating World. Got {len(generatedMap)}"
            )

        Logger.debug(f"Generated Map With Final Size Of {len(generatedMap)}",
                     module="init-world")
        # Return Generated Map Bytesarray
        return generatedMap
 def _initModules(self):
     for module in self._sorted_module_graph:
         try:
             Logger.debug(f"Initializing Module {module.NAME}",
                          module=f"{module.NAME}-init")
             # Initialize Module
             initializedModule = module()
             # Initialize and Transfer Module Variables
             initializedModule.NAME = module.NAME
             initializedModule.DESCRIPTION = module.DESCRIPTION
             initializedModule.AUTHOR = module.AUTHOR
             initializedModule.VERSION = module.VERSION
             initializedModule.DEPENDENCIES = module.DEPENDENCIES
             # Replacing Item in _module_list with the Initialized Version!
             self._module_list[module.NAME] = initializedModule
         except FatalError as e:
             # Pass Down Fatal Error To Base Server
             raise e
         except Exception as e:
             # Handle Exception if Error Occurs
             self._error_list.append(
                 (module.NAME, "Init-Module"))  # Module Loaded WITH Errors
             # If the Error is an Init Error (raised on purpose), Don't print out TB
             if type(e) is InitError:
                 printTb = False
             else:
                 printTb = True
             Logger.error(
                 f"Error While Initializing Modules For {module.NAME} - {type(e).__name__}: {e}\n",
                 module="module-init",
                 printTb=printTb)
             Logger.warn(
                 "!!! Module Errors May Cause Compatibility Issues And/Or Data Corruption !!!\n",
                 module="module-init")
             Logger.warn(f"Skipping Module {module.NAME}?",
                         module="module-init")
             Logger.askConfirmation()
             # Remove Module
             Logger.warn(f"Removing Module {module.NAME} From Loader!",
                         module="module-init")
             del self._module_list[module.NAME]
    async def handlePlayerCommand(self, cmdMessage: str):
        # Format, Process, and Handle incoming player commands.
        Logger.debug(f"Handling Command From Player {self.name}", module="command")

        # Splitting Command Data
        cmdName, *cmdArgs = cmdMessage.split(" ")
        Logger.info(f"Command {cmdName} Received From Player {self.name}", module="command")
        Logger.debug(f"Handling Command {cmdName} With Arguments {cmdArgs}", module="command")

        # Get Command Object
        command = Commands.getCommandFromName(cmdName)

        # Parse Command Arguments
        parsedArguments, parsedKwArgs = _parseArgs(command, cmdArgs)

        # Run Command
        try:
            await command.execute(self, *parsedArguments, **parsedKwArgs)
        except Exception as e:
            Logger.error(f"Command {command.NAME} Raised Error {str(e)}", module="command")
            await self.sendMessage("&cAn Unknown Internal Server Error Has Occurred!")