From cb7aa59d896b3171cf6066258f874f194ef7c5e0 Mon Sep 17 00:00:00 2001 From: AleaJactaEst Date: Wed, 15 Apr 2020 19:28:02 +0200 Subject: [PATCH] decode message in ACTION_GENERIC_MULTI_PART_CODE --- spykhanat.py | 11 +++++ tools/CGenericMultiPartTemp.py | 50 ++++++++++---------- tools/Enum.py | 9 ++++ tools/Impulse.py | 83 ++++++++++++++++++++++++++++++++-- 4 files changed, 122 insertions(+), 31 deletions(-) diff --git a/spykhanat.py b/spykhanat.py index 60e71d6..122fa81 100755 --- a/spykhanat.py +++ b/spykhanat.py @@ -411,6 +411,14 @@ class SpyPcap(): pass logging.getLogger(LOGGER).debug("[Server -> Client] ACTION_GENERIC_MULTI_PART_CODE : %s" % action) for id in self.client_state[dst]['GenericMultiPartTempServer'].data: + logging.getLogger(LOGGER).info("[Server -> Client] ACTION_GENERIC_MULTI_PART_CODE {id:%d, available:%s NbBlock:%d/%d, isDecoded:%s, FirstRead:%s}" % ( + id, + self.client_state[dst]['GenericMultiPartTempServer'].data[id].isAvailable(), + self.client_state[dst]['GenericMultiPartTempServer'].data[id].getNbCurrentBlock(), + self.client_state[dst]['GenericMultiPartTempServer'].data[id].NbBlock, + self.client_state[dst]['GenericMultiPartTempServer'].data[id].isDecoded(), + self.client_state[dst]['GenericMultiPartTempServer'].data[id].FirstRead + )) if self.client_state[dst]['GenericMultiPartTempServer'].data[id].isAvailable(): logging.getLogger(LOGGER).info("[Server -> Client] ACTION_GENERIC_MULTI_PART_CODE {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d, id:%d, msg:%s}" % ( CurrentSendNumber, src, dst, _LastReceivedAck, id, @@ -423,6 +431,9 @@ class SpyPcap(): ) temp.Reference = self.client_state[dst]['GenericMultiPartTempServer'].data[id].Reference actionsbis.append(temp) + else: + logging.getLogger(LOGGER).info("[Server -> Client] ACTION_GENERIC_MULTI_PART_CODE {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d, id:%d}" % ( + CurrentSendNumber, src, dst, _LastReceivedAck, id)) elif action.Code == Enum.TActionCode.ACTION_DUMMY_CODE: #action.add_reference(Parent) logging.getLogger(LOGGER).info("Action : ACTION_DUMMY_CODE") diff --git a/tools/CGenericMultiPartTemp.py b/tools/CGenericMultiPartTemp.py index d329c7f..476d4e4 100644 --- a/tools/CGenericMultiPartTemp.py +++ b/tools/CGenericMultiPartTemp.py @@ -26,15 +26,15 @@ LOGGER='CGenericMultiPartTemp' class CGenericMultiPartTemp(): def __init__(self): self.NbBlock = 0xFFFFFFFF - self.NbCurrentBlock = 0 - self.TempSize = 0 - self.Temp = [] - self.BlockReceived = [] self.MsgDecoded = None self.FirstRead = False self.Reference = [] + self.block = {} self.Name = None + def getNbCurrentBlock(self): + return len(self.block) + def set(self, Number, Part, NbBlock, PartCont, decodeImpulse, world, Reference = None, Name = None): ''' khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::CGenericMultiPartTemp::set (CActionGenericMultiPart *agmp, CNetworkConnection *parent) @@ -48,36 +48,34 @@ class CGenericMultiPartTemp(): if self.NbBlock == 0xFFFFFFFF: # Initialize self.NbBlock = NbBlock - self.NbCurrentBlock = 0 - self.TempSize = 0 - self.Temp = [] - while len(self.Temp) < NbBlock: - self.Temp.append(None) - while len(self.BlockReceived) < NbBlock: - self.BlockReceived.append(False) - if self.BlockReceived[Part]: - logging.getLogger(LOGGER).debug('This part is already received, discard it %d' % Part) - return - self.Temp[Part] = PartCont - self.BlockReceived[Part] = True - self.NbCurrentBlock += 1 - self.TempSize += len(PartCont) - - logging.getLogger(LOGGER).debug("NbCurrentBlock:%d / NbBlock:%d" % (self.NbCurrentBlock, self.NbBlock)) - if self.NbCurrentBlock == self.NbBlock: + self.block.setdefault(Part, PartCont) + self.block.setdefault(Part, None) + self.block[Part] = PartCont + logging.getLogger(LOGGER).error("CGenericMultiPartTemp : Number:%d len:%d/%d" % (Number, len(self.block), self.NbBlock)) + if len(self.block) == self.NbBlock: # reform the total action bms = BitStream.BitStream() self.NbBlock == 0xFFFFFFFF - for data in self.Temp: - bms.pushBitStream(data) - ret = decodeImpulse.execute(bms, world) - logging.getLogger(LOGGER).debug("CGenericMultiPartTemp : data : %s" % bms.showAllData()) + for data in self.block: + logging.getLogger(LOGGER).error("CGenericMultiPartTemp : Number:%d id:%d len:%d/%d" % (Number, data, len(self.block), self.NbBlock)) + bms.pushBitStream(self.block[data]) + try: + ret = decodeImpulse.execute(bms, world) + except: + logging.getLogger(LOGGER).error("CGenericMultiPartTemp : Error to decode - Number:%d len:%d/%d msg:%s" % (Number, len(self.block), self.NbBlock, bms.showAllData())) + return ret + logging.getLogger(LOGGER).error("CGenericMultiPartTemp : data : %s" % bms.showAllData()) self.MsgDecoded = bms else: - logging.getLogger(LOGGER).debug("CGenericMultiPartTemp : Wait other block") + logging.getLogger(LOGGER).error("CGenericMultiPartTemp : Wait other block Number:%d [%d/%d]" % (Number, len(self.block), self.NbBlock)) return ret + def isDecoded(self): + if self.MsgDecoded: + return True + return False + def isAvailable(self): if self.MsgDecoded and not self.FirstRead: return True diff --git a/tools/Enum.py b/tools/Enum.py index c0da949..e1f721f 100644 --- a/tools/Enum.py +++ b/tools/Enum.py @@ -603,3 +603,12 @@ class TItemPropId(IntEnum): PrerequisitValid = 14, Worned = 15, NbItemPropId = 16 + +class TCDBBank(IntEnum): + CDBPlayer = 0, + CDBGuild = 1, + # /* CDBContinent, + CDBOutpost 2, + #/* CDBGlobal, */ + NB_CDB_BANKS = 3, + INVALID_CDB_BANK = 4 diff --git a/tools/Impulse.py b/tools/Impulse.py index e62447f..1907e03 100644 --- a/tools/Impulse.py +++ b/tools/Impulse.py @@ -120,6 +120,16 @@ class ImpulseBase: self.param.setdefault(id, value) return value + def readUint64(self, msgin, id): + value = msgin.readUint64(id) + self.param.setdefault(id, value) + return value + + def readSint64(self, msgin, id): + value = msgin.readSint64(id) + self.param.setdefault(id, value) + return value + def readSerial(self, msgin, nbBits, id): if nbBits == 1: value = msgin.readSerial(nbBits, id, typeName="bool/1 bit") @@ -148,6 +158,12 @@ class ImpulseBase: self.param.setdefault(id, value) return value + def readVersion(self, msgin, id): + value = msgin.readUint8(id) + if value == 255: #0xFF: # 0xFF + value = msgin.readUint32(id + '_extended') + self.param.setdefault(id, value) + return value class ImpulseBotchatSetFilters(ImpulseBase): def __init__(self): @@ -564,6 +580,65 @@ class impulseInitInventory(ImpulseBase): _ = self.readSerial(msgin, 10, '%s_%d_%d_iuReset_SlotIndex' %(id, invId, itu)) #self.param.setdefault('%s_%d_y' % (id, i), msgin.readSint32('%s_%d_y' % (id, i))) + +class ImpulseConnectionUserChars(ImpulseBase): + def __init__(self): + super().__init__() + + def read(self, name, msgin, world): + # khanat-opennel-code/code/ryzom/client/src/net_manager.cpp void impulseUserChars(NLMISC::CBitMemStream &impulse) + # khanat-opennel-code/code/ryzom/server/src/entities_game_service/entity_manager/entity_callbacks.cpp void sendCharactersSummary( CPlayer *player, bool AllAutorized, uint32 bitfieldOwnerOfActiveAnimSession, uint32 bitfieldOwnerOfEditSession ) + id = "ConnectionUserChars" + logging.getLogger(LOGGER).debug("read") + self.name = name.replace(':', '_') + _ = self.readUint8(msgin, '%s_ServerPeopleActive' % id) + _ = self.readUint8(msgin, '%s_ServerCareerActive' % id) + CharacterSummaries_Len = self.readUint32(msgin, '%s_CharacterSummaries_Len' % id) + for i in range(0, CharacterSummaries_Len): + self.readVersion(msgin, "%s_CharacterSummaries_%d_Version" % (id, i)) + self.readUint32(msgin, '%s_CharacterSummaries_%d_Mainland' % (id, i)) + self.readUString(msgin, '%s_CharacterSummaries_%d_Name' % (id, i)) + self.readSint32(msgin, '%s_CharacterSummaries_%d_People' % (id, i)) + self.readUint32(msgin, '%s_CharacterSummaries_%d_Location' % (id, i)) + self.readUint64(msgin, '%s_CharacterSummaries_%d_VisualPropA' % (id, i)) + self.readUint64(msgin, '%s_CharacterSummaries_%d_VisualPropB' % (id, i)) + self.readUint64(msgin, '%s_CharacterSummaries_%d_VisualPropC' % (id, i)) + self.readUint32(msgin, '%s_CharacterSummaries_%d_SheetId' % (id, i)) + self.readSint32(msgin, '%s_CharacterSummaries_%d_Title' % (id, i)) + self.readUint8(msgin, '%s_CharacterSummaries_%d_CharacterSlot' % (id, i)) + self.readBool(msgin, '%s_CharacterSummaries_%d_InRingSession' % (id, i)) + self.readBool(msgin, '%s_CharacterSummaries_%d_HasEditSession' % (id, i)) + self.readBool(msgin, '%s_CharacterSummaries_%d_InNewbieland' % (id, i)) + shardNames_Len = self.readUint32(msgin, '%s_ShardNames_Len' % id) + for i in range(0, shardNames_Len): + self.readString(msgin, '%s_ShardNames_%d' % (id, i)) + _ = self.readString(msgin, '%s_Privileges' % id) + self.readBool(msgin, '%s_FreeTrial' % (id)) + Mainlands_Len = self.readUint32(msgin, '%s_Mainlands_Len' % id) + for i in range(0, Mainlands_Len): + self.readUint32(msgin, '%s_Mainlands_%d_id' % (id, i)) + self.readUString(msgin, '%s_Mainlands_%d_Name' % (id, i)) + self.readUString(msgin, '%s_Mainlands_%d_Description' % (id, i)) + self.readString(msgin, '%s_Mainlands_%d_LanguageCode' % (id, i)) + self.readBool(msgin, '%s_Mainlands_%d_Online' % (id, i)) + + +class impulseDatabaseInitPlayer(ImpulseBase): + def __init__(self): + super().__init__() + + def read(self, name, msgin, world): + # khanat-opennel-code/code/ryzom/client/src/net_manager.cpp void impulseDatabaseInitPlayer(NLMISC::CBitMemStream &impulse) + # khanat-opennel-code/code/ryzom/server/src/simulation_service/simulated_editor.cpp void impulseDatabaseInitPlayer(NLMISC::CBitMemStream &impulse) + id = "DatabaseInitPlayer" + logging.getLogger(LOGGER).debug("read") + self.name = name.replace(':', '_') + self.readUint32(msgin, '%s_serverTick' % id) + propertyCount = self.readUint16(msgin, '%s_propertyCount' % id) + for i in range(0, propertyCount): + propertyCount = self.readUint32(msgin, '%s_propertyCount' % id) + + class DecodeImpulseSimple: def __init__(self): ''' @@ -583,6 +658,7 @@ class DecodeImpulseSimple: self.GenericMsgHeaderMngr.setdefault( "CONNECTION:SELECT_CHAR", ImpulseConnectionSelectChar ) self.GenericMsgHeaderMngr.setdefault( "CONNECTION:SHARD_ID", ImpulseConnectionShardId ) self.GenericMsgHeaderMngr.setdefault( "CONNECTION:USER_CHAR", ImpulseConnectionUserChar ) + self.GenericMsgHeaderMngr.setdefault( "CONNECTION:USER_CHARS", ImpulseConnectionUserChars ) self.GenericMsgHeaderMngr.setdefault( "CONNECTION:VALID_NAME", ImpulseConnectionValidName ) self.GenericMsgHeaderMngr.setdefault( "DEBUG:PING", ImpulseDebugPing ) self.GenericMsgHeaderMngr.setdefault( "DEATH:RESPAWN_POINT", impulseDeathRespawnPoint) @@ -598,6 +674,7 @@ class DecodeImpulseSimple: self.GenericMsgHeaderMngr.setdefault( "STRING_MANAGER:STRING_RQ", ImpulseSringManagerStringRq ) self.GenericMsgHeaderMngr.setdefault( "ENCYCLOPEDIA:INIT", impulseEncyclopediaInit ) self.GenericMsgHeaderMngr.setdefault( "DB_INIT:INV", impulseInitInventory) +# self.GenericMsgHeaderMngr.setdefault( "DB_INIT:PLR", impulseDatabaseInitPlayer) def execute(self, msgin, world, references = [], name=""): ''' @@ -652,12 +729,8 @@ class DecodeImpulseSimple: a = msgin.readSerial(nbBitNotRead, decode=False) if a == 0: return impulse - logging.getLogger(LOGGER).error("MessageXML not decoded: [%s] %s [size:%d, last:%d]" % (fullname, msgin.showAllData(), nbBitNotRead, a)) - raise "Message not full decoded" - # logging.getLogger(LOGGER).error("Code not fully decoded [name:%s, id:%s]" % (name, fullname)) -# logging.getLogger(LOGGER).error("MessageXML decoded: %s" % msgin.showAllData() ) + logging.getLogger(LOGGER).error("MessageXML not decoded: [%s] %s [size:%d, not read:%d]" % (fullname, msgin.showAllData(), nbBitNotRead, a)) logging.getLogger(LOGGER).error("MessageXML not decoded: [%s] %s [size:%d]" % (fullname, msgin.showAllData(), nbBitNotRead)) - raise "Message not full decoded" return None else: #logging.getLogger(LOGGER).debug("Non trouve")