from os.path import getsize MAXTRANS = 5000 DMF = 16 DNF = 100 DVELF = 1 MAP_PATH = "/home/robertj/public_html/sauerville/client_files/packages/map/" # enums ganked from sauerbraten/src/fpsgame/game.h for the most part ganked_enums = """ SV_INITS2C, SV_INITC2S, SV_POS, SV_TEXT, SV_SOUND, SV_CDIS, SV_SHOOT, SV_EXPLODE, SV_SUICIDE, SV_DIED, SV_DAMAGE, SV_HITPUSH, SV_SHOTFX, SV_TRYSPAWN, SV_SPAWNSTATE, SV_SPAWN, SV_FORCEDEATH, SV_ARENAWIN, SV_GUNSELECT, SV_TAUNT, SV_MAPCHANGE, SV_MAPVOTE, SV_ITEMSPAWN, SV_ITEMPICKUP, SV_DENIED, SV_PING, SV_PONG, SV_CLIENTPING, SV_TIMEUP, SV_MAPRELOAD, SV_ITEMACC, SV_SERVMSG, SV_ITEMLIST, SV_RESUME, SV_EDITMODE, SV_EDITENT, SV_EDITF, SV_EDITT, SV_EDITM, SV_FLIP, SV_COPY, SV_PASTE, SV_ROTATE, SV_REPLACE, SV_DELCUBE, SV_REMIP, SV_NEWMAP, SV_GETMAP, SV_SENDMAP, SV_MASTERMODE, SV_KICK, SV_CLEARBANS, SV_CURRENTMASTER, SV_SPECTATOR, SV_SETMASTER, SV_SETTEAM, SV_APPROVEMASTER, SV_BASES, SV_BASEINFO, SV_TEAMSCORE, SV_REPAMMO, SV_BASEREGEN, SV_FORCEINTERMISSION, SV_ANNOUNCE, SV_CLEARTARGETS, SV_CLEARHUNTERS, SV_ADDTARGET, SV_REMOVETARGET, SV_ADDHUNTER, SV_REMOVEHUNTER, SV_LISTDEMOS, SV_SENDDEMOLIST, SV_GETDEMO, SV_SENDDEMO, SV_DEMOPLAYBACK, SV_RECORDDEMO, SV_STOPDEMO, SV_CLEARDEMOS, SV_TAKEFLAG, SV_RETURNFLAG, SV_RESETFLAG, SV_DROPFLAG, SV_SCOREFLAG, SV_INITFLAGS, SV_SAYTEAM, SV_CLIENT, """ sauerConst = {} i = 0 for var in ganked_enums.split(","): sauerConst[var.strip()] = i i += 1 def prettyType(t): p = None for c in sauerConst: if sauerConst[c] == t: p = c if p is None: p = t return p import enet import stuff from worldSet import worlds import time import masterServer from puppetMaster import puppetMaster from threading import Thread # needed for sauerBuffer from array import array # needed for exception logging import sys, traceback puppet_handlers = {} class sauerBuffer: debug = False def __init__(self, ent=None): if ent is not None: self.data = posPacket(ent).data else: self.data = array('B') def putint(self, value): if (-127 < value) and (value < 128): self.data.append(value & 0xFF) elif (-0x8000 <= value) and (value < 0x8000): self.data.append(0x80) self.data.append(value & 0xFF) self.data.append((value >> 8) & 0xFF) else: self.data.append(0x81) self.data.append(value & 0xFF) self.data.append((value >> 8) & 0xFF) self.data.append((value >> 16) & 0xFF) self.data.append((value >> 24) & 0xFF) def getint(self): a = self.data.pop(0) if (0x80 == a): a = self.data.pop(0) a |= self.data.pop(0) << 8 if (0x8000 & a): # fix negative values a = - (0xFFFF ^ (a-1)) elif (0x81 == a): a = self.data.pop(0) a |= self.data.pop(0) << 8 a |= self.data.pop(0) << 16 a |= self.data.pop(0) << 24 if (0x80000000 & a): # fix negative values a = - (0xFFFFFFFF ^ (a-1)) elif (0x80 & a): # fix negative values a = - (0xFF ^ (a-1)) return a def putuint(self, value): """much smaller encoding for unsigned integers up to 28 bits, but can handle sign smaller encoding for unsigned integers up to 28 bits, but can handle signed""" if ((1 << 28) <= value) or (value < -(1 << 27)): raise ValueError("more than 28 bits used") if (value < 0) or ((1<<21) <= value): self.data.append(0x80 | (value & 0x7F)) self.data.append(0x80 | ((value >> 7) & 0x7F)) self.data.append(0x80 | ((value >> 14) & 0x7F)) self.data.append(0xFF & (value >> 21)) elif (value < (1 << 7)): self.data.append(0xFF & value) elif (value < (1 << 14)): self.data.append(0x80 | (value & 0x7F)) self.data.append(0xFF & (value >> 7)) else: self.data.append(0x80 | (value & 0x7F)) self.data.append(0x80 | ((value >> 7) & 0x7F)) self.data.append(0xFF & (value >> 14)) def getuint(self): a = self.data.pop(0) if (0x80 & a): a += (self.data.pop(0) << 7) - 0x80 if (a & (1<<14)): a += (self.data.pop(0) << 14) - (1<<14) if (a & (1<<21)): a += (self.data.pop(0) << 21) - (1<<21) if(a & (1<<28)): # fix negative values a |= 0xF0000000 a = - (0xFFFFFFFF ^ (a-1)) return a def hasData(self): if len(self.data) > 0: return True else: return False def putstr(self, msg): for char in msg: self.putint(ord(char)) self.putint(0) def getstr(self): buffer = "" x = self.getint() while x != 0: buffer += chr(x) x = self.getint() return buffer def subbuf(self, size): s = sauerBuffer() for x in range(size): s.data.append(self.data.pop(0)) return s def len(self): return len(self.data) def test_int(self, exhaustive = 0): """test putint and getint""" print "test_int: border cases ... " for value in [0, 1, -1, 127, -126, 128, -127, 0x7FFF, -0x7FFF, -0x8000, 0x8000, -0x8001, 0x7ABCDEF9, -0x7ABCDEF9, 0x7FFFFFFF, -0x7FFFFFFE, 1 << 27, (1 << 27) - 1, -(1 << 27), 1-(1 << 27), 1 << 28, (1 << 28) - 1, -(1 << 28), 1-(1 << 28)]: p = sauerBuffer() try: p.putint(value) except: print "could not putint ", value continue if (p.getint() != value) or (0 != len(p.data)): print "FAILED ", value if(exhaustive): print "test_int: exhaustive ... (this is going to take quite a bit)" b = 2 ** 31 lower_bound = -b upper_bound = b i = lower_bound while i < upper_bound: p = sauerBuffer() try: p.putint(i) except: print "could not putint ", i continue if(p.getint() != i): print "FAILED ", i i+= 1 print "DONE" def test_uint(self, exhaustive = 0): """test putuint and getuint""" print "test_uint: border cases ... " for value in [0, 1, -1, 127, -126, 128, -127, 0x7FFF, -0x7FFF, -0x8000, 0x8000, -0x8001, 1 << 27, (1 << 27) - 1, -(1 << 27), 1-(1 << 27), (1 << 28) - 1]: p = sauerBuffer() try: p.putuint(value) except: print "could not putuint ", value continue if (p.getuint() != value) or (0 != len(p.data)): print "FAILED ", value, "(", result, ")" if(exhaustive): print "test_uint: exhaustive ... (this is going to take quite a bit)" b = (1 << 28) - 1 lower_bound = -0xFFFFF upper_bound = b i = lower_bound while i < upper_bound: p = sauerBuffer() try: p.putuint(i) except: print "could not putuint ", i continue if (p.getuint() != i) or (0 != len(p.data)): print "FAILED ", i i+= 1 print "DONE" class sauerAdvertiserThread(Thread): __stop = False def stop(self): self.__stop = True def run(self): # register print "advertising server presence to sauerbraten master server" while not self.__stop: # TODO cant sleep this long or takes forever to shutdown when we wait for this thread to quit #time.sleep(60 * 15) pass class sauerServerThread(Thread): __stop = False def stop(self): self.__stop = True def run(self): serverAddress = enet.Address(enet.HOST_ANY, 28785) # SAUERBRATEN_SERVER_PORT server = enet.Host(serverAddress, 32, 0, 0) print "now listening for sauerbraten connections on port ", serverAddress.port while not self.__stop: event = server.service(.02) if event.type == 1: if puppet_handlers.has_key(event.peer.incomingPeerID): puppet_handlers[event.peer.incomingPeerID].connectionLost("Duplicate Connection") if hasattr(puppet_handlers[event.peer.incomingPeerID], "name"): name = puppet_handlers[event.peer.incomingPeerID].name else: name = "unnamed session" print "Disconnected ", name, " due to duplicate connection." puppet_handlers[event.peer.incomingPeerID] = sauerPuppetMaster(event.peer) elif event.type == 2: try: puppet_handlers[event.peer.incomingPeerID].connectionLost("DISCONNECT from enet") except: pass elif event.type == 3: #try: puppet_handlers[event.peer.incomingPeerID].handleInput(event.packet) #except: # pass for player in puppet_handlers: try: puppet_handlers[player].sendQueuedUpdates() except: puppet_handlers[player].connectionLost("DISCONNECT couldn't sendQuedUpdates") time.sleep(.03) def newGuiPacket(name, contents): b = sauerBuffer() b.putint(sauerConst['SV_NEWGUI']) b.putstr(name) b.putstr(contents) return b def showGuiPacket(name): b = sauerBuffer() b.putint(sauerConst['SV_SHOWGUI']) b.putstr(name) return b def hideGuiPacket(name): b = sauerBuffer() b.putint(sauerConst['SV_HIDEGUI']) b.putstr(name) return b def statsPacket(ent): b = sauerBuffer() b.putint(sauerConst['SV_STATS']) b.putint(ent.lifesequence) b.putint(ent.hp) return b def mapChangePacket(map, mode): b = sauerBuffer() b.putint(sauerConst['SV_MAPCHANGE']) b.putstr("map/" + map) # FIXME should be mode but cant receive map in modes other than 1, can all players use mode 1 now including admins who used to use mode 4? b.putint(1) return b def messagePacket(msg): b = sauerBuffer() b.putint(sauerConst['SV_SERVMSG']) b.putstr(msg) return b def itemListPacket(): b = sauerBuffer() b.putint(sauerConst['SV_ITEMLIST']) b.putint(-1) return b def posPacket(viewer, ent): b = sauerBuffer() b.putint(sauerConst['SV_POS']) b.putint(viewer.getSauerNum(ent)) b.putuint(ent.o[0] * DMF) b.putuint(ent.o[1] * DMF) b.putuint(ent.o[2] * DMF) b.putuint(ent.yaw) b.putint(ent.pitch) b.putint(ent.roll) b.putint(ent.v[0] * DVELF) b.putint(ent.v[1] * DVELF) b.putint(ent.v[2] * DVELF) if ent.g[1]: b2 = 0x20 else: b2 = 0 if ent.g[2]: b3 = 0x10 else: b3 = 0 ps_pack = ent.physstate | (ent.g[0] & b2 | b3) b.putint(ps_pack) if ent.g[0] & ent.g[1]: b.putint(ent.g[0] * DVELF) b.putint(ent.g[1] * DVELF) if ent.g[2]: b.putint(ent.g[2] * DVELF) b.putint(ent.move_pack) return b def infoPacket(ent): # even though we don't need immortal objects to have hp in sauerville, sauerbraten does b = sauerBuffer() b.putint(sauerConst['SV_INITC2S']) b.putstr(ent.name) b.putstr("pauerEnt") return b def damagePacket(experiencer, ent, damage): b = sauerBuffer(ent) b.putint(sauerConst['SV_DAMAGE']) b.putint(experiencer.getSauerNum(ent)) putint(damage) putint(ent.lifesequence) # frags putint(0) putint(0) putint(0) return b def editEntPacket(experiencer, ent, itemnum, o, type, a, b, c, d): b = sauerBuffer(experiencer) b.data += ent.posPacket().data b.putint(sauerConst['SV_EDITENT']) b.putint(itemnum) b.putint(o[0] * DMF) b.putint(p[1] * DMF) b.putint(o[2] * DMF) b.putint(type) # these 4 have different meanings depending on enttype b.putint(a) b.putint(b) b.putint(c) b.putint(d) return b def removeEntPacket(experiencer, ent): b = sauerBuffer() b.putint(sauerConst['SV_CDIS']) b.putint(experiencer.getSauerNum(ent)) class sauerPuppetMaster(puppetMaster): buffer = sauerBuffer() locked = False debug = True state = 0 # used for login process only sent_welcome = False def __init__(self, peer): self.resetTrackedEnts() self.chanPos = [] self.chanServ = [] self.chanFile = [] self.chanClient = {} self.puppet = None self.player = False self.peer = peer self.handleInput = self.handleInputLogin puppet_handlers[peer.incomingPeerID] = self self.queue(welcomePacket(), desc="welcome") self.hearMsg(self, "Type your character's name to get started.") self.hearMapChange("login_room", 4) # this should eventually go away entirely #self.queue(itemListPacket(), desc="itemListPacket from setMap") def select(self, ent): super(stuff.player, self).select(ent) self.cmd("examine") def connectionLost(self, reason): if self.player: if hasattr(self.player, "onDisconnect"): self.player.onDisconnect() self.player = False def getSauerNum(self, ent): if not self.ents.has_key(ent): self.ents[ent] = self.next_entnum self.next_entnum += 1 return self.ents[ent] def resetTrackedEnts(self): self.ents = {} self.next_entnum = 0 # functions that send data to sauer def queue(self, packet, ent=None, isPosUpdate=False, isFile=False, desc=None): if self.debug is True: if desc is not None: print "sending ", desc g = sauerBuffer() g.data = packet.data #while g.hasData(): print g.peekint() else: print "sending unknown packet" while self.locked: pass if ent is None: if isPosUpdate: self.chanPos.append(packet) elif isFile: self.chanFile.append(packet) else: self.chanServ.append(packet) else: try: self.chanClient[ent].append(packet) except: self.chanClient[ent] = [packet] def sendQueuedUpdates(self): while self.locked: pass self.locked = True for (channelData, channelNumber) in [(self.chanPos, 0), (self.chanServ, 1), (self.chanFile, 2)]: if channelData != []: data = array('B') for packet in channelData: data += packet.data p = enet.Packet(data.tostring(), flags=enet.PACKET_FLAG_RELIABLE) self.peer.send(channelNumber, p) #print "putting data in from ", channel[1], " for ", id(self) #print "SENDING REPR ", repr(data.tostring()) #p = enet.Packet("ABCDEFGHIJKLMNOP", flags=enet.PACKET_FLAG_RELIABLE) if self.chanClient != {}: all_client_data = array('B') for ent in self.chanClient: size = 0 data = array('B') envelope = sauerBuffer() print "adding data for ", ent.name, " number of packets ", len(self.chanClient[ent]) for packet in self.chanClient[ent]: size += packet.len() data += packet.data envelope.putint(sauerConst['SV_CLIENT']) envelope.putint(self.getSauerNum(ent)) envelope.putuint(size) all_client_data += envelope.data all_client_data += data packet = enet.Packet(all_client_data.tostring(), flags=enet.PACKET_FLAG_RELIABLE) print "ALL DATA: ", all_client_data, all_client_data.tostring() self.peer.send(1, packet) self.chanPos = [] self.chanServ = [] self.chanFile = [] self.chanClient = {} self.locked = False # functions that respond to events def hearMsg(self, ent, text): self.queue(messagePacket(text), desc="msg") def hearEnterWorld(self, world): self.hearMapChange(world.map, 4) def hearPerspectiveChange(self, source, target): self.hearUnexpose(target) self.hearExpose(source) def hearEquipment(self): self.hearMsg(self, "EQUIPMENT") menu = self.menu("Equipment") for slot in self.equipment_slots: if self.equipment_slots[slot] is not None: name = self.equipment_slots[slot].name else: name = "" submenu = self.menu("Equiped Item") submenu.button("drop", "say drop") submenu.button("sell", "say sell") menu.button(slot + ": " + name, "newgui item [ " + submenu.txt + "]; showgui item;") menu.fire() def hearInventory(self): menu = self.menu("Inventory") for item in self.inventory: submenu = self.menu("item") submenu.button("drop", "say drop " + item.name) submenu.button("sell", "say sell " + item.name) menu.button(item.name, "newgui item [ " + submenu.txt + "]; showgui item;") if len(self.inventory) == 0: menu.txt = "" menu.button("status", "select " + self.name + "; say examine;") menu.fire() def hearExamine(self, ent): menu = self.menu("Examine") sale_set = set() if hasattr(ent, "selling"): sale_set = ent.selling if hasattr(ent, "making"): sale_set = sale_set.union(ent.making) if hasattr(ent, "selling") and sale_set != []: menu.tab("selling") for x in sale_set: menu.button(x.name, "say buy " + x.name) menu.tab("info") menu.text(ent.name) if hasattr(ent, "maxhp"): menu.text("hp: " + str(ent.hp) + " / " + str(ent.maxhp)) if hasattr(ent, "xp"): menu.text("xp: " + str(ent.xp)) if hasattr(ent, "level"): menu.text("level: " + str(ent.level)) if hasattr(ent, "gold"): menu.text("gold: " + str(ent.gold)) if hasattr(ent, "lootable"): if ent.lootable == "auto": menu.button("say take " + ent.name, "get") else: if len(ent.contents) == 0: menu.text(ent.name + " is empty.") else: for x in ent.contents: menu.button("say take " + x.name, "take " + x.name) if self.controller.admin: menu.tab("admin") if(hasattr(self.selection, "face")): menu.button("face", "say face") if(hasattr(self.selection, "setPosition")): menu.button("summon", "say summon") if(hasattr(self.selection, "name")): menu.button("rename", "saycommand [/say foo ]") if(hasattr(self.selection, "save")): menu.button("save", "say save") menu.fire() def hearStats(self): if self.debug is True: return self.queue(statsPacket(self), desc="hearStats") def hearExpose(self, ent): if ent is self.puppet: return self.queue(infoPacket(ent), ent=ent, desc="hearExpose") def hearUnexpose(self, ent): if self.debug is True: return self.queue(removeEntPacket(self, ent), desc="unexpose") def hearMapChange(self, map, mode): print "CHANGING TO MAP ", map # send out the file to the client filename = MAP_PATH + map + ".ogz" self.hearMsg(self, "Sending map..." + str(filename) + ", " + str(getsize(filename)) + "kb") #data = sendfilePacket(filename).data #p = enet.Packet(data.tostring(), flags=enet.PACKET_FLAG_RELIABLE) #self.peer.send(2, p) self.queue(sendfilePacket(filename), isFile = True, desc="map file") # BUG!!! if I dont force a queue update things go crazy! Why! self.sendQueuedUpdates() # then tell them to change to it #if self.debug is True: return try: if self.controller.admin: mode = 1 else: mode = 4 except: mode = 4 self.queue(mapChangePacket(map, mode), desc="hearMapChange") def hearLocation(self, ent): if ent is self.puppet: return #self.hearMsg(self, "I heard a " + ent.name + "move to " + str(ent.o[0]) + ", " + str(ent.o[1])) self.queue(posPacket(self.puppet_master, ent), isPosUpdate=True, desc="hearLocation") def hearTeleport(self, nexto): #kinda hacky to have the editEntPacket not be a self method #but in the long term we shouldn't need it because we should #be able to remove the pos from the start of editEntPacket if self.debug is True: return super(stuff.player, self).onDisconnect() placeTeleDestPacket = editEntPacket(self, 100, nexto, 16, 27, 1, 0, 0) # place teleporter on top of player placeTeleDoorPacket = editEntPacket(self, 101, nexto, 15, 1, 0, 0, 0) self.queue(placeTeleDestPacket, ent=self, desc="teleport place destination") self.queue(placeTeleDoorPacket, ent=self, desc="teleport place entrance") super(stuff.player, self).teleport(nexto) # we have never seen our entnum connect so we believe its another player # make us believe we have disconnected removeGhostPacket = removeEntPacket(self, self) self.queue(removeGhostPacket(), desc="teleport remove door") # login command handler def login_cmd(self, text): if self.state == 0: self.name = text if not masterServer.playerRegisteredWithName(text): self.hearMsg(self, "That name is not yet registered. Would you like to create it (y/n)?\r\n") self.state = 2 else: self.hearMsg(self, "password: ") self.state = 1 elif self.state == 1: self.password = text dbID = masterServer.playerRegisteredWithName(self.name, self.password) if dbID == False: self.hearMsg(self, "You have provided an incorrect password.\r\n") self.hearMsg(self, "name: ") self.state = 0 else: self.loginPlayerID(dbID) world = worlds.getWorldByMapName("sauerville") elif self.state == 2: if text == "y": self.hearMsg(self, "password: ") self.state = 3 elif text == "n": self.state = 0 self.hearMsg(self, "name: ") else: self.hearMsg(self, "You must answer with either y or n.\r\n") elif self.state == 3: self.password = text self.hearMsg(self, "password (again): ") self.state = 4 elif self.state == 4: if text == self.password: masterServer.registerPlayer(self.name, self.password) dbID = masterSer.playerRegisteredWithName(self.name, self.password) self.loginPlayerID(dbID) else: self.hearMsg(self, "Passwords did not match. Character creation aborted.\r\n") self.state = 0 self.hearMsg(self, "name: ") def handleInputLogin(self, packet): print "GOT LOGIN INPUT ", id(self) # sandboxes clients so we dont have to check if they are connected over and over in handleInputGame # butchered version of handleInputGame, parse only enough to receive txt commands and toss out all other data # since we get POS, INITC2S, and PING before TEXT, we do parse those to get to the TEXT pw = self.buffer pw.data += array('B', packet.data) while pw.hasData(): #print repr(pw.data) type = pw.getint() #pretty_type = "got " + str(type) #for packet_type in sauerConst: # if sauerConst[packet_type] == type: # pretty_type = packet_type #print "login handling type ", prettyType(type) if type == sauerConst['SV_TEXT']: text = pw.getstr().strip() try: self.login_cmd(text) except: t, v, tb = sys.exc_info() print "EXCEPTION:\n".join(traceback.format_exception(t,v,tb)) #if True: pass elif type == sauerConst['SV_POS']: pw.getint() pw.getuint() pw.getuint() pw.getuint() pw.getuint() pw.getint() pw.getint() pw.getint() pw.getint() pw.getint() tmp = pw.getint() if tmp & 0x20: # physstate pack pw.getint() pw.getint() elif tmp & 0x10: # physstate pack pw.getint() pw.getint() # state pack elif type == sauerConst['SV_INITC2S']: print repr(pw.data) print pw.getstr() print pw.getstr() elif type == sauerConst['SV_INITS2C']: pw.getint() # client num pw.getint() # protocol version pw.getint() # hasmap elif type == sauerConst['SV_FORCEDEATH']: pw.getint() # foo, clientnum i think print "forcing death not implemented " elif type == sauerConst['SV_PING']: pw.getint() elif type == sauerConst['SV_CLIENTPING']: pw.getint() elif type == sauerConst['SV_ITEMLIST']: #item list while pw.getint() != -1: continue else: print "Don't know how to handle this client's event, got event type ", prettyType(type) self.peer.disconnect() self.buffer.data = "" def handleInputGame(self, packet): pw = self.buffer pw.data += array('B', packet.data) if pw.debug is True: print "GOT ", repr(packet.data) while pw.hasData(): type = pw.getint() if pw.debug is True: print "got ", type #print "HANDELING ", type, repr(pw.data) #print "handling type ", prettyType(type) if type == sauerConst['SV_POS']: pw.getint() # client num #print "xyz yaw" new_o = (pw.getuint() / DMF, pw.getuint() / DMF, pw.getuint() / DMF) # xyz self.puppet.yaw = pw.getuint() # yaw self.puppet.pitch = pw.getint() # pitch self.puppet.roll = pw.getint() # roll self.puppet.v = (pw.getint()/DVELF, pw.getint()/DVELF, pw.getint()/DVELF) # velocity xyz #print "State Info" tmp = pw.getint() if tmp & 0x20: # physstate pack if pw.debug is True: print " ------- found x,y gravity vectors" self.puppet.g = (pw.getint()/DVELF, pw.getint()/DVELF, self.puppet.g[2]) # gravity x y plus current elif tmp & 0x10: # physstate pack if pw.debug is True: print " ------- found z gravity vector" self.puppet.g = (self.puppet.g[0], self.puppet.g[1], pw.getint()/DVELF) #gravity z pw.getint() # state pack self.puppet.o = new_o # must do this last to avoid resending locs with old xyz elif type == sauerConst['SV_SOUND']: pw.getint() elif type == sauerConst['SV_INITS2C']: pw.getint() # client num pw.getint() # protocol version pw.getint() # hasmap elif type == sauerConst['SV_INITC2S']: # self init info u_name = pw.getstr() print "Got connect from user name ", u_name # ignore name changes # if self.puppet.dbID == -1: self.puppet.name = u_name team = pw.getstr() print "Got connect from team name ", team if team == "VILLE": self.enhanced = True print "got name ", u_name, " team ", team elif type == sauerConst['SV_TEXT']: # text from self, command or chat text = pw.getstr().strip() try: self.puppet.cmd(text, controller = self) except: t, v, tb = sys.exc_info() print "EXCEPTION:\n".join(traceback.format_exception(t,v,tb)) elif type == sauerConst['SV_SOUND']: pw.getint() elif type == sauerConst['SV_SHOOT']: pw.getint() # game offset pw.getint() # gun for d in 'x','y','z': pw.getint()/DMF # source for d in 'x','y','z': pw.getint()/DMF # destination hits = pw.getint() for i in range(hits): pw.getint() # target num pw.getint() # target lifesequence pw.getint() # target rays for d in 'x','y','z': pw.getint()/DNF # target dmg vector elif type == sauerConst['SV_DAMAGE']: victim_num = pw.getint() dmg = pw.getint() # damage pw.getint() # lifesequence of victim pw.getint() #x pw.getint() #y pw.getint() #z victim = None if victim_num == -1: victim = self.puppet elif stuff.ents.has_key(victim_num): victim = stuff.ents[victim_num] if victim != None: if dmg == 50: self.puppet.attack(victim) else: self.select(victim) elif type == sauerConst['SV_MAPCHANGE']: # map name pw.getstr() pw.getint() elif type == sauerConst['SV_PING']: # ping pw.getint() elif type == sauerConst['SV_CLIENTPING']: # client ping pw.getint() elif type == sauerConst['SV_SERVMSG']: # server message, needs to be here to avoid crashing on forged packet becasue its a fixed length message pw.getstr() elif type == sauerConst['SV_ITEMLIST']: #item list while pw.getint() != -1: continue elif type == sauerConst['SV_EDITENT']: # entity type print "i ", pw.getint() print "x ", pw.getint() print "y ", pw.getint() print "z ", pw.getint() print "type ", pw.getint() print "p1 ", pw.getint() print "p2 ", pw.getint() print "p3 ", pw.getint() print "p4 ", pw.getint() elif type == sauerConst['SV_COPY'] or type == sauerConst['SV_PASTE']: # copy from edit mode x1 = pw.getint() # x1 y1 = pw.getint() # y1 z1 = pw.getint() # z1 x2 = pw.getint() # x2 y2 = pw.getint() # y2 z2 = pw.getint() # z2 gridsize = pw.getint() #grid pw.getint() #grid orientation pw.getint() #cx pw.getint() #cxs pw.getint() #cy pw.getint() #cys pw.getint() #corner if(type == 31): pw.getint() # tex pw.getint() # newtex pw.getint() # orient # shove selection coordinates into a structure so we can organize them properly tselect = [x1,y1,z1,x1 + (x2 * gridsize),y1 + (y2 * gridsize),z1 + (z2 * gridsize)] psA = [0,0,0] psB = [0,0,0] for i in (0,1,2): if tselect[i] < tselect[i+3]: psA[i] = tselect[i] psB[i] = tselect[i+3] else: psB[i] = tselect[i+3] psA[i] = tselect[i] self.selectionA = (psA[0], psA[1], psA[2]) self.selectionB = (psB[0], psB[1], psB[2]) self.hearMsg(self, "Area selected.") elif type == sauerConst['SV_BASES']: # ctf bases while pw.getint() != -1: getint(p) getint(p) elif type == sauerConst['SV_BASEINFO']: # ctf base info pw.getint() pw.getstr() pw.getstr() pw.getint() elif type == sauerConst['SV_TEAMSCORE']: # team score pw.getstr() pw.getint() else: print "Unknown packet type %d." % type print "We should never get a packet type %d, %s!" % (type, prettyType(type)) print "Disconnecting ", self.puppet.name self.puppet.onDisconnect() # empty the buffer so we don't proccess any other packets self.buffer.data = "" #raise SystemExit def loginPlayerID(self, dbID): world = worlds.getWorldByMapName("sauerville") self.player = stuff.player() self.puppet = self.player self.admin = True self.puppet_master = self self.puppet.puppet_masters.add(self) self.puppet.world = world self.handleInput = self.handleInputGame def welcomePacket(): b = sauerBuffer() b.putint(sauerConst['SV_INITS2C']) b.putint(0) # we are always player 0 b.putint(256) # Protocol Version # send game mode 4 to start so players cant do dmg to self with grenade launcher b.putint(4) return b def introductionPacket(ent, unintroduced_packet): b = sauerBuffer() length = len(unintroduced_packet.data) b.data.append(ent.entnum) b.data.append(length & 0xFF) b.data.append(length >> 8) return b def sendfilePacket(filename): b = sauerBuffer() b.putint(sauerConst['SV_SENDMAP']) file = open(filename, 'r') map_data = array('B', file.read()) file.close() # should probably set packet closer to size of len(map_data) but seems to work for x in map_data: b.data.append(x) return b class sauerMenu: def __init__(self, player, name): self.txt = "" self.name = name self.player = player def title(self, text): self.txt += "guititle [" + self.sauerfy(text) + "];" def tab(self, text): self.txt += "guitab [" + self.sauerfy(text) + "];" def text(self, text): self.txt += "guitext [" + self.sauerfy(text) + "];" def button(self, text, cmd): self.txt += "guibutton [" + self.sauerfy(text) + "] [" + self.sauerfy(cmd) + "];" def fire(self): pass self.player.queue(newGuiPacket("A", "B"), desc="new gui from fire") self.player.queue(showGuiPacket("B"), desc="show gui from fire") def sauerfy(self, text): return text