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()
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()
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)
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"
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()
from engineinterface import EngineInterface eI = EngineInterface() client = eI.getGlobal("client") client.configure("cl_showmouse", 1) client.playVideo("intro") client.addInterface("TitleScreen")
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())
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()
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()