Пример #1
0
class SubtitleDrawer():
    def __init__(self, master):
        self.oP = OutPipe("SubtitleDrawer", 0)
        self.eI = EngineInterface()
        self.master = master

        self.currentSubtitle = None

        self.oP("Initialized.")

    def drawSubtitle(self, subtitle):
        if self.master.subtitles:
            drawSubtitle = self.eI.getGlobal("drawSubtitle")

            subtitlesFile = open(
                DIALOG_PATH + self.master.language + "/" + "dialogs" +
                TEXT_EXT, "r")

            self.currentSubtitle = subtitle

            try:
                subtitles = eval(subtitlesFile.read())
                drawSubtitle(subtitles[subtitle])
            except:
                self.oP("Failed to read subtitles.")
                drawSubtitle(subtitle)

            subtitlesFile.close()

    def clearSubtitle(self):
        clearSubtitle = self.eI.getGlobal("clearSubtitle")

        clearSubtitle()
Пример #2
0
class VideoPlayer():
    def __init__(self):
        self.oP = OutPipe("VideoPlayer", 0)
        self.eI = EngineInterface()

        self.oP("Initialized.")

    def playVideo(self, video):
        playVideo = self.eI.getGlobal("playVideo")

        if playVideo:
            self.eI.l.globalDict["launcher"].sound.playVideoAudio(video)
            playVideo(VIDEO_PATH + video + VIDEO_EXT)

            self.oP("Requested video playback.")

    def stopVideo(self):
        stopVideo = self.eI.getGlobal("stopVideo")

        if stopVideo:
            self.eI.l.globalDict["launcher"].sound.stopVideoAudio()
            stopVideo()

            self.oP("Stopped video playback.")

    def loop(self):
        isVideoFinished = self.eI.getGlobal("isVideoFinished")

        if isVideoFinished:
            if isVideoFinished():
                self.oP("Video end detected, stopping video.")
                self.stopVideo()
Пример #3
0
class Interface():
    def __init__(self, name, resource, scriptName):
        self.oP = OutPipe("Interface - " + name, 0)
        self.eI = EngineInterface(objectMode=False)
        self.sE = ScriptExecuter()

        self.name = name

        self.gameObject = None

        self.sE.addContext("Interface", self)
        self.sE.execute(scriptName)

        self.eI.getGlobal("addToQueue")(resource, name, self)

        if hasattr(self, "init"):
            self.init()

        self.oP("Added interface %s." % name)

    def __str__(self):
        return self.name

    def __repr__(self):
        return self.name

    def kill(self):
        self.eI.removeInterface(self.name)
Пример #4
0
class InputReceiver():
    def __init__(self):
        self.oP = OutPipe("InputReceiver", 0)
        self.cR = ConfigReader(GAME_PATH + "controls")
        self.sE = ScriptExecuter()
        self.eI = EngineInterface(objectMode=False)
        self.keyboard = self.eI.getKeyboard()
        self.mouse = self.eI.getMouse()
        self.tH = TypingHandler(self.keyboard)
        self.pairs = {}
        self.responses = {}
        self.oldKeyboard = self.keyboard.events
        self.oldMouse = self.mouse.events

        self.sE.addContext("Input", self)
        self.sE.execute(INPUT_PATH + "csp")
        self.sE.execute(INPUT_PATH + "input")

        self.keyEvents = []

        self.readControls()

        self.locked = False
        self.xsens = 50
        self.ysens = 50
        self.inverted = 0
        self.predict = False

        self.recent = {}

        self.oP("Initialized.")

    def addEvent(self, event):
        if not event in self.recent.keys():
            self.keyEvents.append(["INPUT", "COMMAND", event])

            if not type(event) == type(tuple()):
                self.recent[event] = time.time()

            if self.predict:
                self.callClientSidePrediction(event)

    def callClientSidePrediction(self, event):
        if not type(event) == type(tuple()):
            if hasattr(self, "csp_" + event):
                getattr(self, "csp_" + event)()
        else:
            if hasattr(self, "csp_look"):
                getattr(self, "csp_look")(event)

    def readControls(self):
        keys = self.cR.getAllOptions("CONTROLS")

        for key in keys:
            keyString = self.cR.get("CONTROLS", key)
            keyCode = self.eI.getKeyCode(keyString)
            try:
                self.pairs[keyCode] = getattr(self, key)
                self.oP("Read in key response %s successfully." % key)
            except:
                self.oP("Failed to read in key response %s successfully." %
                        key)

    def checkControls(self):
        for keyCode in self.pairs.keys():
            if keyCode in self.keyboard.events and not self.locked:
                if self.keyboard.events[keyCode] == self.eI.l.KX_INPUT_ACTIVE:
                    self.callCommand("KEYBOARD", keyCode)
                elif self.keyboard.events[
                        keyCode] == self.eI.l.KX_INPUT_JUST_ACTIVATED:
                    self.callCommand("KEYBOARD", keyCode)
                elif self.keyboard.events[
                        keyCode] == self.eI.l.KX_INPUT_JUST_RELEASED:
                    self.callCommand("KEYBOARD", keyCode)

            elif keyCode in self.mouse.events:
                if self.mouse.events[keyCode] == self.eI.l.KX_INPUT_ACTIVE:
                    self.callCommand("MOUSE", keyCode)
                elif self.mouse.events[
                        keyCode] == self.eI.l.KX_INPUT_JUST_ACTIVATED:
                    self.callCommand("MOUSE", keyCode)
                elif self.mouse.events[
                        keyCode] == self.eI.l.KX_INPUT_JUST_RELEASED:
                    self.callCommand("MOUSE", keyCode)

        self.oldKeyboard = self.keyboard.events
        self.oldMouse = self.mouse.events

        #Handle the "recent" spam blocker
        keys = self.recent.keys()
        for key in keys:
            if abs(self.recent[key] - time.time()) > 0.1:
                del self.recent[key]
                break

        if self.locked:
            self.tH.process()

    def callCommand(self, mode, keyCode):
        if mode == "KEYBOARD":
            state = self.getState(self.keyboard.events[keyCode],
                                  self.oldKeyboard[keyCode])
        elif mode == "MOUSE":
            state = self.getState(self.mouse.events[keyCode],
                                  self.oldMouse[keyCode])

        consumed = False

        if state == "DEACTIVATE" and keyCode in [
                self.eI.e.LEFTMOUSE, self.eI.e.RIGHTMOUSE
        ]:
            consumed = self.checkInterfaceClick(keyCode, self.mouse.position)

        if not consumed and not keyCode in [
                self.eI.e.MOUSEX, self.eI.e.MOUSEY
        ]:
            self.pairs[keyCode](state)
        elif keyCode in [self.eI.e.MOUSEX, self.eI.e.MOUSEY]:
            pos = self.mouse.position
            self.pairs[keyCode](pos)

    def checkInterfaceClick(self, keyCode, pos):
        return self.eI.getGlobal("client").inputClick(keyCode, pos)

    def getState(self, newstate, oldstate):
        if newstate == self.eI.l.KX_INPUT_ACTIVE:
            if oldstate == self.eI.l.KX_INPUT_ACTIVE:
                return "ACTIVE"
            elif oldstate == self.eI.l.KX_INPUT_NONE:
                return "ACTIVATE"
            elif oldstate == self.eI.l.KX_INPUT_JUST_ACTIVATED:
                return "ACTIVATE"
            elif oldstate == self.eI.l.KX_INPUT_JUST_RELEASED:
                return "ACTIVATE"

        if newstate == self.eI.l.KX_INPUT_NONE:
            if oldstate == self.eI.l.KX_INPUT_ACTIVE:
                return "DEACTIVATE"
            elif oldstate == self.eI.l.KX_INPUT_NONE:
                return "INACTIVE"
            elif oldstate == self.eI.l.KX_INPUT_JUST_ACTIVATED:
                return "DEACTIVATE"
            elif oldstate == self.eI.l.KX_INPUT_JUST_RELEASED:
                return "DEACTIVATE"

        if newstate == self.eI.l.KX_INPUT_JUST_ACTIVATED:
            if oldstate == self.eI.l.KX_INPUT_ACTIVE:
                return "ACTIVATE"
            elif oldstate == self.eI.l.KX_INPUT_NONE:
                return "ACTIVATE"
            elif oldstate == self.eI.l.KX_INPUT_JUST_ACTIVATED:
                return "ACTIVATE"
            elif oldstate == self.eI.l.KX_INPUT_JUST_RELEASED:
                return "ACTIVATE"

        if newstate == self.eI.l.KX_INPUT_JUST_RELEASED:
            if oldstate == self.eI.l.KX_INPUT_ACTIVE:
                return "DEACTIVATE"
            elif oldstate == self.eI.l.KX_INPUT_NONE:
                return "DEACTIVATE"
            elif oldstate == self.eI.l.KX_INPUT_JUST_ACTIVATED:
                return "DEACTIVATE"
            elif oldstate == self.eI.l.KX_INPUT_JUST_RELEASED:
                return "DEACTIVATE"
Пример #5
0
class ShaderHandler():
    def __init__(self):
        self.oP = OutPipe("ShaderHandler", 0)
        self.eI = EngineInterface()

        self.actionQueue = []
        self.actionCooldown = 0

        self.oldObjectCount = 0

        self.oP("Initialized.")

    def enableShader(self, index, name, mode):
        self.actionQueue.append(["enable", index, name, mode])

    def disableShader(self, index):
        self.actionQueue.append(["disable", index])

    def doShaderAction(self):
        if not self.actionQueue:
            return

        action = self.actionQueue.pop()

        if action[0] == "enable":
            index = action[1]
            name = action[2]
            mode = action[3]

            launcher = self.eI.getGlobal("launcher")

            text = ""

            if mode == "fragment":
                fsh = open(SHADER_PATH + name + FSHADER_EXT, "r")

                text = fsh.read()

                fsh.close()
            elif mode == "vertex":
                vsh = open(SHADER_PATH + name + VSHADER_EXT, "r")

                text = vsh.read()

                vsh.close()
            else:
                return

            launcher.enableShader(index, text)

        elif action[0] == "disable":
            index = action[1]

            launcher = self.eI.getGlobal("launcher")

            launcher.disableShader(index)

        self.actionCooldown = 120

    def loop(self):
        objects = self.eI.getAllObjects()

        if self.oldObjectCount != len(objects):
            for obj in objects:
                if "shader" in obj and not "shaderLoaded" in obj:
                    fsh = open(SHADER_PATH + obj["shader"] + FSHADER_EXT, "r")

                    fShaderText = fsh.read()

                    fsh.close()

                    vsh = open(SHADER_PATH + obj["shader"] + VSHADER_EXT, "r")

                    vShaderText = vsh.read()

                    vsh.close()

                    mesh = obj.meshes[0]
                    for mat in mesh.materials:
                        shader = mat.getShader()
                        if shader != None and not shader.isValid():
                            shader.setSource(vShaderText, fShaderText, 1)

                    obj["shaderLoaded"] = True
            self.oldObjectCount = len(objects)

        if self.actionCooldown > 0:
            self.actionCooldown -= 1
        else:
            self.doShaderAction()
Пример #6
0
from engineinterface import EngineInterface

eI = EngineInterface()

client = eI.getGlobal("client")

client.configure("cl_showmouse", 1)

client.playVideo("intro")

client.addInterface("TitleScreen")
Пример #7
0
class NetCore():
    def __init__(self):

        #Socket
        self.__s = None

        #Queues
        self.__sq = []
        self.__rq = []

        #Incremental IDs
        self.__packetIDOut = -1

        #Clients
        self.clients = []

        #Acknowledgements
        self.__requiredAcks = {}

        #Shutdown
        self.killThread = False
        self.killQueue = []

        #Logging
        self.NAME = ""
        self.DEBUG = False
        self.VERBOSE = False
        self.DATADUMP = False

        #Network
        self.BUFFER = 1024
        self.HOST = "0.0.0.0"
        self.PORT = 7777

        #Config
        self.PROTO = ""
        self.DUPLEX = True
        self.FORCESEND = False
        self.FORCERECV = False

        #Blocking/Timeout
        self.BLOCK = 0
        self.TIMEOUT = 0.001

        #FIXME REMOVE FOR RE-USE
        self.eI = EngineInterface()
        self.pingcount = 1

        self.pr("Started NetCore.")

    def configure(self, name, value):
        '''Changes a configuration property of the NetCore.'''
        if type(name) == type("") and hasattr(self, name):
            setattr(self, name, value)
            self.pr("%s configured to %s." % (name, str(value)))
            return True

        self.pr("Configuration failed.")
        return False

    def setProtocol(self, proto):
        '''Sets the protocol used to a particular protocol.'''
        self.pr("Setting protocol...")
        if type(proto) == type(""):
            if proto.lower() == "udp":
                self.PROTO = SOCK_DGRAM
                self.pr("Protocol set successful.")
                return True
            elif proto.lower() == "tcp":
                self.PROTO = SOCK_STREAM
                self.pr("Protocol set successful.")
                return True

        self.pr("Protocol set failed.")
        return False

    def clear(self):
        '''Resets the NetCore and shuts down the network.'''
        if self.__s:
            self.__s.close()

        self.__s = None

        self.__sq = []
        self.__rq = []
        self.clients = []
        self.__packetIDOut = -1
        self.__packetIDIn = -1
        self.__requiredAcks = {}
        self.killQueue = []

        self.pr("Purged system.")

    def destroy(self):
        '''Exits the NetCore thread.'''
        self.killThread = True
        self.pr("NetCore scheduled to be destroyed.")

    def initialize(self):
        '''Initializes the socket.'''
        self.__startSocket()
        self.__bind()
        self.__configSocket()
        #self.__startLoop()

    def pullKillQueue(self):
        '''Pulls a kill handler from the queue.'''
        if self.killQueue:
            i = self.killQueue[0]
            self.killQueue = self.killQueue[1:]
            return i

    def pushKillQueue(self, i):
        '''Pushs a kill callback to the queue.'''
        self.killQueue.append(i)

    def __removeClient(self, cli):
        '''Removes a client from the NetCore, queues it's kill callback.'''
        if cli.disconnectFunc:
            self.pushKillQueue(cli.disconnectFunc)
        self.clients.remove(cli)

    def __selectIPVersion(self):
        '''Gets the current IP version.'''
        for res in getaddrinfo(self.HOST, self.PORT, AF_UNSPEC, self.PROTO, 0,
                               AI_PASSIVE):
            return res

    def __startSocket(self):
        '''Initializes the socket.'''
        self.pr("Initializing socket...")
        try:
            res = self.__selectIPVersion()
            self.__s = socket(res[0], res[1])
            self.pr("Socket initialized.")
            return True
        except:
            self.pr("Socket initialization failed.", True)
            return False

    def __bind(self):
        '''Binds the socket.'''
        if self.DUPLEX:
            try:
                self.__s.bind((self.HOST, self.PORT))
                self.pr("Bind succeeded.")
                return True
            except:
                self.pr("Bind failed.", True)
                return False
        else:
            self.pr("Bind not completed because NetCore is not set to DUPLEX.")
            return False

    def __configSocket(self):
        '''Configures the block and timeout properties of the socket.'''
        self.pr("Configuring socket...")
        self.__s.setblocking(self.BLOCK)
        self.__s.settimeout(self.TIMEOUT)
        self.pr("Socket configured.")

    def __startLoop(self):
        '''Starts the NetCore loop.'''
        self.pr("Starting loop...")
        t = Thread(target=self.loop, name="NetCore Loop")
        t.start()
        self.pr("Loop started.")

    def deconstructMultiPacket(self, packet, source):
        '''Takes apart a multi-packet to recover the original packets.'''
        packets = []

        lastSplit = 0
        counter = 0

        skip = False

        for char in packet:
            if not skip:
                if char == byt("&")[0] and packet[counter + 1] == byt("&")[0]:
                    skip = True
                elif char == byt("&")[0] and not packet[counter +
                                                        1] == byt("&")[0]:
                    packetData = packet[lastSplit:counter]
                    packets.append(Packet(packetData, source, "PACKET"))

                    lastSplit = counter + 1
            else:
                skip = False
            counter += 1

        packets.append(Packet(packet[lastSplit:], source, "PACKET"))

        return packets

    def removeUsedPackets(self, mP):
        '''Clears out any queued packets used to make a multipacket.'''
        for ID in mP.ids:
            counter = 0
            while counter < len(self.__sq):
                if self.__sq[counter].headers["PACKETID"] == ID:
                    self.__sq = self.__sq[:counter] + self.__sq[counter + 1:]
                    break
                counter += 1

    def __recv(self):
        '''Socket level receipt of data.'''
        try:
            packet, source = self.__s.recvfrom(self.BUFFER)
            self.pr("Packet received from %s." % (str(source)))
            self.pr("Packet recv contents: " + str(packet), v=True)
            self.pr("Packet received size %i." % (len(packet)), v=True)
            packets = self.deconstructMultiPacket(packet, source)
            return packets
        except:
            #self.pr("Packet receive failed, Error: %s" % (format_exc()), v=True)
            return None

    def __send(self, packet):
        '''Socket level transmission of data.'''
        try:
            self.__s.sendto(packet.getPacket(), packet.addr)
            self.pr("Packet #%i sent to %s." %
                    (packet.packets[0].headers["PACKETID"], str(packet.addr)))
            self.pr("Packet sent size %i." % (len(packet.getPacket())), v=True)
            self.pr((("Packet #%i sent contents: " %
                      (packet.packets[0].headers["PACKETID"])) +
                     str(packet.getPacket())),
                    v=True)
            return True
        except:
            self.pr("Packet #%i failed to send. Error: %s" %
                    (packet.packets[0].headers["PACKETID"], str(format_exc())),
                    v=True)
            return False

    def loop(self):
        '''The main loop of the NetCore.'''

        #SEND
        while len(self.__sq) > 0:
            #Combine packets together
            mP = None

            if self.__sq[0].length() < self.BUFFER:
                destination = self.__sq[0].addr
                key = 0
                mP = MultiPacket(self.__sq[0].addr)
                mP.addPacket(self.__sq[0])

                for packet in self.__sq:
                    if key != 0 and packet.addr == destination:
                        if mP.length() + packet.length() + 1 < self.BUFFER:
                            mP.addPacket(packet)
                    key += 1
            if mP:
                self.writeLog(mP, 1)
                self.__send(mP)
                self.removeUsedPackets(mP)
            else:
                self.__send(self.__sq[0])
                self.__sq = self.__sq[1:]

            if not self.FORCESEND:
                break

        #RECV
        if self.DUPLEX:
            while 1:
                packets = self.__recv()

                if packets:
                    for packet in packets:
                        self.writeLog(packet, 0)
                        self.__rq.append(packet)
                else:
                    break

                if not self.FORCERECV:
                    break

            while self.__rq:
                self.__processPacket(self.__rq[0])
                self.__rq = self.__rq[1:]

        #TIMEOUT
        for cli in self.clients:
            #FIXME REMOVE FOR RE-USE
            if time.time(
            ) - cli.lastreceived > TIMEOUT_MIN and cli.lastreceived != -1:
                self.eI.getGlobal("drawDisconnect")(
                    cli.addr[0], cli.addr[1],
                    TIMEOUT - (time.time() - cli.lastreceived))
            else:
                self.eI.getGlobal("clearDisconnect")()

            if time.time(
            ) - cli.lastreceived > TIMEOUT and cli.lastreceived != -1:
                self.send(Packet("", cli.addr, "PAYLOAD"), "DISCONN")
                try:
                    self.__removeClient(cli)
                except:
                    self.pr("Client could not be removed.")
                self.pr("Client %s was disconnected for inactivity." %
                        (str(cli.addr)))
                self.eI.getGlobal("clearDisconnect")()

        #Acknowledgements
        for key in self.__requiredAcks.keys():
            try:
                msg = self.__requiredAcks[key]

                if time.time() - msg["timesent"] > TIMEOUT_PACKET:
                    del self.__requiredAcks[key]
                    packet = msg["packet"]
                    self.pr("Resending packet #%i." % key)
                    if msg["tries"] == -1:
                        self.__resend(packet)
                    elif msg["tries"] > 0:
                        self.__resend(packet, msg["tries"] - 1)
                    break
            except:
                pass

    def __getNextPacketID(self):
        '''Gets and increments the outgoing packet ID.'''
        self.__packetIDOut += 1

        return self.__packetIDOut

    def send(self, packet, mode, ack=0):
        '''Called by SubSockets when they need to send.'''
        h = {}

        h["PROTOID"] = 540

        h["PACKETID"] = self.__getNextPacketID()

        if mode == "FAF":
            h["ACK"] = -1
            h["NEEDACK"] = 0
            h["CONN"] = 0
            h["DISCARD"] = 1

        elif mode == "RT":
            h["ACK"] = -1
            h["NEEDACK"] = 1
            h["CONN"] = 0
            h["DISCARD"] = 0

        elif mode == "ACK":
            h["ACK"] = ack
            h["NEEDACK"] = 0
            h["CONN"] = 0
            h["DISCARD"] = 0

        elif mode == "CONN":
            h["ACK"] = -1
            h["NEEDACK"] = 1
            h["CONN"] = 1
            h["DISCARD"] = 0

        elif mode == "DISCONN":
            h["ACK"] = -1
            h["NEEDACK"] = 2
            h["CONN"] = 2
            h["DISCARD"] = 0

        packet.headers = h

        if h["NEEDACK"] == 1:
            self.__requiredAcks[h["PACKETID"]] = {
                "packet": packet,
                "timesent": time.time(),
                "tries": -1
            }
        elif h["NEEDACK"] == 2:
            self.__requiredAcks[h["PACKETID"]] = {
                "packet": packet,
                "timesent": time.time(),
                "tries": 3
            }

        self.__sq.append(packet)

    def __resend(self, packet, tries=-1):
        '''Queues a packet for retransmission.'''
        packet.headers["PACKETID"] = self.__getNextPacketID()

        self.__requiredAcks[packet.headers["PACKETID"]] = {
            "packet": packet,
            "timesent": time.time(),
            "tries": tries
        }

        self.__sq.append(packet)

    def __sendAcknowledgement(self, addr, packetID):
        if self.__sq:
            for packet in self.__sq:
                if packet.headers["ACK"] == -1:
                    packet.headers["ACK"] = packetID
                    break
        else:
            self.send(Packet("", addr, "PAYLOAD"), "ACK", packetID)

    def __processPacket(self, packet):
        '''Handles a received packet.'''
        h = packet.headers

        self.pr("Processing packet...", v=True)
        if "PROTOID" in h:
            self.pr("Packet headers are intact.", v=True)
            if h["PROTOID"] == 540:
                self.pr("Protocol is correct.", v=True)

                #Check if this packet comes from a pre-existing client
                done = False
                for cli in self.clients:
                    if cli.addr == packet.addr:
                        cli.lastreceived = time.time()
                        done = True
                        break

                if not done or (
                    (h["PACKETID"] > cli.getInPacketID() or not h["DISCARD"])
                        and not h["PACKETID"] in cli.receivedIDs):
                    self.pr("Packet #%i is in order and is not a duplicate." %
                            (h["PACKETID"]),
                            v=True)

                    #Client only stream security
                    if done:
                        if h["PACKETID"] > cli.getInPacketID():
                            cli.setInPacketID(h["PACKETID"])

                        cli.receivedIDs.append(h["PACKETID"])

                    #Acknowledge sendback
                    if h["NEEDACK"]:
                        self.pr("Packet #%i being acknowledged." %
                                (h["PACKETID"]))
                        self.__sendAcknowledgement(packet.addr, h["PACKETID"])

                    #Check for onboard acks
                    if h["ACK"] != -1:
                        self.pr("Packet #%i is carrying an acknowledgement." %
                                h["PACKETID"],
                                v=True)
                        if h["ACK"] in self.__requiredAcks.keys():
                            #Connection ack
                            if self.__requiredAcks[
                                    h["ACK"]]["packet"].headers["CONN"] == 1:
                                self.pr("Connection to %s acknowledged." %
                                        (str(packet.addr)))
                            #Disconnection ack
                            elif self.__requiredAcks[
                                    h["ACK"]]["packet"].headers["CONN"] == 2:
                                self.pr("Disconnection from %s acknowledged." %
                                        (str(packet.addr)))
                            #General acks
                            else:
                                entry = self.__requiredAcks[h["ACK"]]

                                #FIXME Remove for reuse
                                if self.pingcount:
                                    self.eI.getGlobal("drawPing")(
                                        packet.addr[0], packet.addr[1],
                                        (time.time() - entry["timesent"]) *
                                        1000)
                                else:
                                    self.eI.getGlobal("clearPing")()

                                del self.__requiredAcks[h["ACK"]]
                                self.pr(
                                    "Packet #%i acknowledged on #%i accepted."
                                    % (h["ACK"], h["PACKETID"]))

                    #Handle other packets
                    else:
                        #Normal Packets
                        if h["CONN"] == 0:
                            self.pr(
                                "Packet #%i is normal, sending to client object."
                                % h["PACKETID"],
                                v=True)
                            for cli in self.clients:
                                if cli.addr == packet.addr:
                                    cli.pushRecv(packet)
                                    break

                        #Connect packets
                        elif h["CONN"] == 1:
                            self.pr("Connect packet #%i received from %s." %
                                    (h["PACKETID"], str(packet.addr)))
                            alreadyExists = False
                            for cli in self.clients:
                                if cli.addr == (packet.addr[0],
                                                int(packet.getPayload())):
                                    alreadyExists = True
                                    break
                            if not alreadyExists:
                                self.clients.append(
                                    SubSocket(self,
                                              (packet.addr[0],
                                               int(packet.getPayload()))))

                        #Disconnect packets
                        elif h["CONN"] == 2:
                            self.pr("Disconnect packet #%i received from %s." %
                                    (h["PACKETID"], str(packet.addr)))
                            for cli in self.clients:
                                if cli.addr == packet.addr:
                                    self.__removeClient(cli)
                else:
                    pass
                    self.pr("Packet #%i rejected for being out of order." %
                            h["PACKETID"],
                            v=True)
            else:
                pass
                self.pr("Packet rejected for incorrect PROTOID.")
        else:
            self.pr("Packet rejected for incorrect headers.")
            return False

    def connect(self, addr):
        '''Attempts to connect to a remote socket.'''
        self.pr("Connecting to %s." % (str(addr)))
        self.send(Packet(str(self.PORT), addr, "PAYLOAD"), "CONN")
        self.clients.append(SubSocket(self, addr))

    def writeLog(self, packet, direction):
        '''Writes statistics logging data to a file.'''
        if self.DATADUMP:
            #Open the file
            try:
                f = open(
                    NET_PATH + "netdata_" + str(self.PORT) + "_" + self.NAME +
                    TEXT_EXT, "a")
            except:
                f = open(
                    NET_PATH + "netdata_" + str(self.PORT) + "_" + self.NAME +
                    TEXT_EXT, "w")

            #Write the data
            if not hasattr(packet, "packets"):
                f.write("{'id':%i, 'size':%i, 'time':%.3f, 'direction':%i}\n" %
                        (packet.headers["PACKETID"], len(
                            packet.getPayload()), time.time(), direction))
            else:
                for packet in packet.packets:
                    f.write(
                        "{'id':%i, 'size':%i, 'time':%.3f, 'direction':%i}\n" %
                        (packet.headers["PACKETID"], len(
                            packet.getPayload()), time.time(), direction))

            #Close the file
            f.close()

    def pr(self, msg, err=False, v=False):
        '''Outputs to the console and/or log file.'''
        if self.DEBUG and (not v or self.VERBOSE):
            try:
                f = open(
                    NET_PATH + "net_" + str(self.PORT) + "_" + self.NAME +
                    TEXT_EXT, "ab")
            except:
                f = open(
                    NET_PATH + "net_" + str(self.PORT) + "_" + self.NAME +
                    TEXT_EXT, "wb")

            msg = "Net%s - %s - %s\n" % (self.NAME, getFormattedTime(),
                                         str(msg))

            f.write(bytes(msg, "UTF-8"))
            f.close()

            if 1:
                print("Net%s - %s" %
                      (self.NAME, str(msg.replace("\n", "\\n"))))

            if err:
                print(exc_info())
Пример #8
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()
Пример #9
0
class Client(GameSide):
    def __init__(self):
        '''Initializes the client.'''

        self.mode = "client"

        self.oP = OutPipe("Client", 0)

        self.eI = EngineInterface(objectMode=True)
        self.vP = VideoPlayer()
        self.sE = ScriptExecuter()
        self.iR = InputReceiver()
        self.l = Localizer(self)
        self.pA = PhysicsApplicator(self)
        self.sH = ShaderHandler()
        self.nC = None

        self.sE.addContext("Client", self)

        self.cvars = {
            #Low level settings
            "cl_update": 1,
            "cl_synced": 0,
            "cl_addr": "0.0.0.0",
            "cl_oport": 7777,
            "cl_iport": 7778,
            "cl_netlog": 0,
            "cl_game": 0,
            "cl_startscript": "",
            "cl_master": 0,
            "cl_predict": 1,
            "cl_smooth": 0,
            "cl_name": "Player",
            "cl_password": "",
            "cl_camera": "",
            "cl_lockcontrols": 1,
            "cl_showmouse": 1,
            "cl_xsens": 50,
            "cl_ysens": 50,
            "cl_inverted": 0,
            "cl_netping": 0,

            #High level settings
            "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_mastervolume": 10,

            #Server shared settings
            "sv_level": "",
            "sv_gamemode": "",
            "sv_game": 0,
            "sv_background_red": 0,
            "sv_background_green": 0,
            "sv_background_blue": 0,
            "sv_background_alpha": 0,
        }

        self.netVars = {}

        self.chatMessages = []

        self.interfaces = []
        self.entities = []
        self.level = None

        self.gameEvents = []
        self.updateNetwork()

        #self.startLoop()
        self.forceUpdateCVars()

        self.keepAliveTicker = 0
        self.trackedProperties = []

        loadClient(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 "sv_" == key[:3]:
                self.configure(key, self.get(key), override=True)
        self.oP("Force updated cVars.")

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

        if key in self.cvars.keys() and (not "sv_" == key[:3] or fromServer):
            #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.oP("CVar %s configured to %s (%s)." %
                            (key, val, str(type(val)).replace(
                                "<class '", "").replace("'>", "")))
        elif "sv_" == key[:3] and not fromServer and key in self.cvars.keys(
        ) and self.cvars[key] != val:
            self.sendEvent(["SYSTEM", "CVARS", [key, val]])
            self.oP("Asking server to change CVar %s." % key)
        else:
            self.oP("CVar %s not present." % key)

        if changed:
            self.updateGame(key)

    def connectGame(self):
        '''Connects to a game.'''
        self.oP("Connecting to game.")
        self.nC.connect((self.get("cl_addr"), self.get("cl_oport")))
        self.configure("cl_game", 1)
        self.configure("cl_synced", 0)

    def disconnectGame(self):
        '''Disconnects from a game.'''
        self.oP("Disconnecting from a game.")
        self.updateNetwork()
        self.configure("cl_game", 0)
        self.configure("cl_synced", 0)
        self.configure("cl_update", 1)
        self.oP("Disconnected from game.")

    def updateGame(self, key):
        '''Reacts to changes to the cVars.'''
        if key == "cl_startscript":
            self.sE.addContext("Client", self)
            self.sE.execute(self.get("cl_startscript"))

        elif key in ["cl_iport"]:
            self.updateNetwork()

        elif key == "cl_addr":
            if self.get("cl_addr") == "0.0.0.0":
                self.configure("cl_addr", "127.0.0.1")

        elif key == "cl_name":
            self.sendEvent(["SYSTEM", "NAME", self.get("cl_name")])

        elif key == "sv_level" and not self.get("cl_master"):
            if self.get("sv_game"):
                self.setLevel(self.get("sv_level"))

        elif key == "sv_game" and not self.get("cl_master"):
            if self.get("sv_game"):
                self.setLevel(self.get("sv_level"))
            else:
                self.endLevel()

        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 == "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_camera" and self.get("cl_camera") != "":
            self.eI.setCamera(self.get("cl_camera"))

        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_lockcontrols":
            self.iR.locked = self.get("cl_lockcontrols")

        elif key == "cl_showmouse":
            self.eI.setMouseState(self.get("cl_showmouse"))

        elif key == "cl_xsens":
            self.iR.xsens = self.get("cl_xsens")

        elif key == "cl_ysens":
            self.iR.ysens = self.get("cl_ysens")

        elif key == "cl_inverted":
            self.iR.inverted = self.get("cl_inverted")

        elif key == "cl_predict":
            self.iR.predict = self.get("cl_predict")

            if not self.get("cl_predict"):
                for GUID in self.pA.blacklistedGUIDs:
                    self.removeFromRotationBlacklist(GUID)

        elif key == "cl_smooth":
            self.pA.smooth = self.get("cl_smooth")

        elif key == "cl_netlog":
            if self.get("cl_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_netping":
            self.nC.pingcount = self.get("cl_netping")

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

        self.nC = NetCore()
        if self.get("cl_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", "Client")
        self.nC.setProtocol("UDP")
        self.nC.configure("PORT", self.get("cl_iport"))
        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 startGameRemote(self):
        '''Used to connect to another person's game.'''
        self.oP("Starting game (remote)...")
        self.configure("cl_master", 0)
        self.configure("cl_update", 1)
        self.configure("cl_predict", 1)

        self.connectGame()

    def startGameFull(self):
        '''Used if you want the lobby when you start up a game.'''
        self.oP("Starting game (full)...")
        self.configure("cl_master", 1)
        self.configure("cl_update", 0)
        self.configure("cl_predict", 0)

        launcher = self.eI.getGlobal("launcher")

        if launcher:
            launcher.bootServer()
            self.oP("Booted server from client (Full).")
            self.configure("cl_addr", launcher.s.get("sv_addr"))
            self.connectGame()

    def startGameFast(self, level, gamemode, singleplayer=True):
        '''Used if you want to go straight to the game, usually used for singleplayer.'''
        self.oP("Starting game (fast)...")
        self.configure("cl_master", 1)
        self.configure("cl_update", 0)
        self.configure("cl_predict", 0)
        self.configure("cl_game", 1)

        self.updateNetwork()

        launcher = self.eI.getGlobal("launcher")

        if launcher:
            launcher.bootServer()
            self.oP("Booted server from client (Fast).")
            launcher.s.configure("sv_level", level)
            launcher.s.configure("sv_gamemode", gamemode)
            launcher.s.configure("sv_game", 1)
            if singleplayer:
                launcher.s.configure("sv_singleplayer", 1)
            else:
                launcher.s.configure("sv_singleplayer", 0)
            self.configure("cl_addr", launcher.s.get("sv_addr"))
            self.connectGame()

    def endGame(self):
        '''Ends the game instance and disconnects.'''
        self.oP("Ending game session...")
        self.disconnectGame()

        self.endLevel()

        launcher = self.eI.getGlobal("launcher")

        if launcher and self.get("cl_master") and launcher.s:
            launcher.s.quitGame()
            launcher.s = None

    def quitGame(self):
        '''Quits the game completely.'''
        self.oP("Shutting down...")
        self.endGame()
        self.purgeNetwork()
        self.eI.quitGame()

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

        launcher.sound.playMusic(music)
        self.oP("Set music to %s." % music)

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

        launcher.sound.stopMusic()
        self.oP("Stopped music.")

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

        if emitter:
            launcher.sound.playSound(sound, emitter.gameObject)
        else:
            launcher.sound.playSound(sound)

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

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

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

        self.oP("Stopped sound %s." % name)

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

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

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

        if emitter:
            launcher.sound.playDialog(sound, emitter.gameObject)
        else:
            launcher.sound.playDialog(sound)

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

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

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

        self.oP("Stopped dialog %s." % name)

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

        launcher.sound.stopDialogByGUID(GUID, name)

        self.oP("Stopped dialog %s." % name)

    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 playVideo(self, video):
        '''Plays a video.'''
        self.vP.playVideo(video)
        self.oP("Started video %s." % video)

    def stopVideo(self):
        '''Stops a video.'''
        self.vP.stopVideo()
        self.oP("Stopped video.")

    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)

        ent.gameObject.replaceMesh(meshName, True, True)
        self.oP("Replaced mesh of %s with %s." % (ent.GUID, meshName))

    def addInterface(self, name):
        '''Adds an interface.'''
        if not self.getInterfaceByName(name):
            cR = self.load("UI", name)

            name = cR.get("name")
            resource = cR.get("resourcePath")
            scriptName = cR.get("scriptPath")

            #self.loadLibrary("UI", resource)

            self.oP("Creating interface %s." % name)
            self.interfaces.append(Interface(name, resource, scriptName))
        else:
            self.oP("Interface %s already exists, not created." % name)

    def removeInterface(self, name):
        '''Removes an interface.'''
        interface = self.getInterfaceByName(name)

        if interface:
            self.oP("Removing interface %s." % name)
            self.interfaces.remove(interface)
            interface.kill()

    def removeAllInterfaces(self):
        '''Removes all interfaces.'''
        self.oP("Removing all interfaces.")
        names = []
        for interface in self.interfaces:
            names.append(interface.name)

        for name in names:
            self.removeInterface(name)

    def getInterfaceByName(self, name):
        '''Gets an interface by name.'''
        for interface in self.interfaces:
            if interface.name == name:
                return interface

    def addMarker(self, name, GUID):
        '''Adds a marker tracking the specified Entity.'''
        cR = self.load("UI", name)

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

        self.eI.getGlobal("addToWaypoints")(resource, name, GUID)

        self.oP("Added waypoint %s tracking %s." % (name, GUID))

    def removeMarker(self, GUID):
        '''Removes all markers tracking an Entity.'''
        for obj in self.eI.getWaypointsScene().objects:
            if "targetGUID" in obj and obj["targetGUID"] == GUID:
                obj.endObject()

        self.oP("Removed waypoints tracking %s." % GUID)

    def inputClick(self, keyCode, pos):
        '''Checks for the interface clicks.'''
        obj, scene = self.eI.getMouseOverObjectScene(pos)

        if obj and scene:
            for interface in self.interfaces:
                if interface.name == self.eI.getTerminalParent(obj).name:
                    interface.onClick(obj.name)
                    return True

            for i in self.entities:
                if obj == i.gameObject or obj in i.gameObject.childrenRecursive:
                    i.onClick(obj.name)
                    return True

        return False

    def getDisconnectReaction(self):
        '''Gets the reaction function for disconnecting from the server.'''
        self.sE.execute(NETSCRIPT_PATH + "disconnect")
        return self.disconnectReaction

    def addToRotationBlacklist(self, GUID):
        '''Adds a GUID to the rotation blacklist.'''
        if not GUID in self.pA.blacklistedGUIDs:
            self.pA.blacklistedGUIDs.append(GUID)

    def removeFromRotationBlacklist(self, GUID):
        '''Removes a GUID from the rotation blacklist.'''
        if GUID in self.pA.blacklistedGUIDs:
            self.pA.blacklistedGUIDs.remove(GUID)

    def sendInterfaceEvent(self, event, aux=None):
        '''Sends an interface event.'''
        self.sendEvent(["INPUT", "INTERFACE", [event, aux]])

    def sendChatMessage(self, msg):
        '''Sends a chat message.'''
        self.sendEvent(["SYSTEM", "CHAT", msg])

    def sendGameEvent(self, mode, data):
        '''Sends a game event.'''
        self.sendEvent(["GAME", mode, data])

    def sendEvent(self, event):
        '''Sends an event to the server.'''
        if event[0] == "INPUT" or event == "KEEPALIVE":
            mode = "FAF"
        elif event[0] in ["SYSTEM", "GAME", "NETWORK"]:
            mode = "RT"

        if self.nC.clients:
            server = self.nC.clients[0]
            server.send(event, mode)

    def recvEvent(self, event):
        '''Handles an event from the server.'''
        if event[0] == "PHYSICS" and self.get("cl_update"):
            self.pA.update(event)
        if event[0] == "SYSTEM":
            if event[1] == "CVARS":
                self.configure(event[2][0], event[2][1], fromServer=True)
            elif event[1] == "NETVARS":
                self.netVars[event[2][0]] = event[2][1]

            elif event[1] == "SOUND_PLAY" and self.get("cl_update"):
                entity = self.getEntityByGUID(event[2][0])
                self.playSound(event[2][1], entity)
            elif event[1] == "SOUND_STOP" and self.get("cl_update"):
                self.stopSoundByGUID(event[2][0], event[2][1])

            elif event[1] == "DIALOG_PLAY" and self.get("cl_update"):
                entity = self.getEntityByGUID(event[2][0])
                self.playDialog(event[2][1], entity)
            elif event[1] == "DIALOG_STOP" and self.get("cl_update"):
                self.stopDialogByGUID(event[2][0], event[2][1])

            elif event[1] == "MUSIC_PLAY" and self.get("cl_update"):
                self.setMusic(event[2][0])
            elif event[1] == "MUSIC_STOP" and self.get("cl_update"):
                self.stopMusic()

            elif event[1] == "SET_CAMERA":
                self.configure("cl_camera", event[2])

            elif event[1] == "INTERFACE_CREATE":
                self.addInterface(event[2])
            elif event[1] == "INTERFACE_REMOVE":
                self.removeInterface(event[2])

            elif event[1] == "CHAT":
                self.chatMessages.append(event[2])

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

        #cl = OptiClock()

        #Detector Index
        if not self.get("cl_master"):
            self.updateDetectorIndex()

        #cl.clockIn("DetectorIndex")

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

        #cl.clockIn("KeepAlive")

        #Do Things#######################

        #Read in controls

        self.iR.checkControls()

        #cl.clockIn("Input")

        #Update Video Player

        self.vP.loop()

        #cl.clockIn("VideoPlayer")

        if self.get("cl_update"):
            #Update localization
            self.l.loop()

            #cl.clockIn("Localization")
            #Apply shaders
            self.sH.loop()

        #cl.clockIn("Shaders")
        #Run object code

        for ent in self.entities:
            if hasattr(ent, "loop"):
                ent.checkAnimation()
                ent.loop(self, "client")
        #Run interface code

        #cl.clockIn("Entities")

        if self.level:
            if hasattr(self.level, "loop"):
                self.level.loop(self, "client")

        #cl.clockIn("Level")

        for interface in self.interfaces:
            if hasattr(interface, "loop"):
                try:
                    interface.loop()
                except:
                    pass

        #cl.clockIn("Interface")

        if self.nC:
            #Send Things#####################
            for key in self.iR.keyEvents:
                self.sendEvent(key)

            for event in self.gameEvents:
                self.sendEvent(event)

            self.gameEvents = []
            self.iR.keyEvents = []

            #cl.clockIn("SendLoop")

            #Recv Things#####################

            if self.nC.clients:
                server = self.nC.clients[0]

                packet = server.recv()

                if packet:
                    payload = packet.getPayload()

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

                    if data:
                        self.recvEvent(data)

            #cl.clockIn("RecvLoop")

            #Initial sync
            if self.nC.clients:
                server = self.nC.clients[0]

                if not self.get("cl_synced"):
                    server.disconnectFunc = self.getDisconnectReaction()
                    self.sendEvent(["SYSTEM", "NAME", self.get("cl_name")])
                    self.sendEvent(
                        ["SYSTEM", "PASSWORD",
                         self.get("cl_password")])
                    self.sendEvent(["SYSTEM", "PHYSICS", "FORCEUPDATE"])
                    self.configure("cl_synced", 1)

            #cl.clockIn("Sync")

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

            if kill:
                kill()

            #cl.clockIn("Kill")

            self.nC.loop()