def __recv_msg(self): header = MessageBuf(self.__recv_bytes(2)) data_len = header.get_uint16(be=True) msg = MessageBuf(self.__recv_bytes(data_len)) if self.verbose: self.info('< ' + str(msg)) return msg
def on_msg_rel(self, msg): seq = msg.get_uint16() while not msg.eom(): rel_type = msg.get_uint8() if (rel_type & 0x80) != 0: rel_type &= 0x7F rel_len = msg.get_uint16() rmsg = MessageBuf(msg.get_bytes(rel_len)) else: rmsg = MessageBuf(msg.get_remaining()) if seq == self.rseq: if rel_type == RelMessageType.RMSG_NEWWDG: self.on_rmsg_newwdg(rmsg) elif rel_type == RelMessageType.RMSG_WDGMSG: self.on_rmsg_wdgmsg(rmsg) elif rel_type == RelMessageType.RMSG_DSTWDG: self.on_rmsg_dstwdg(rmsg) elif rel_type == RelMessageType.RMSG_GLOBLOB: self.on_rmsg_globlob(rmsg) elif rel_type == RelMessageType.RMSG_RESID: self.on_rmsg_resid(rmsg) elif rel_type == RelMessageType.RMSG_PARTY: self.on_rmsg_party(rmsg) elif rel_type == RelMessageType.RMSG_CATTR: self.on_rmsg_cattr(rmsg) else: pass self.gc.ack(seq) self.rseq = (self.rseq + 1) % 65536 seq += 1
def handle_wiact_message(self, data): if self.get_gs() != GameState.PLAY: # TODO: Send response back to the client return item_id = data['iid'] msg = MessageBuf() msg.add_uint8(RelMessageType.RMSG_WDGMSG) msg.add_uint16(item_id) msg.add_string('take') msg.add_list([Coords.Z, Coords.Z]) self.queue_rmsg(msg) wound_id = int(data['wid']) msg = MessageBuf() msg.add_uint8(RelMessageType.RMSG_WDGMSG) msg.add_uint16(self.chr_wdg_id) msg.add_string('wiact') msg.add_list([ wound_id, 0 # modflags ]) self.queue_rmsg(msg)
def queue_rmsg(self, rmsg): msg = MessageBuf() msg.add_uint8(MessageType.MSG_REL) msg.add_uint16(self.wseq) msg.add_bytes(rmsg.buf) msg.seq = self.wseq with self.rmsgs_lock: self.rmsgs.append(msg) self.wseq = (self.wseq + 1) % 65536
def start_session(self, username, cookie): msg = MessageBuf() msg.add_uint8(MessageType.MSG_SESS) msg.add_uint16(2) # Magic number msg.add_string('Hafen') msg.add_uint16(9) # Protocol version msg.add_string(username) msg.add_uint16(len(cookie)) msg.add_bytes(cookie) self.send_msg(msg)
def handle_closepmchat_message(self, data): if self.get_gs() != GameState.PLAY: # TODO: Send response back to the client return chat_id = data['id'] msg = MessageBuf() msg.add_uint8(RelMessageType.RMSG_WDGMSG) msg.add_uint16(chat_id) msg.add_string('close') self.queue_rmsg(msg)
def get_cookie(self): msg = MessageBuf() msg.add_string('cookie') self.__send_msg(msg) rpl = self.__recv_msg() status = rpl.get_string() if status == 'ok': cookie = rpl.get_bytes(32) return cookie else: raise AuthException('Unexpected reply: "' + status + '"')
def handle_play_message(self, data): if self.charlist_wdg_id == -1: return char_name = data['char_name'] msg = MessageBuf() msg.add_uint8(RelMessageType.RMSG_WDGMSG) msg.add_uint16(self.charlist_wdg_id) msg.add_string('play') msg.add_list([char_name]) self.queue_rmsg(msg)
def handle_pmchat_message(self, data): if self.get_gs() != GameState.PLAY or self.buddy_wdg_id == -1: # TODO: Send response back to the client return kin_id = data['id'] msg = MessageBuf() msg.add_uint8(RelMessageType.RMSG_WDGMSG) msg.add_uint16(self.buddy_wdg_id) msg.add_string('chat') msg.add_list([kin_id]) self.queue_rmsg(msg)
def handle_transfer_message(self, data): if self.get_gs() != GameState.PLAY: # TODO: Send response back to the client return item_id = data['id'] msg = MessageBuf() msg.add_uint8(RelMessageType.RMSG_WDGMSG) msg.add_uint16(item_id) msg.add_string('transfer') msg.add_list([Coords.Z]) # Ignored self.queue_rmsg(msg)
def handle_drop_message(self, data): if self.get_gs() != GameState.PLAY: # TODO: Send response back to the client return coords = data['coords'] msg = MessageBuf() msg.add_uint8(RelMessageType.RMSG_WDGMSG) msg.add_uint16(self.inv_wdg_id) msg.add_string('drop') msg.add_list([Coord(coords['x'], coords['y'])]) self.queue_rmsg(msg)
def login(self, username, password): msg = MessageBuf() msg.add_string('pw') msg.add_string(username) msg.add_bytes(password.decode('hex')) self.__send_msg(msg) rpl = self.__recv_msg() status = rpl.get_string() if status == 'ok': acc = rpl.get_string( ) # This is normally the same thing as `username` return elif status == 'no': err = rpl.get_string() raise AuthException(err) else: raise AuthException('Unexpected reply: "' + status + '"')
def handle_cl_message(self, data): if self.get_gs() != GameState.PLAY or self.flowermenu_wdg_id == -1: # TODO: Send response back to the client return option = data['option'] msg = MessageBuf() msg.add_uint8(RelMessageType.RMSG_WDGMSG) msg.add_uint16(self.flowermenu_wdg_id) msg.add_string('cl') if option == -1: msg.add_list([option]) else: msg.add_list([ option, 0 # modflags ]) self.queue_rmsg(msg) self.flowermenu_wdg_id = -1 # TODO: Handle it on DSTWDG message or smth like that
def __init__(self, resname, resver, rawinfo): self.resname = resname self.resver = resver buf = MessageBuf(rawinfo) canon_sig = 'Haven Resource 1' sig = buf.get_bytes(len(canon_sig)) if sig != canon_sig: raise ResException('Wrong signature') ver = buf.get_uint16() if ver != self.resver: raise ResException('Wrong version') self.layers = [] while not buf.eom(): layer_type = buf.get_string() layer_len = buf.get_int32() layer_data = buf.get_bytes(layer_len) self.layers.append(ResLayer(layer_type, layer_data))
def handle_transfer_message(self, data): if self.get_gs() != GameState.PLAY: # TODO: Send response back to the client return item_id = data['id'] coords = None with self.items_lock: for item in self.items: if item.wdg_id == item_id: coords = copy.copy(item.coords) if coords is None: # TODO: Send response back to the client return msg = MessageBuf() msg.add_uint8(RelMessageType.RMSG_WDGMSG) msg.add_uint16(item_id) msg.add_string('transfer') msg.add_list([coords]) self.queue_rmsg(msg)
def rworker(self): while True: try: msg = self.gc.recv_msg( ) # TODO: Make it non-blocking to check the game state msg_type = msg.get_uint8() data = MessageBuf(msg.get_remaining()) if msg_type == MessageType.MSG_SESS: self.on_msg_sess(data) elif msg_type == MessageType.MSG_REL: self.on_msg_rel(data) elif msg_type == MessageType.MSG_ACK: self.on_msg_ack(data) elif msg_type == MessageType.MSG_OBJDATA: self.on_msg_objdata(data) elif msg_type == MessageType.MSG_CLOSE: self.on_msg_close() else: pass if self.get_gs() == GameState.CLOSE: return except GameException as e: self.error('Game session error: ' + str(e))
def handle_clicknearest_message(self, data): if self.get_gs() != GameState.PLAY: # TODO: Send response back to the client return if self.mapview_wdg_id == -1: self.sendMessage( unicode( json.dumps({ 'action': 'clicknearest', 'success': False, 'reason': 'Map has not been constructed yet' }))) return obj_name = data['name'] if obj_name != 'table': self.sendMessage( unicode( json.dumps({ 'action': 'clicknearest', 'success': False, 'reason': 'Unsupported object name' }))) return with self.gobs_lock: tables = [] pl = None for gob_id, gob in self.gobs.iteritems(): if gob.c is None: continue if gob.is_table(): tables.append(gob) elif gob_id == self.pgob_id: pl = gob if len(tables) == 0: self.sendMessage( unicode( json.dumps({ 'action': 'clicknearest', 'success': False, 'reason': 'No tables found (try again later)' }))) return if pl is None: self.sendMessage( unicode( json.dumps({ 'action': 'clicknearest', 'success': False, 'reason': 'Player object has not been received yet' }))) return nearest = None nearestc = None for table in tables: d = Coord.diff(pl.c, table.c) if nearest is None or d.x + d.y < nearestc: nearest = table nearestc = d.x + d.y msg = MessageBuf() msg.add_uint8(RelMessageType.RMSG_WDGMSG) msg.add_uint16(self.mapview_wdg_id) msg.add_string('click') msg.add_list([ Coords.Z, # pc (not used) Coords.Z, # mc (not used) 3, # RMB 0, # modflags (no Alt / Ctrl / etc) 0, # no overlay nearest.gob_id, Coord.floor(nearest.c, Coords.POSRES), 0, # overlay ID -1 # click ID ]) self.queue_rmsg(msg) self.sendMessage( unicode(json.dumps({ 'action': 'clicknearest', 'success': True })))
def __prepend_header(self, msg): tmp = MessageBuf() tmp.add_uint16(len(msg.buf), be=True) tmp.add_bytes(msg.buf) return tmp
def ack(self, seq): msg = MessageBuf() msg.add_uint8(MessageType.MSG_ACK) msg.add_uint16(seq) self.send_msg(msg)
def beat(self): msg = MessageBuf() msg.add_uint8(MessageType.MSG_BEAT) self.send_msg(msg)
def on_msg_objdata(self, msg): # NOTE: We don't really need to handle all of these messages, # we just want to get rid of most of them by sending the corresponding MSG_OBJACK messages while not msg.eom(): fl = msg.get_uint8() id = msg.get_uint32() frame = msg.get_int32() while True: data_type = msg.get_uint8() if data_type == ObjDataType.OD_REM: with self.gobs_lock: del self.gobs[id] self.sendMessage( unicode(json.dumps({ 'action': 'gobrem', 'id': id }))) elif data_type == ObjDataType.OD_MOVE: msg.get_int32() msg.get_int32() ia = msg.get_uint16() elif data_type == ObjDataType.OD_RES: resid = msg.get_uint16() if (resid & 0x8000) != 0: resid &= ~0x8000 sdt_len = msg.get_uint8() sdt = MessageBuf(msg.get_bytes(sdt_len)) elif data_type == ObjDataType.OD_LINBEG: msg.get_int32() msg.get_int32() msg.get_int32() msg.get_int32() elif data_type == ObjDataType.OD_LINSTEP: w = msg.get_int32() if w == -1: pass elif (w & 0x80000000) == 0: pass else: w = msg.get_int32() elif data_type == ObjDataType.OD_SPEECH: zo = msg.get_int16() / 100.0 text = msg.get_string() elif data_type == ObjDataType.OD_COMPOSE: resid = msg.get_uint16() with self.gobs_lock: gob = self.gobs.get(id, Gob(id)) gob.compose(resid) self.gobs[id] = gob elif data_type == ObjDataType.OD_CMPPOSE: pfl = msg.get_uint8() seq = msg.get_uint8() if (pfl & 2) != 0: while True: resid = msg.get_uint16() if resid == 65535: break if (resid & 0x8000) != 0: resid &= ~0x8000 sdt_len = msg.get_uint8() sdt = MessageBuf(msg.get_bytes(sdt_len)) if (pfl & 4) != 0: while True: resid = msg.get_uint16() if resid == 65535: break if (resid & 0x8000) != 0: resid &= ~0x8000 sdt_len = msg.get_uint8() sdt = MessageBuf(msg.get_bytes(sdt_len)) ttime = msg.get_uint8() / 10.0 elif data_type == ObjDataType.OD_CMPMOD: while True: modid = msg.get_uint16() if modid == 65535: break while True: resid = msg.get_uint16() if resid == 65535: break if (resid & 0x8000) != 0: resid &= ~0x8000 sdt_len = msg.get_uint8() sdt = MessageBuf(msg.get_bytes(sdt_len)) elif data_type == ObjDataType.OD_CMPEQU: while True: h = msg.get_uint8() if h == 255: break ef = h & 0x80 et = h & 0x7f at = msg.get_string() resid = msg.get_uint16() if (resid & 0x8000) != 0: resid &= ~0x8000 sdt_len = msg.get_uint8() sdt = MessageBuf(msg.get_bytes(sdt_len)) if (ef & 128) != 0: x = msg.get_int16() y = msg.get_int16() z = msg.get_int16() elif data_type == ObjDataType.OD_ZOFF: off = msg.get_int16() / 100.0 elif data_type == ObjDataType.OD_LUMIN: msg.get_int32() msg.get_int32() sz = msg.get_uint16() sstr = msg.get_uint8() elif data_type == ObjDataType.OD_AVATAR: while True: layer = msg.get_uint16() if layer == 65535: break elif data_type == ObjDataType.OD_FOLLOW: oid = msg.get_uint32() if oid != 0xffffffffl: xfres = msg.get_uint16() # getres xfname = msg.get_string() elif data_type == ObjDataType.OD_HOMING: oid = msg.get_uint32() if oid != 0xffffffffl: pass else: msg.get_int32() msg.get_int32() msg.get_int32( ) # double v = msg.int32() * 0x1p-10 * 11; elif data_type == ObjDataType.OD_OVERLAY: oid = msg.get_int32() resid = msg.get_uint16() if resid == 65535: pass else: if (resid & 0x8000) != 0: resid &= ~0x8000 sdt_len = msg.get_uint8() sdt = MessageBuf(msg.get_bytes(sdt_len)) elif data_type == ObjDataType.OD_HEALTH: hp = msg.get_uint8() elif data_type == ObjDataType.OD_BUDDY: name = msg.get_string() if len(name) > 0: group = msg.get_uint8() btype = msg.get_uint8() with self.gobs_lock: gob = self.gobs.get(id, Gob(id)) gob.buddy(name) self.gobs[id] = gob self.sendMessage( unicode( json.dumps({ 'action': 'buddy', 'id': id, 'name': name }))) elif data_type == ObjDataType.OD_ICON: resid = msg.get_uint16() if resid == 65535: pass else: ifl = msg.get_uint8() elif data_type == ObjDataType.OD_RESATTR: resid = msg.get_uint16() dat_len = msg.get_uint8() if dat_len > 0: dat = MessageBuf(msg.get_bytes(dat_len)) elif data_type == ObjDataType.OD_END: break msg = MessageBuf() msg.add_uint8(MessageType.MSG_OBJACK) msg.add_uint32(id) msg.add_int32(frame) self.gc.send_msg(msg)
def recv_msg(self): data, addr = self.s.recvfrom(65535) msg = MessageBuf(data) if self.verbose: self.info('< ' + str(msg)) return msg