From 66f67603d4272dc5f8222a8aa3796c25180f14cc Mon Sep 17 00:00:00 2001 From: AleaJactaEst Date: Mon, 13 Apr 2020 23:44:47 +0200 Subject: [PATCH] update spykhanat --- tools/DecodeImpulse.py | 2 + tools/Enum.py | 26 +++ tools/Impulse.py | 443 +++++++++++++++++++++++++++++++---------- 3 files changed, 362 insertions(+), 109 deletions(-) diff --git a/tools/DecodeImpulse.py b/tools/DecodeImpulse.py index c5bf7ec..8c56508 100644 --- a/tools/DecodeImpulse.py +++ b/tools/DecodeImpulse.py @@ -248,6 +248,8 @@ class DecodeImpulse(): def impulseGuildUpdatePlayerTitle(self, msgin, world): logging.getLogger(LOGGER).debug("TODO") + # bUnblock = msgin.readBool('bUnblock') + def impulseGuildUseFemaleTitles(self, msgin, world): world.UseFemaleTitles = msgin.readBool('UseFemaleTitles') logging.getLogger(LOGGER).debug("UseFemaleTitles") diff --git a/tools/Enum.py b/tools/Enum.py index 7ae0d90..c0da949 100644 --- a/tools/Enum.py +++ b/tools/Enum.py @@ -577,3 +577,29 @@ class NPC_ICON(IntEnum): # TNPCMissionGiverState AutoHasUnavailableMissions = 5 AutoHasAvailableMission = 6 NbMissionGiverStates = 7 + +class TInventoryId(IntEnum): + Bag = 0, + Packers = 1, + Room= 5, # Packers+MaxNbPackers, + InvalidInvId = 6, + NbInventoryIds = 6, # =InvalidInvId + +class TItemPropId(IntEnum): + Sheet = 0, + Quality = 1, + Quantity = 2, + UserColor = 3, + CreateTime = 4, + Serial = 5, + Locked = 6, + Weight = 7, + NameId = 8, + Enchant = 9, + ItemClass = 10, + ItemBestStat = 11, + Price = 12, + ResaleFlag = 13, + PrerequisitValid = 14, + Worned = 15, + NbItemPropId = 16 diff --git a/tools/Impulse.py b/tools/Impulse.py index 9194808..e62447f 100644 --- a/tools/Impulse.py +++ b/tools/Impulse.py @@ -21,8 +21,28 @@ import logging from tools import getPowerOf2 from tools import BitStream +from tools import Enum # from tools import Enum +ItemPropStr = [ + "SHEET", # 32 + "QUALITY", # 10 + "QUANTITY", # 10 + "USER_COLOR", # 3 + "CREATE_TIME", # 32 + "SERIAL", # 32 + "LOCKED", # 10 + "WEIGHT", # 16 + "NAMEID", # 32 + "ENCHANT", # 10 + "RM_CLASS_TYPE", # 3 + "RM_FABER_STAT_TYPE", # 5 + "PRICE", # 32 + "RESALE_FLAG", # 2 + "PREREQUISIT_VALID", # 1 + "WORNED" # 1 + ] +DataBitSize = [32, 10, 10, 3, 32, 32, 10, 16, 32, 10, 3, 5, 32, 2, 1, 1] LOGGER='Impulse' @@ -65,6 +85,69 @@ class ImpulseBase: def read(self, name, msgin, world): logging.getLogger(LOGGER).error("Not define") + def readBool(self, msgin, id): + value = msgin.readBool(id) + self.param.setdefault(id, value) + return value + + def readUint8(self, msgin, id): + value = msgin.readUint8(id) + self.param.setdefault(id, value) + return value + + def readSint8(self, msgin, id): + value = msgin.readSint8(id) + self.param.setdefault(id, value) + return value + + def readUint16(self, msgin, id): + value = msgin.readUint16(id) + self.param.setdefault(id, value) + return value + + def readSint16(self, msgin, id): + value = msgin.readSint16(id) + self.param.setdefault(id, value) + return value + + def readUint32(self, msgin, id): + value = msgin.readUint32(id) + self.param.setdefault(id, value) + return value + + def readSint32(self, msgin, id): + value = msgin.readSint32(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") + else: + value = msgin.readSerial(nbBits, id, typeName="%d bits" % nbBits) + self.param.setdefault(id, value) + return value + + def readUString(self, msgin, id): + value = msgin.readUString(id) + self.param.setdefault(id, value) + return value + + def readUtf8String(self, msgin, id): + value = msgin.readUtf8String(id) + self.param.setdefault(id, value) + return value + + def readString(self, msgin, id): + value = msgin.readString(id) + self.param.setdefault(id, value) + return value + + def readFloat(self, msgin, id): + value = msgin.readFloat(id) + self.param.setdefault(id, value) + return value + class ImpulseBotchatSetFilters(ImpulseBase): def __init__(self): @@ -73,14 +156,14 @@ class ImpulseBotchatSetFilters(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('qualityMin', msgin.readUint32('qualityMin')) - self.param.setdefault('qualityMax', msgin.readUint32('qualityMax')) - self.param.setdefault('priceMin', msgin.readUint32('priceMin')) - self.param.setdefault('priceMax', msgin.readUint32('priceMax')) - self.param.setdefault('classMin', msgin.readUint8('classMin')) - self.param.setdefault('classMax', msgin.readUint8('classMax')) - self.param.setdefault('itemPart', msgin.readUint8('itemPart')) - self.param.setdefault('itemType', msgin.readUint8('itemType')) + self.readUint32(msgin, 'qualityMin') + self.readUint32(msgin, 'qualityMax') + self.readUint32(msgin, 'priceMin') + self.readUint32(msgin, 'priceMax') + self.readUint8(msgin, 'classMin') + self.readUint8(msgin, 'classMax') + self.readUint8(msgin, 'itemPart') + self.readUint8(msgin, 'itemType') class ImpulseConnectionAskName(ImpulseBase): @@ -90,8 +173,8 @@ class ImpulseConnectionAskName(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('Name', msgin.readUString('Name')) - self.param.setdefault('HomeSessionId', msgin.readUint32('HomeSessionId')) + self.readUString(msgin, 'Name') + self.readUint32(msgin, 'HomeSessionId') class ImpulseConnectionCreateChar(ImpulseBase): @@ -101,40 +184,40 @@ class ImpulseConnectionCreateChar(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('Slot', msgin.readUint8('Slot')) - self.param.setdefault('SheetId', msgin.readUint32('SheetId')) - self.param.setdefault('CSessionId', msgin.readUint32('CSessionId')) - self.param.setdefault('name', msgin.readUString('name')) - self.param.setdefault('People', msgin.readUint8('People')) - self.param.setdefault('Sex', msgin.readUint8('Sex')) - self.param.setdefault('NbPointFighter', msgin.readUint8('NbPointFighter')) - self.param.setdefault('NbPointCaster', msgin.readUint8('NbPointCaster')) - self.param.setdefault('NbPointCrafter', msgin.readUint8('NbPointCrafter')) - self.param.setdefault('NbPointHarvester', msgin.readUint8('NbPointHarvester')) - self.param.setdefault('StartPoint', msgin.readSint32('StartPoint')) - self.param.setdefault('HairType', msgin.readSint8('HairType')) - self.param.setdefault('HairColor', msgin.readSint8('HairColor')) - self.param.setdefault('GabaritHeight', msgin.readSint8('GabaritHeight')) - self.param.setdefault('GabaritTorsoWidth', msgin.readSint8('GabaritTorsoWidth')) - self.param.setdefault('GabaritArmsWidth', msgin.readSint8('GabaritArmsWidth')) - self.param.setdefault('GabaritLegsWidth', msgin.readSint8('GabaritLegsWidth')) - self.param.setdefault('GabaritBreastSize', msgin.readSint8('GabaritBreastSize')) - self.param.setdefault('MorphTarget1', msgin.readSint8('MorphTarget1')) - self.param.setdefault('MorphTarget2', msgin.readSint8('MorphTarget2')) - self.param.setdefault('MorphTarget3', msgin.readSint8('MorphTarget3')) - self.param.setdefault('MorphTarget4', msgin.readSint8('MorphTarget4')) - self.param.setdefault('MorphTarget5', msgin.readSint8('MorphTarget5')) - self.param.setdefault('MorphTarget6', msgin.readSint8('MorphTarget6')) - self.param.setdefault('MorphTarget7', msgin.readSint8('MorphTarget7')) - self.param.setdefault('MorphTarget8', msgin.readSint8('MorphTarget8')) - self.param.setdefault('EyesColor', msgin.readSint8('EyesColor')) - self.param.setdefault('Tattoo', msgin.readSint8('Tattoo')) - self.param.setdefault('JacketColor', msgin.readSint8('JacketColor')) - self.param.setdefault('TrousersColor', msgin.readSint8('TrousersColor')) - self.param.setdefault('HatColor', msgin.readSint8('HatColor')) - self.param.setdefault('ArmsColor', msgin.readSint8('ArmsColor')) - self.param.setdefault('HandsColor', msgin.readSint8('HandsColor')) - self.param.setdefault('FeetColor', msgin.readSint8('FeetColor')) + self.readUint8(msgin, 'Slot') + self.readUint32(msgin, 'SheetId') + self.readUint32(msgin, 'CSessionId') + self.readUString(msgin, 'name') + self.readUint8(msgin, 'People') + self.readUint8(msgin, 'Sex') + self.readUint8(msgin, 'NbPointFighter') + self.readUint8(msgin, 'NbPointCaster') + self.readUint8(msgin, 'NbPointCrafter') + self.readUint8(msgin, 'NbPointHarvester') + self.readSint32(msgin, 'StartPoint') + self.readSint8(msgin, 'HairType') + self.readSint8(msgin, 'HairColor') + self.readSint8(msgin, 'GabaritHeight') + self.readSint8(msgin, 'GabaritTorsoWidth') + self.readSint8(msgin, 'GabaritArmsWidth') + self.readSint8(msgin, 'GabaritLegsWidth') + self.readSint8(msgin, 'GabaritBreastSize') + self.readSint8(msgin, 'MorphTarget1') + self.readSint8(msgin, 'MorphTarget2') + self.readSint8(msgin, 'MorphTarget3') + self.readSint8(msgin, 'MorphTarget4') + self.readSint8(msgin, 'MorphTarget5') + self.readSint8(msgin, 'MorphTarget6') + self.readSint8(msgin, 'MorphTarget7') + self.readSint8(msgin, 'MorphTarget8') + self.readSint8(msgin, 'EyesColor') + self.readSint8(msgin, 'Tattoo') + self.readSint8(msgin, 'JacketColor') + self.readSint8(msgin, 'TrousersColor') + self.readSint8(msgin, 'HatColor') + self.readSint8(msgin, 'ArmsColor') + self.readSint8(msgin, 'HandsColor') + self.readSint8(msgin, 'FeetColor') class ImpulseConnectionReady(ImpulseBase): @@ -144,7 +227,7 @@ class ImpulseConnectionReady(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('LanguageCode', msgin.readString('LanguageCode')) + self.readString(msgin, 'LanguageCode') class ImpulseConnectionSelectChar(ImpulseBase): @@ -154,7 +237,7 @@ class ImpulseConnectionSelectChar(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('SelectCharMsg', msgin.readUint8('SelectCharMsg')) + self.readUint8(msgin, 'SelectCharMsg') class ImpulseConnectionUserChar(ImpulseBase): @@ -164,15 +247,15 @@ class ImpulseConnectionUserChar(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('X', msgin.readSint32('X')) - self.param.setdefault('Y', msgin.readSint32('Y')) - self.param.setdefault('Z', msgin.readSint32('Z')) - self.param.setdefault('Heading', msgin.readFloat('Heading')) - self.param.setdefault('season', msgin.readSerial(3, 'season')) - self.param.setdefault('userRole', msgin.readSerial(3, 'userRole')) - self.param.setdefault('highestMainlandSessionId', msgin.readUint32('highestMainlandSessionId')) - self.param.setdefault('firstConnectedTime', msgin.readUint32('firstConnectedTime')) - self.param.setdefault('playedTime', msgin.readUint32('playedTime')) + self.readSint32(msgin, 'X') + self.readSint32(msgin, 'Y') + self.readSint32(msgin, 'Z') + self.readFloat(msgin, 'Heading') + self.readSerial(msgin, 3, 'season') + self.readSerial(msgin, 3, 'userRole') + self.readUint32(msgin, 'highestMainlandSessionId') + self.readUint32(msgin, 'firstConnectedTime') + self.readUint32(msgin, 'playedTime') class ImpulseConnectionShardId(ImpulseBase): @@ -182,8 +265,8 @@ class ImpulseConnectionShardId(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('shardId', msgin.readUint32('shardId')) - self.param.setdefault('webHost', msgin.readString('webHost')) + self.readUint32(msgin, 'shardId') + self.readString(msgin, 'webHost') class ImpulseConnectionValidName(ImpulseBase): @@ -193,7 +276,7 @@ class ImpulseConnectionValidName(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('valide', msgin.readUint8('valide')) + self.readUint8(msgin, 'valide') class ImpulseDebugPing(ImpulseBase): @@ -203,7 +286,7 @@ class ImpulseDebugPing(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('localTime', msgin.readUint32('localTime')) + self.readUint32(msgin, 'localTime') class ImpulseGuildFemaleTitles(ImpulseBase): @@ -213,7 +296,7 @@ class ImpulseGuildFemaleTitles(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('UseFemaleTitles', msgin.readSerial(1, 'UseFemaleTitles')) + self.readSerial(msgin, 1, 'UseFemaleTitles') class ImpulseNpsIconSetDesc(ImpulseBase): @@ -226,11 +309,10 @@ class ImpulseNpsIconSetDesc(ImpulseBase): ''' logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('nb8', msgin.readUint8('nb8')) - nb8 = self.param['nb8'] + nb8 = self.readUint8(msgin, 'nb8') for i in range(0, nb8): - self.param.setdefault('%d:npcAlias' % nb8, msgin.readUint32('npcAlias')) - self.param.setdefault('%d:state' % nb8, msgin.readUint32('state')) + self.readUint32(msgin, 'NpcIconSetDesc_%d_npcAlias' % nb8) + self.readUint32(msgin, 'NpcIconSetDesc_%d_state' % nb8) class ImpulsePhraseDownload(ImpulseBase): @@ -238,11 +320,10 @@ class ImpulsePhraseDownload(ImpulseBase): super().__init__() def readSerialPhrase(self, msgin, id): - self.param.setdefault(id, msgin.readUtf8String(id)) - size = msgin.readSint32(id + ':len') - self.param.setdefault(id + ':len', size) + self.readUtf8String(msgin, id) + size = self.readSint32(msgin, id + '_len') for i in range(0, size): - self.param.setdefault('%s:compBricks:%d' % (id, i), msgin.readUint16('%s:compBricks:%d' % (id, i))) + self.readUint16(msgin, '%s_compBricks_%d' % (id, i)) def readSerialPhrases(self, msgin, id): """ @@ -250,24 +331,30 @@ class ImpulsePhraseDownload(ImpulseBase): khanat-opennel-code/code/nel/include/nel/misc/stream.h:1089 void serialVector(T &cont) khanat-opennel-code/code/ryzom/common/src/game_share/sphrase_com.cpp:57 void CSPhraseCom::serial(NLMISC::IStream &impulse) """ - size = msgin.readSint32(id + ':len') - self.param.setdefault(id + ':len', size) + size = self.readSint32(msgin, id + '_len') for i in range(0, size): #self.param.setdefault('%d:Phrase' % i, msgin.readUtf8String('%d:Phrase:Name' % i)) #self.param.setdefault('%d:Phrase' % i, msgin.readString('%d:Phrase' % i)) - self.readSerialPhrase(msgin, '%d:Phrase' % i) - self.param.setdefault('%d:KnownSlot' % i, msgin.readUint16('%d:KnownSlot' % i)) - self.param.setdefault('%d:PhraseSheetId:id' % i, msgin.readUint32('%d:PhraseSheetId:id' % i)) - self.param.setdefault('%d:PhraseSheetId:Type' % i, msgin.readUint32('%d:PhraseSheetId:IdInfos:Type' % i)) - self.param.setdefault('%d:PhraseSheetId:Type' % i, msgin.readUint32('%d:PhraseSheetId:IdInfos:Id' % i)) + self.readSerialPhrase(msgin, '%s_%d_Phrase' % (id, i)) + self.readUint16(msgin, '%s_%d_KnownSlot' % (id, i)) + self.readUint32(msgin, '%s_%d_PhraseSheetId' % (id, i)) + #self.param.setdefault('%d:PhraseSheetId:Type' % i, msgin.readUint32('%d:PhraseSheetId:IdInfos:Type' % i)) + #self.param.setdefault('%d:PhraseSheetId:Type' % i, msgin.readUint32('%d:PhraseSheetId:IdInfos:Id' % i)) def readSerialMemorizedPhrases(self, msgin, id): - size = msgin.readSint32(id + ':len') - self.param.setdefault(id + ':len', size) + size = self.readSint32(msgin, id + '_len') for i in range(0, size): - self.param.setdefault('%d:MemoryLineId' % i, msgin.readUint8('MemoryLineId')) - self.param.setdefault('%d:MemorySlotId' % i, msgin.readUint8('MemorySlotId')) - self.param.setdefault('%d:PhraseId' % i, msgin.readUint16('PhraseId')) + self.readUint8(msgin, '%s_%d_MemoryLineId' % (id, i)) + self.readUint8(msgin, '%s_%d_MemorySlotId' % (id, i)) + self.readUint16(msgin, '%s_%d_PhraseId' % (id, i)) +# tmp = {} +# for i in range(0, size): +# data = {} +# data.setdefault('MemoryLineId', msgin.readUint8('%d:MemoryLineId' % i)) +# data.setdefault('MemorySlotId', msgin.readUint8('%d:MemorySlotId' % i)) +# data.setdefault('PhraseId', msgin.readUint16('%d:PhraseId' %i)) +# tmp.setdefault('MemorizedPhrase_%d' % i, data) +# self.param.setdefault("MemorizedPhrase", tmp) def read(self, name, msgin, world): """ @@ -275,13 +362,13 @@ class ImpulsePhraseDownload(ImpulseBase): """ logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - return + # return #self.param.setdefault(id + 'phrases', msgin.readString('phrases')) #self.param.setdefault(id + 'memorizedPhrases', msgin.readString('memorizedPhrases')) - self.readSerialPhrases(msgin, 'knownPhrases') - self.readSerialMemorizedPhrases(msgin, 'memorizedPhrases') - logging.getLogger(LOGGER).error("[Client -> Server] msg:%s" % msgin.showAllData()) - raise ValueError + self.readSerialPhrases(msgin, 'KnownPhrases') + self.readSerialMemorizedPhrases(msgin, 'MemorizedPhrases') + #logging.getLogger(LOGGER).error("[Client -> Server] msg:%s" % msgin.showAllData()) + #raise ValueError class ImpulsePosition(ImpulseBase): @@ -291,10 +378,10 @@ class ImpulsePosition(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('X', msgin.readSint32('X')) - self.param.setdefault('Y', msgin.readSint32('Y')) - self.param.setdefault('Z', msgin.readSint32('Z')) - self.param.setdefault('Heading', msgin.readFloat('Heading')) + self.readSint32(msgin, 'X') + self.readSint32(msgin, 'Y') + self.readSint32(msgin, 'Z') + self.readFloat(msgin, 'Heading') class ImpulseSringDynString(ImpulseBase): @@ -304,7 +391,7 @@ class ImpulseSringDynString(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('phraseId', msgin.readUint32('phraseId')) + self.readUint32(msgin, 'phraseId') class ImpulseSringManagerReloadCache(ImpulseBase): @@ -314,7 +401,7 @@ class ImpulseSringManagerReloadCache(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('timestamp', msgin.readUint32('timestamp')) + self.readUint32(msgin, 'timestamp') class ImpulseSringManagerPhraseSend(ImpulseBase): @@ -324,16 +411,15 @@ class ImpulseSringManagerPhraseSend(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('dynId', msgin.readUint32('dynId')) - self.param.setdefault('StringId', msgin.readUint32('StringId')) - try: - id = 0 - while True: - self.param.setdefault('StringId:%d' % id, msgin.readUint32('StringId')) - id += 1 - except: - pass - + id = 'SringManagerPhrase' + #self.param.setdefault('%s_seqNum' %(id), msgin.readUint32('%s_seqNum' % (id))) + #self.param.setdefault('%s_id'%(id), msgin.readUint32('%s_id'%(id))) + self.readUint32(msgin, '%s_dynId' % id) + self.readUint32(msgin, '%s_StringId' % id) + i = 0 + while msgin.needRead() >= 32: + self.readUint32(msgin, '%s_StringId_%d' % (id, i)) + i += 1 class ImpulseSringManagerStringResp(ImpulseBase): def __init__(self): @@ -342,8 +428,8 @@ class ImpulseSringManagerStringResp(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('stringId', msgin.readUint32('stringId')) - self.param.setdefault('strUtf8', msgin.readUtf8String('strUtf8')) + self.readUint32(msgin, 'stringId') + self.readUtf8String(msgin, 'strUtf8') class ImpulseSringManagerStringRq(ImpulseBase): @@ -353,9 +439,131 @@ class ImpulseSringManagerStringRq(ImpulseBase): def read(self, name, msgin, world): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') - self.param.setdefault('stringId', msgin.readUint32('stringId')) + self.readUint32(msgin, 'stringId') +class impulseGuildUpdatePlayerTitle(ImpulseBase): + def __init__(self): + super().__init__() + + def read(self, name, msgin, world): + logging.getLogger(LOGGER).debug("read") + self.name = name.replace(':', '_') + self.readBool(msgin, 'bUnblock') + id = "vTitle" + size = self.readSint32(msgin, '%s_len' % id) + for i in range(0, size): + self.readUint16(msgin, '%s_%d' % (id, i)) + +class impulseDeathRespawnPoint(ImpulseBase): + def __init__(self): + super().__init__() + + def read(self, name, msgin, world): + id = "CRespawnPointsMsg" + logging.getLogger(LOGGER).debug("read") + self.name = name.replace(':', '_') + self.readBool(msgin, '%s_NeedToReset' % id) + size = self.readSint32(msgin, '%s_len' % id) + for i in range(0, size): + self.readSint32(msgin, '%s_%d_x' % (id, i)) + self.readSint32(msgin, '%s_%d_y' % (id, i)) + +class impulseEncyclopediaInit(ImpulseBase): + def __init__(self): + super().__init__() + + def read_thema(self, id, msgin): + size_thema = self.readSint32(msgin, '%s_thema_len' % (id)) + for ii in range(0, size_thema): + self.readUint32(msgin, '%s_thema_%d_Name' % (id, ii)) + StateNbTask = self.readUint8(msgin, '%s_thema_%d_StateNbTask' % (id, ii)) + State = StateNbTask & 0x3; + NbTask = StateNbTask >> 2 ; + if State == 2: + self.readUint32(msgin, '%s_thema_%d_RewardText' % (id, ii)) + self.readUint32(msgin, '%s_thema_%d_RewardSheet' % (id, ii)) + for iii in range(0, NbTask): + self.readUint32(msgin, '%s_thema_%d_Task_%d_Name' % (id, ii, iii)) + self.readUint32(msgin, '%s_thema_%d_Task_%d_NPCName' % (id, ii, iii)) + self.readUint16(msgin, '%s_thema_%d_RiteTaskStatePacked' % (id, ii)) + + def read_album(self, id, msgin): + self.readUint32(msgin, '%s_Album_Name' % (id)) + self.readUint32(msgin, '%s_Album_RewardBrick' % (id)) + self.readUint8(msgin, '%s_Album_State' % (id)) + self.read_thema(id, msgin) + + def read(self, name, msgin, world): + id = "EncyclopediaInit" + logging.getLogger(LOGGER).debug("read") + self.name = name.replace(':', '_') + type = self.readSint32(msgin, '%s_Type' % id) + if type == 0: # UpdateInit + id += '_AllAlbums' + size = self.readSint32(msgin, '%s_len' % id) + for i in range(0, size): + self.read_album(id, msgin) + elif type == 1: # UpdateAlbum + id += '_UpdateAlbum' + self.read_album(id, msgin) + else: # type == 2: # UpdateThema + id += '_UpdateThema' + self.readUint32(msgin, '%s_AlbumName' % (id)) + self.read_thema(id, msgin) + +class impulseInitInventory(ImpulseBase): + def __init__(self): + super().__init__() + + def read(self, name, msgin, world): + # khanat-opennel-code/code/ryzom/client/src/net_manager.cpp void updateInventoryFromStream (NLMISC::CBitMemStream &impulse, const CInventoryCategoryTemplate *templ, bool notifyItemSheetChanges) + # khanat-opennel-code/code/ryzom/server/src/entities_game_service/inventory_updater.cpp void CInventoryUpdaterForCharacter::sendAllUpdates( const NLMISC::CEntityId& destEntityId ) + id = "InitInventory" + logging.getLogger(LOGGER).debug("read") + self.name = name.replace(':', '_') + #self.readSint32(msgin, '%s_pos' % id) + self.readUint32(msgin, '%s_serverTick' % id) + for invId in range(0, Enum.TInventoryId.NbInventoryIds): + hasContent = self.readBool(msgin, '%s_%d_hasContent' % (id, invId)) + if hasContent == False: + continue; + nbChanges = self.readSerial(msgin, 3, '%s_%d_nbChanges' % (id, invId)) # INVENTORIES::LowNumberBits = 3 + if nbChanges == 7: # == INVENTORIES::LowNumberBound = 7 + nbChanges = self.readSerial(msgin, 32, '%s_%d_nbChanges_next' % (id, invId)) # INVENTORIES::LowNumberBits = 3 + for itu in range(0, nbChanges): + iuInfoVersion = self.readSerial(msgin, 1, '%s_%d_%d_itu_iuInfoVersion' % (id, invId, itu)) + if iuInfoVersion == 1: + _ = self.readSerial(msgin, 10, '%s_%d_%d_itu_iuInfoVersion_slotIndex' % (id, invId, itu)) # ICInventoryCategoryTemplate::SlotBitSize = 10 + #self.param.setdefault('%s_%d_infoVersion' % (id, i), msgin.readUint8('%s_%d_infoVersion' % (id, i))) + else: + iuAll = self.readSerial(msgin, 1, '%s_%d_%d_iuAll' % (id, invId, itu)) + if iuAll == 1: + _ = self.readSerial(msgin, 10, '%s_%d_%d_iuAll_slotIndex' % (id, invId, itu)) # ICInventoryCategoryTemplate::SlotBitSize = 10 + for ii in range(0, 6): + #ItemSlot = msgin.readSerial( DataBitSize[ii], '%s_%d_ItemSlot_%s' % (id, i, ItemPropStr[ii])) + self.readSerial(msgin, DataBitSize[ii], '%s_%d_%d_iuAll_ItemProp_%s' % (id, invId, itu, ItemPropStr[ii])) + for ii in range(6, Enum.TItemPropId.NbItemPropId): + b = self.readBool(msgin, '%s_%d_%d_iuAll_ItemProp_%s_compressed' %(id, invId, itu, ItemPropStr[ii])) + if b: + pass + else: + #ItemProp = msgin.readSerial(DataBitSize(ii), '%s_%d_ItemSlot_%d_ItemProp' %(id , i, ii)) + self.readSerial(msgin, DataBitSize[ii], '%s_%d_%d_iuAll_ItemProp_%s_ItemProp' %(id, invId, itu, ItemPropStr[ii])) + else: + iuOneProp = self.readSerial(msgin, 1, '%s_%d_%d_iuOneProp' % (id, invId, itu)) + if iuOneProp == 1: + # bms.serial( _SlotIndex, CInventoryCategoryTemplate::SlotBitSize ); 10 + _ = self.readSerial(msgin, 10, '%s_%d_%d_iuOneProp_SlotIndex' %(id, invId, itu)) + ItemPropIdUint32 = self.readSerial(msgin, 4, '%s_%d_%d_iuOneProp_ItemPropId' %(id, invId, itu)) + _ = self.readSerial(msgin, DataBitSize[ItemPropIdUint32], '%s_%d_%d_iuOneProp_ItemPropValue' %(id, invId, itu)) + # bms.serial( _OneProp ); + # bms.serial((uint32&)ItemPropIdUint32, NbBitsForItemPropId); + # bms.serial((uint32&)ItemPropValue, CItemSlot::DataBitSize[ItemPropId]); + else: # iuReset + _ = 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 DecodeImpulseSimple: def __init__(self): ''' @@ -377,6 +585,8 @@ class DecodeImpulseSimple: self.GenericMsgHeaderMngr.setdefault( "CONNECTION:USER_CHAR", ImpulseConnectionUserChar ) self.GenericMsgHeaderMngr.setdefault( "CONNECTION:VALID_NAME", ImpulseConnectionValidName ) self.GenericMsgHeaderMngr.setdefault( "DEBUG:PING", ImpulseDebugPing ) + self.GenericMsgHeaderMngr.setdefault( "DEATH:RESPAWN_POINT", impulseDeathRespawnPoint) + self.GenericMsgHeaderMngr.setdefault( "GUILD:UPDATE_PLAYER_TITLE", impulseGuildUpdatePlayerTitle) self.GenericMsgHeaderMngr.setdefault( "GUILD:USE_FEMALE_TITLES", ImpulseGuildFemaleTitles ) self.GenericMsgHeaderMngr.setdefault( "NPC_ICON:SET_DESC", ImpulseNpsIconSetDesc ) self.GenericMsgHeaderMngr.setdefault( "PHRASE:DOWNLOAD", ImpulsePhraseDownload ) @@ -386,6 +596,8 @@ class DecodeImpulseSimple: self.GenericMsgHeaderMngr.setdefault( "STRING_MANAGER:PHRASE_SEND", ImpulseSringManagerPhraseSend ) self.GenericMsgHeaderMngr.setdefault( "STRING_MANAGER:STRING_RESP", ImpulseSringManagerStringResp ) self.GenericMsgHeaderMngr.setdefault( "STRING_MANAGER:STRING_RQ", ImpulseSringManagerStringRq ) + self.GenericMsgHeaderMngr.setdefault( "ENCYCLOPEDIA:INIT", impulseEncyclopediaInit ) + self.GenericMsgHeaderMngr.setdefault( "DB_INIT:INV", impulseInitInventory) def execute(self, msgin, world, references = [], name=""): ''' @@ -394,7 +606,7 @@ class DecodeImpulseSimple: khanat-opennel-code/code/ryzom/common/src/game_share/generic_xml_msg_mngr.h:431 CNode *select(NLMISC::CBitMemStream &strm) uint32 index = 0; -q uint NbBits; + uint NbBits; strm.serialAndLog2(index, node->NbBits); ''' @@ -432,7 +644,21 @@ q uint NbBits; for reference in references: impulse.add_reference(reference) impulse.add_value("Message", msgin.extractAllData()) - return impulse + # check we decode all message + nbBitNotRead = msgin.needRead() + if nbBitNotRead == 0: + return impulse + elif nbBitNotRead < 8: + 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]" % (fullname, msgin.showAllData(), nbBitNotRead)) + raise "Message not full decoded" + return None else: #logging.getLogger(LOGGER).debug("Non trouve") for ele in head: @@ -440,11 +666,10 @@ q uint NbBits; head = ele break if head != ele: - logging.getLogger(LOGGER).error("Impossible to found %s" % fullname ) - logging.getLogger(LOGGER).debug("MessageXML decoded: %s" % msgin.showAllData() ) + logging.getLogger(LOGGER).error("MessageXML not decoded: [%s] %s" % (fullname, msgin.showAllData() )) return None # End While - logging.getLogger(LOGGER).debug("MessageXML decoded: %s" % msgin.showAllData() ) + logging.getLogger(LOGGER).error("MessageXML not decoded: [%s] %s" % (fullname, msgin.showAllData() )) return None def loadMsg(self, msgXml):