Beispiel #1
0
class SoundEngine():
    def __init__(self):
        self.oP = OutPipe("SoundEngine", 0)
        self.eI = EngineInterface()
        self.sD = SubtitleDrawer(self)

        self.subtitles = 1
        self.language = "en"

        self.device = aud.device()

        self.sounds = {}
        self.dialogs = {}

        self.music = None
        self.musicHandle = None

        self.playbacks = []
        self.dialogPlaybacks = []

        self.videoAudio = None

        self.masterVolume = 1.0
        self.dialogVolume = 1.0
        self.musicVolume = 1.0
        self.soundVolume = 1.0

        self.setMasterVolume(1.0)

        self.oP("Initialized.")

    def preLoadAudio(self):
        self.oP("Preloading audio files...")
        f = open(GAME_PATH + "preload_audio" + TEXT_EXT, "r")
        try:
            data = eval(f.read())
        except:
            pass
        f.close()

        for i in data:
            if i[1] == "sound":
                self.loadSound(i[0])
            if i[1] == "music":
                self.loadSound(i[0], music=True)
            if i[1] == "dialog":
                self.loadSound(i[0], dialog=True)

    def setMasterVolume(self, volume):
        self.masterVolume = volume * 0.1
        self.device.volume = self.masterVolume

    def setDialogVolume(self, volume):
        self.dialogVolume = volume * 0.1
        for key in self.dialogs.keys():
            self.sounds[key].volume = self.soundVolume
        for i in self.dialogPlaybacks:
            i.volume = self.soundVolume

    def setMusicVolume(self, volume):
        self.musicVolume = volume * 0.1
        if self.music:
            self.music.volume = self.musicVolume
        if self.musicHandle:
            self.musicHandle.volume = self.musicVolume

    def setSoundVolume(self, volume):
        self.soundVolume = volume * 0.1
        for key in self.sounds.keys():
            self.sounds[key].volume = self.soundVolume
        for i in self.playbacks:
            i.volume = self.soundVolume

    def loop(self):
        self.listener = self.eI.getMainScene().active_camera

        self.device.listener_location = self.listener.worldPosition
        self.device.listener_orientation = self.listener.worldOrientation.to_quaternion(
        )
        self.device.listener_velocity = self.listener.getLinearVelocity()

        #Update 3D positioning
        for playback in self.playbacks + self.dialogPlaybacks:
            if playback[1].status == True:
                if playback[0]:
                    playback[1].relative = False
                    playback[1].location = playback[0].worldPosition
                    playback[1].orientation = playback[
                        0].worldOrientation.to_quaternion()
                    playback[1].velocity = playback[0].getLinearVelocity()
                else:
                    playback[1].relative = False
                    playback[1].location = self.listener.worldPosition
                    playback[
                        1].orientation = self.listener.worldOrientation.to_quaternion(
                        )
                    playback[1].velocity = self.listener.getLinearVelocity()
            #Garbage collection
            else:
                if playback in self.playbacks:
                    self.playbacks.remove(playback)
                break

        #Clear subtitles
        for playback in self.dialogPlaybacks:
            if playback[1].status == False:
                if self.sD.currentSubtitle == playback[2]:
                    self.sD.clearSubtitle()
                self.dialogPlaybacks.remove(playback)
                break

        #Music positioning and garbage collection
        if self.musicHandle and self.musicHandle.status == True:
            self.musicHandle.relative = False
            self.musicHandle.location = self.listener.worldPosition
            self.musicHandle.orientation = self.listener.worldOrientation.to_quaternion(
            )
            self.musicHandle.velocity = self.listener.getLinearVelocity()
        elif self.musicHandle and self.musicHandle.status == False:
            self.musicHandle = None

    def load(self, location, name):
        path = LOCATIONS[location]
        if "Dialog" in path:
            path += self.language + "/"
        cR = ContentReader(path + name)
        return cR

    def loadSound(self, sound, music=False, dialog=False):
        if dialog:
            cR = self.load("Dialog", sound)
            EXT = DIALOG_EXT
            PATH = DIALOG_PATH + self.language + "/"
        elif not music:
            cR = self.load("Sound", sound)
            EXT = SOUND_EXT
            PATH = SOUND_PATH
        else:
            cR = self.load("Music", sound)
            EXT = MUSIC_EXT
            PATH = MUSIC_PATH

        name = cR.get("name")
        volume = cR.get("volume")
        loop = cR.get("loop")
        sound3D = cR.get("3D")
        resourceNames = cR.get("resources")
        resources = []

        for n in resourceNames:
            try:
                factory = aud.Factory.file(PATH + n + EXT)

                #Configure specific volumes
                if dialog:
                    factory = factory.volume(self.dialogVolume)
                elif not music:
                    factory = factory.volume(self.soundVolume)
                else:
                    factory = factory.volume(self.musicVolume)

                if loop:
                    factory = factory.loop(-1)
                resources.append(factory)
                self.oP("Loaded sound resource %s." % (n + EXT))
            except:
                self.oP("Failed to load sound resource %s." % (n + EXT))

        self.oP("Loaded sound %s." % sound)

        if dialog:
            self.dialogs[name] = Sound(self, name, sound3D, resources)
        elif not music:
            self.sounds[name] = Sound(self, name, sound3D, resources)
        else:
            self.music = Sound(self, name, sound3D, resources)

    def playSound(self, sound, emitter=None):
        if not sound in self.sounds:
            self.loadSound(sound)

        if sound in self.sounds:
            soundObject = self.sounds[sound]
            handle = soundObject.play()
            self.playbacks.append([emitter, handle, sound])

        return handle

    def stopSound(self, handle):
        handle.stop()
        for playback in self.playbacks:
            if playback[1] == handle:
                self.playbacks.remove(playback)
                return playback[0].GUID, playback[2]

    def playDialog(self, dialog, emitter=None):
        if not dialog in self.dialogs:
            self.loadSound(dialog, dialog=True)

        if dialog in self.dialogs:
            dialogObject = self.dialogs[dialog]
            handle = dialogObject.play()
            self.dialogPlaybacks.append([emitter, handle, dialog])
            self.sD.drawSubtitle(dialog)

        return handle

    def stopDialog(self, handle):
        handle.stop()
        for playback in self.dialogPlaybacks:
            if playback[1] == handle:
                self.dialogPlaybacks.remove(playback)
                return playback[0].GUID, playback[2]

    def stopSoundByGUID(self, GUID, name):
        for playback in self.playbacks:
            if playback[0]["GUID"] == GUID and playback[2] == name:
                playback[1].stop()
                self.playbacks.remove(playback)

    def playMusic(self, music):
        if self.music:
            self.stopMusic()

        self.loadSound(music, music=True)
        self.musicHandle = self.music.play()
        self.oP("Started music %s." % music)

    def stopMusic(self):
        if self.music:
            self.music.stop()
            self.music = None
        self.oP("Stopped music.")

    def playVideoAudio(self, name):
        resource = aud.Factory.file(VIDEO_PATH + name + SOUND_EXT)
        resource = resource.volume(self.soundVolume)
        try:
            self.videoAudio = self.device.play(resource, False)
        except:
            pass

    def stopVideoAudio(self):
        if self.videoAudio:
            self.videoAudio.stop()
            self.videoAudio = None
        self.oP("Stopped video audio.")
Beispiel #2
0
class Server(GameSide):
    def __init__(self):
        '''Initializes the server.'''
        self.mode = "server"

        self.oP = OutPipe("Server", 0)
        self.nC = None

        self.cvars = {
            "sv_addr": "0.0.0.0",
            "sv_port": 7777,
            "sv_netlog": 0,
            "sv_level": "",
            "sv_game": 0,
            "sv_singleplayer": 0,
            "sv_gamemode": "singleplayer",
            "sv_startscript": "",
            "sv_master": "",
            "sv_dedicated": 0,
            "sv_chat": 1,
            "sv_background_red": 0,
            "sv_background_green": 0,
            "sv_background_blue": 0,
            "sv_background_alpha": 0,
            "sv_password": "",
            "cl_language": "en",
            "cl_subtitles": 1,
            "cl_width": 1280,
            "cl_height": 720,
            "cl_fullscreen": 0,
            "cl_motionblur": 0,
            "cl_motionblur_amount": 0,
            "cl_anisotropic": 1,
            "cl_mipmap": "none",
            "cl_vsync": "off",
            "cl_musicvolume": 10,
            "cl_dialogvolume": 10,
            "cl_soundvolume": 10,
            "cl_netping": 0,
        }

        self.netVars = {}

        self.oldNetVars = self.netVars
        self.oldcvars = self.cvars

        self.gameMode = None
        self.level = None

        self.unassignedPlayers = []

        self.entities = []

        self.events = []

        self.saveFile = None

        self.chatMessages = []

        self.eI = EngineInterface(True)
        self.sE = ScriptExecuter()
        self.pR = PhysicsReader(self)
        self.sH = ShaderHandler()
        self.l = Localizer(self)

        self.updateNetwork()

        self.forceUpdateCVars()

        self.keepAliveTicker = 0
        self.trackedProperties = []

        loadServer(self)

        self.oP("Initialized.")

    def forceUpdateCVars(self):
        '''Forces all the cVars to run their updaters as though they had just been set.'''
        for key in self.cvars.keys():
            if not "cl_" == key[:3]:
                self.configure(key, self.get(key), override=True)
        self.oP("Force updated cVars.")

    def configureNetVar(self, var, val):
        '''Configures a NetVar and updates clients about it.'''
        self.netVars[var] = val
        self.events.append([None, ["SYSTEM", "NETVARS", [var, val]]])
        self.oP("Configured netVar %s to %s." % (str(var), str(val)))

    def configure(self, key, val, override=False):
        '''Configure a cvar.'''
        changed = False

        if key in self.cvars.keys():
            #Switch for int
            if type(self.cvars[key]) == type(0):
                val = int(val)

            #Used for functions
            if type(self.cvars[key]) == type(self.configure):
                self.cvars[key](val)
                self.oP("CVar %s executed." % key)
            else:
                if val != self.cvars[key] or override:
                    changed = True
                    self.cvars[key] = val
                    self.sendEvent([None, ["SYSTEM", "CVARS", [key, val]]])
                    self.oP("CVar %s configured to %s (%s)." %
                            (key, val, str(type(val)).replace(
                                "<class '", "").replace("'>", "")))
        else:
            self.oP("CVar %s not present." % key)

        if changed:
            self.updateGame(key)

    def endGame(self):
        '''Ends the game instance.'''
        self.oP("Ending game instance.")
        self.endGameMode()
        self.endLevel()

    def endGameMode(self):
        '''Ends the game mode.'''
        if hasattr(self.gameMode, "kill"):
            self.gameMode.kill()
        self.gameMode = None

    def replaceMesh(self, ent, meshName):
        '''Replaces the mesh of an entity.'''
        cR = self.load("Mesh", meshName)

        name = cR.get("name")
        resourcePath = cR.get("resourcePath")

        self.loadLibrary("Mesh", resourcePath, mesh=True)

        for obj in self.eI.getMainScene().objectsInactive:
            if obj.name == meshName:
                meshName = obj.meshes[0]
                break

        ent.gameObject.replaceMesh(meshName, True, True)
        self.sendEvent([None, ["PHYSICS", "MESH", [ent.GUID, meshName]]])
        self.oP("Replaced mesh of %s with %s." % (ent.GUID, meshName))

    def quitGame(self):
        '''Ends the game and kills network connections.'''
        self.oP("Shutting down...")
        self.endGame()
        self.purgeNetwork()

    def setGameMode(self, name):
        '''Load a gamemode into the engine.'''
        self.sE.addContext("Server", self)
        self.sE.execute(GAMEMODE_PATH + name)
        self.gameMode = self.newGamemode(self)

    def updateNetwork(self):
        '''Update the network module for changes to port or addr'''
        self.purgeNetwork()

        self.nC = NetCore()
        if self.get("sv_netlog"):
            self.nC.configure("DEBUG", True)
            self.nC.configure("VERBOSE", True)
        else:
            self.nC.configure("DEBUG", False)
            self.nC.configure("VERBOSE", False)

        self.nC.pingcount = self.get("cl_netping")

        self.nC.configure("NAME", "Server")
        self.nC.setProtocol("UDP")
        self.nC.configure("HOST", self.get("sv_addr"))
        self.nC.configure("PORT", self.get("sv_port"))
        self.nC.initialize()

    def purgeNetwork(self):
        '''Destroys the NetCore once and for all.'''
        if self.nC:
            self.nC.clear()
            self.nC.destroy()
            self.nC = None

    def setMusic(self, music):
        '''Sets the music track.'''
        launcher = self.eI.getGlobal("launcher")

        launcher.sound.playMusic(music)
        self.events.append([None, ["SYSTEM", "MUSIC_PLAY", [music, 0.0]]])
        self.oP("Set music to %s." % music)

    def stopMusic(self):
        '''Stops the music track.'''
        launcher = self.eI.getGlobal("launcher")

        launcher.sound.stopMusic()
        self.events.append([None, ["SYSTEM", "MUSIC_STOP", None]])

    def playSound(self, sound, emitter=None):
        '''Plays a sound.'''
        launcher = self.eI.getGlobal("launcher")

        if emitter:
            launcher.sound.playSound(sound, emitter.gameObject)
            self.events.append(
                [None, ["SYSTEM", "SOUND_PLAY", [emitter.GUID, sound]]])
        else:
            launcher.sound.playSound(sound)
            self.events.append([None, ["SYSTEM", "SOUND_PLAY", [None, sound]]])

        self.oP("Started sound %s." % sound)

    def stopSound(self, handle):
        '''Stops a sound.'''
        launcher = self.eI.getGlobal("launcher")

        GUID, sound = launcher.sound.stopSound(handle)

        self.events.append(["SYSTEM", "SOUND_STOP", [emitter.GUID, sound]])
        self.oP("Stopped sound %s." % sound)

    def stopSoundByGUID(self, GUID, name):
        '''Stops a sound.'''
        launcher = self.eI.getGlobal("launcher")

        GUID, sound = launcher.sound.stopSoundByGUID(GUID, name)
        self.oP("Stopped sound %s." % sound)

        self.events.append(["SYSTEM", "SOUND_STOP", [emitter.GUID, sound]])
        self.oP("Stopped sound %s." % sound)

    def playDialog(self, sound, emitter=None):
        '''Plays a dialog line.'''
        launcher = self.eI.getGlobal("launcher")

        if emitter:
            launcher.sound.playDialog(sound, emitter.gameObject)
            self.events.append(
                [None, ["SYSTEM", "DIALOG_PLAY", [emitter.GUID, sound]]])
        else:
            launcher.sound.playDialog(sound)
            self.events.append(
                [None, ["SYSTEM", "DIALOG_PLAY", [None, sound]]])

        self.oP("Started dialog %s." % sound)

    def stopDialog(self, handle):
        '''Stops a dialog line.'''
        launcher = self.eI.getGlobal("launcher")

        GUID, sound = launcher.sound.stopDialog(handle)

        self.events.append(["SYSTEM", "DIALOG_STOP", [emitter.GUID, sound]])
        self.oP("Stopped dialog %s." % sound)

    def stopDialogByGUID(self, GUID, name):
        '''Stops a dialog line.'''
        launcher = self.eI.getGlobal("launcher")

        GUID, sound = launcher.sound.stopDialogByGUID(GUID, name)
        self.oP("Stopped dialog %s." % sound)

        self.events.append(["SYSTEM", "DIALOG_STOP", [emitter.GUID, sound]])
        self.oP("Stopped dialog %s." % sound)

    def enableShader(self, index, name, mode):
        '''Enables a shader as a filter for the entire screen.'''
        self.sH.enableShader(index, name, mode)

    def disableShader(self, index):
        '''Disables a shader that was filtering the entire screen.'''
        self.sH.disableShader(index)

    def updateGame(self, key):
        '''Reacts to changes to the cVars.'''
        if key == "sv_gamemode" and self.get("sv_game"):
            self.setGameMode(self.get("sv_gamemode"))
        elif key == "sv_level" and self.get("sv_game"):
            self.configure("sv_game", 0)
            self.configure("sv_game", 1)
        elif key == "sv_game":
            if self.get("sv_game"):
                self.setGameMode(self.get("sv_gamemode"))
                self.setLevel(self.get("sv_level"))
            else:
                self.endGame()
        elif key == "sv_port" or key == "sv_addr":
            self.updateNetwork()
        elif key == "sv_startscript":
            self.sE.addContext("Server", self)
            self.sE.execute(self.get("sv_startscript"))

        elif key in [
                "sv_background_red", "sv_background_green",
                "sv_background_blue", "sv_background_alpha"
        ] and not self.get("cl_master"):
            self.eI.setBackgroundColor((self.getBackgroundColor()))

        elif key == "sv_netlog":
            if self.get("sv_netlog"):
                self.nC.configure("DEBUG", True)
                self.nC.configure("VERBOSE", True)
            else:
                self.nC.configure("DEBUG", False)
                self.nC.configure("VERBOSE", False)

        elif key == "cl_width" or key == "cl_height":
            self.eI.setResolution(self.get("cl_width"), self.get("cl_height"))
        elif key == "cl_fullscreen":
            self.eI.setFullscreen(self.get("cl_fullscreen"))
        elif key == "cl_motionblur" or key == "cl_motionblur_amount":
            self.eI.setMotionBlur(self.get("cl_motionblur"),
                                  self.get("cl_motionblur_amount"))
        elif key == "cl_anisotropic":
            self.eI.setAnisotropic(self.get("cl_anisotropic"))
        elif key == "cl_mipmap":
            self.eI.setMipmapping(self.get("cl_mipmap"))
        elif key == "cl_vsync":
            self.eI.setVSync(self.get("cl_vsync"))

        elif key == "cl_mastervolume":
            launcher = self.eI.getGlobal("launcher")

            if launcher:
                launcher.sound.setMasterVolume(self.get("cl_mastervolume"))

        elif key == "cl_musicvolume":
            launcher = self.eI.getGlobal("launcher")

            if launcher:
                launcher.sound.setMusicVolume(self.get("cl_musicvolume"))

        elif key == "cl_dialogvolume":
            launcher = self.eI.getGlobal("launcher")

            if launcher:
                launcher.sound.setDialogVolume(self.get("cl_dialogvolume"))

        elif key == "cl_soundvolume":
            launcher = self.eI.getGlobal("launcher")

            if launcher:
                launcher.sound.setSoundVolume(self.get("cl_soundvolume"))

        elif key == "cl_subtitles":
            launcher = self.eI.getGlobal("launcher")

            if launcher:
                launcher.sound.subtitles = self.get("cl_subtitles")

        elif key == "cl_language":
            launcher = self.eI.getGlobal("launcher")

            if launcher:
                launcher.sound.language = self.get("cl_language")

        elif key == "cl_netping":
            self.nC.pingcount = self.get("cl_netping")

    def getEmergencyUpdate(self, cli):
        '''Gets a special update to repair desynced clients.'''
        events = []

        for var in self.cvars:
            if not "cl_" == var[:3]:
                events.append(
                    [cli, ["SYSTEM", "CVARS", [var, self.cvars[var]]]])

        for var in self.netVars:
            events.append(
                [cli, ["SYSTEM", "NETVARS", [var, self.netVars[var]]]])

        return events

    def setPlayerCamera(self, cli, GUID):
        '''Set a client's current camera.'''
        self.events.append([cli, ["SYSTEM", "SET_CAMERA", GUID]])
        if cli:
            self.oP("Set client %s camera to be %s" % (str(cli.addr), GUID))
        else:
            self.oP("Set all client cameras to be %s" % GUID)

    def checkServer(self):
        '''Runs server loops and checks for events.'''
        events = []

        #CVar based events
        for key in self.cvars.keys():
            if not key in self.oldcvars or self.cvars[key] != self.oldcvars[
                    key]:
                events.append(["SYSTEM", "CVARS", [key, self.cvars[key]]])

        self.oldcvars = self.cvars

        if self.gameMode:
            self.gameMode.loop()

        #Other game events
        events += self.events
        self.events = []

        return events

    def sendChatMessage(self, msg, client=None):
        '''Sends a chat message to the client(s).'''
        self.sendEvent([client, ["SYSTEM", "CHAT", msg]])
        self.chatMessages.append(msg)

    def sendEvent(self, event):
        '''Sends an event to the client(s).'''
        if (event[1][0] == "PHYSICS" and not event[1][1]
                in ["CREATE", "DELETE"]) or event[1] == "KEEPALIVE":
            mode = "FAF"
        else:
            mode = "RT"

        #Send global events
        if event[0] == None:
            for cli in self.nC.clients:
                if cli.userProps["confirmed"] or not self.get("sv_password"):
                    cli.send(event[1], mode)
        #Send one user events
        else:
            if event[0].userProps["confirmed"] or not self.get("sv_password"):
                event[0].send(event[1], mode)

    def recvEvent(self, cli, event):
        '''Handles an event from a client.'''
        if type(event) == type([]) and len(event) >= 3:
            if event[0] == "INPUT":

                if event[1] == "COMMAND" or event[1] == "INTERFACE":
                    if cli.userProps["player"]:
                        cli.userProps["player"].pushCommand(event[2])

            elif event[0] == "SYSTEM":

                if event[1] == "PHYSICS":
                    if event[2] == "FORCEUPDATE" and not cli.userProps[
                            "synced"]:
                        events = self.pR.getEmergencyUpdate(cli)
                        events += self.getEmergencyUpdate(cli)
                        for event in events:
                            self.sendEvent(event)
                        cli.userProps["synced"] = True

                elif event[1] == "CVARS":
                    if cli.addr[0] == self.get("sv_master"):
                        self.configure(event[2][0], event[2][1])

                elif event[1] == "CHAT" and self.get("sv_chat"):
                    self.chatMessages.append(event[2])
                    self.sendEvent([None, event])

                elif event[1] == "NAME":
                    if cli.userProps["player"]:
                        cli.userProps["player"].username = event[2]
                    cli.userProps["username"] = event[2]

                elif event[1] == "PASSWORD":
                    if event[2] == self.get("sv_password"):
                        cli.userProps["confirmed"] = True

            elif event[0] == "GAME":
                self.gameMode.pushGameEvent([event[1], event[2]])

    def openSaveFile(self, name):
        '''Opens the save file.'''
        try:
            self.saveFile = shelve.open(SAVE_PATH + name + SAVE_EXT)
            self.oP("Opened save file %s." % (SAVE_PATH + name + SAVE_EXT))
            return True
        except:
            self.saveFile = None
            self.oP("Failed to open save file %s." %
                    (SAVE_PAT + name + SAVE_EXT))
            return False

    def closeSaveFile(self):
        '''Closes the save file.'''
        if self.saveFile != None:
            self.saveFile.close()
            self.oP("Closed the save file.")
            self.saveFile = None

    def saveSaveFile(self):
        '''Saves the save file.'''
        if self.saveFile != None:
            self.oP("Saved the save file.")
            self.saveFile.sync()

    def saveState(self):
        '''Saves the game state.'''
        self.oP("Saving entity state.")
        self.openSaveFile("save")

        if self.saveFile != None:
            data = Sarcophagus()

            for ent in self.entities:
                #if ent.name != "avatar":
                self.saveEntity(ent, data)

            for cli in self.nC.clients:
                if cli.userProps["player"]:
                    self.savePlayer(cli.userProps["player"], data)

            for player in self.unassignedPlayers:
                self.savePlayer(player, data)

            records, playerRecords = data.cleanUp()

            try:
                self.saveFile["data"] = data
                self.oP("Saved data to save file.")
            except:
                self.oP("Failed to save data to save file.")

            self.saveSaveFile()

        self.closeSaveFile()

        data.restore(records, playerRecords)

        for ent in self.entities:
            #if ent.name != "avatar":
            data.reconstructEntity(ent)

        for cli in self.nC.clients:
            if cli.userProps["player"]:
                data.reconstructPlayer(cli.userProps["player"])

        for player in self.unassignedPlayers:
            data.reconstructPlayer(player)

    def loadState(self):
        '''Loads the game state.'''
        self.oP("Loading entity state.")
        self.openSaveFile("save")

        if self.saveFile != None:
            if "data" in self.saveFile.keys():
                container = self.saveFile["data"]
                for entry in container.entities:
                    self.loadEntity(entry)
                for player in container.players:
                    self.loadPlayer(player)

        self.closeSaveFile()

    def saveEntity(self, ent, data):
        '''Saves an Entity to the sarcophagus.'''
        objData = self.pR.getObjectData(ent)
        data.deconstructEntity(ent)
        data.addEntity(ent, objData)

    def savePlayer(self, player, data):
        '''Saves a Player to the sarcophagus.'''
        data.deconstructPlayer(player)
        data.addPlayer(player)

    def loadEntity(self, entry):
        '''Reconstructs an Entity.'''
        ent = entry[0]

        ent.reconstructObject(entry[1])

        self.oP("Retrieved entity %s from save file." % ent.GUID)

        self.entities.append(ent)

    def loadPlayer(self, player):
        '''Reconstructs a player.'''
        player.reconstructPlayer(self)

        self.oP("Retrieved player %s from save file." % player.username)

        self.unassignedPlayers.append(player)

    def getOldPlayer(self, name):
        '''Checks for an unassigned player.'''
        for player in self.unassignedPlayers:
            if player.username == name:
                return player

    def removeOldPlayer(self, player):
        '''Removes a player from the unassigned list.'''
        self.unassignedPlayers.remove(player)

    def disconnectPlayer(self, cli):
        '''Handles the disconnection of a player.'''
        if cli.userProps["player"]:
            cli.userProps["player"].cli = None
            self.unassignedPlayers.append(cli.userProps["player"])

    def loop(self):
        '''Does everything basically.'''

        #cl = OptiClock()

        #Detector Index
        self.updateDetectorIndex()

        #cl.clockIn("DetectorIndex")

        #KEEP ALIVE
        self.keepAliveTicker += 1
        if self.keepAliveTicker % 600 == 0:
            self.sendEvent([None, "KEEPALIVE"])

        #cl.clockIn("KeepAlive")

        #RECV THINGS###############################################

        for cli in self.nC.clients:
            #Make sure only one client gets through on singleplayer
            if not self.get("sv_singleplayer") or len(self.nC.clients) <= 1:
                #Create a player once the username is collected
                if not cli.userProps["player"] and "username" in cli.userProps:
                    player = self.getOldPlayer(cli.userProps["username"])
                    if player:
                        self.oP("Client's previous avatar found, reassigning.")
                        cli.userProps["player"] = player
                        player.cli = cli
                        player.reLinkPlayer()
                        self.removeOldPlayer(cli.userProps["player"])
                    else:
                        self.oP("Client gets a new avatar.")
                        cli.userProps["player"] = Player(self, cli)
                    cli.disconnectFunc = cli.userProps["player"].destruct
                #If a player has been created
                elif cli.userProps["player"]:
                    cli.userProps["player"].loop()

            packet = cli.recv()

            if packet:
                payload = packet.getPayload()

                try:
                    data = eval(payload)
                except:
                    data = None

                if data:
                    self.recvEvent(cli, data)

        #cl.clockIn("RecvLoop")

        #CHANGE THINGS###########################################

        #Apply Shaders
        self.sH.loop()

        #cl.clockIn("Shaders")

        #Localize text
        self.l.loop()

        #cl.clockIn("Localization")

        #Entities loop
        for ent in self.entities:
            ent.checkPhysics()
            ent.checkAnimation()

            if hasattr(ent, "loop"):
                #print(ent)
                ent.loop(self, "server")

        #cl.clockIn("Entities")

        #Physics Read Loop
        events = self.pR.loop()

        #cl.clockIn("Physics")

        #Self Read Loop

        events += self.checkServer()

        #cl.clockIn("GameEvents")

        #Gamerules Loop
        if hasattr(self.gameMode, "loop"):
            self.gameMode.loop()

        #cl.clockIn("GameMode")

        #Level loop
        if self.level and hasattr(self.level, "loop"):
            self.level.loop(self, "server")

        #cl.clockIn("Level")

        #SEND THINGS###############################################

        #Send Events
        for event in events:
            self.sendEvent(event)

        #cl.clockIn("SendLoop")

        #KILL THINGS###################################################
        kill = self.nC.pullKillQueue()

        if kill and self.gameMode:
            kill()

        #cl.clockIn("Kill")

        self.nC.loop()