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
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
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
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")
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 [])
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
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
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]
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!")