#!/usr/bin/python3 # -*- coding: utf-8 -*- # # module Impulse # # Copyright (C) 2019 AleaJactaEst # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import logging from tools import getPowerOf2 from tools import BitStream from tools import Enum from tools import DecodeDatabase # 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' class ImpulseNoElement(Exception): pass class ImpulseBase: def __init__(self): self.name = "" self.id = "" self.param = {} #self.Reference = [] self.notice = {} self.headernotice = None def set_header_notice(self, header): self.headernotice = header def append_notice(self, data): for key in data: #print("Add", key) self.notice.setdefault(key, data [key]) def add_notice(self, id, value): if not self.headernotice: return ref = { self.headernotice + '/' +id: value} self.append_notice(ref) def get_notice(self): return self.notice def set_name(self, name): self.name = name.replace(':', '_') def get_name(self): return self.name def add_reference(self, ref): #self.Reference.append(ref) self.param.setdefault('Reference', []) self.param['Reference'].append(ref) def get_reference(self): return self.param['Reference'] def get_parameter(self): return self.param def add_parameter(self, key, value): self.param.setdefault(key, []) self.param[key].append(value) def add_value(self, key, value): self.param.setdefault(key, "") self.param[key] = value def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).error("Not define") def readBool(self, msgin, id): value = msgin.readBool(id) self.param.setdefault(id, value) self.add_notice(id, value) return value def readUint8(self, msgin, id): value = msgin.readUint8(id) self.param.setdefault(id, value) self.add_notice(id, value) return value def readSint8(self, msgin, id): value = msgin.readSint8(id) self.param.setdefault(id, value) self.add_notice(id, value) return value def readUint16(self, msgin, id): value = msgin.readUint16(id) self.param.setdefault(id, value) self.add_notice(id, value) return value def readSint16(self, msgin, id): value = msgin.readSint16(id) self.param.setdefault(id, value) self.add_notice(id, value) return value def readUint32(self, msgin, id): value = msgin.readUint32(id) self.param.setdefault(id, value) self.add_notice(id, value) return value def readSint32(self, msgin, id): value = msgin.readSint32(id) self.param.setdefault(id, value) self.add_notice(id, value) return value def readUint64(self, msgin, id): value = msgin.readUint64(id) self.param.setdefault(id, value) self.add_notice(id, value) return value def readSint64(self, msgin, id): value = msgin.readSint64(id) self.param.setdefault(id, value) self.add_notice(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) self.add_notice(id, value) return value def readSerialEnum(self, msgin, nbBits, id, typeEnum): if nbBits == 1: value = msgin.readSerial(nbBits, id, typeName="bool/1 bit", decode=False) else: value = msgin.readSerial(nbBits, id, typeName="%d bits" % nbBits, decode=False) nameValue = Enum.GetNameIntEnum(typeEnum, value) if nbBits == 1: value = msgin.readSerial(nbBits, id, typeName="bool/1 bit", commentValue=" " + typeEnum.__name__ + "." + nameValue) else: value = msgin.readSerial(nbBits, id, typeName="%d bits" % nbBits, commentValue=" " + typeEnum.__name__ + "." + nameValue) self.param.setdefault(id, value) self.param.setdefault(id + "_name", typeEnum.__name__ + "." + nameValue) self.add_notice(id, value) return value def readUString(self, msgin, id): value = msgin.readUString(id) self.param.setdefault(id, value) self.add_notice(id, value) return value def readUtf8String(self, msgin, id): value = msgin.readUtf8String(id) self.param.setdefault(id, value) self.add_notice(id, value) return value def readString(self, msgin, id): value = msgin.readString(id) self.param.setdefault(id, value) self.add_notice(id, value) return value def readFloat(self, msgin, id): value = msgin.readFloat(id) self.param.setdefault(id, value) self.add_notice(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) self.add_notice(id, value) return value def readDatabases(self, world, decodeDatabase): return None class ImpulseBotchatSetFilters(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/BOTCHAT/SET_FILTERS') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_',) 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): def __init__(self): super().__init__() self.set_header_notice('MsgXML/CONNECTION/ASK_NAME') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') self.readUString(msgin, 'Name') self.readUint32(msgin, 'HomeSessionId') class ImpulseConnectionCreateChar(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/CCONNECTION/CREATE_CHAR') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') 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): def __init__(self): super().__init__() self.set_header_notice('MsgXML/CONNECTION/READY') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') self.readString(msgin, 'LanguageCode') class ImpulseConnectionSelectChar(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/CONNECTION/SELECT_CHAR') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') self.readUint8(msgin, 'SelectCharMsg') class ImpulseConnectionUserChar(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/CONNECTION/USER_CHAR') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') 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): def __init__(self): super().__init__() self.set_header_notice('MsgXML/CONNECTION/SHARD_ID') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') self.readUint32(msgin, 'shardId') self.readString(msgin, 'webHost') class ImpulseConnectionValidName(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/CONNECTION/VALID_NAME') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') self.readUint8(msgin, 'valide') return {} class ImpulseDebugPing(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/DEBUG/PING') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') self.readUint32(msgin, 'localTime') class ImpulseGuildFemaleTitles(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/GUILD/USE_FEMALE_TITLES') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') self.readSerial(msgin, 1, 'UseFemaleTitles') class ImpulseNpcIconSetDesc(ImpulseBase): def __init__(self): super().__init__() self.data = BitStream.BitStream() self.set_header_notice('MsgXML/NPC_ICON/SET_DESC') def read(self, name, msgin, world, databaseXml): ''' khanat-opennel-code/code/ryzom/server/src/entities_game_service/player_manager/character.cpp:20976 void CCharacter::sendNpcMissionGiverIconDesc( const std::vector& npcKeys ) ''' logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') nb8 = self.readUint8(msgin, 'nb8') self.data.pushUint8(nb8) for i in range(0, nb8): npcAlias = self.readUint32(msgin, 'NpcIconSetDesc_%d_npcAlias' % nb8) self.data.pushUint32(npcAlias) state = self.readUint32(msgin, 'NpcIconSetDesc_%d_state' % nb8) self.data.pushUint32(state) def readDatabases(self, world, decodeDatabase): return decodeDatabase.execute(self.data, world) class ImpulsePhraseDownload(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/PHRASE/DOWNLOAD') def readSerialPhrase(self, msgin, id): self.readUtf8String(msgin, id) size = self.readSint32(msgin, id + '_len') for i in range(0, size): self.readUint16(msgin, '%s_compBricks_%d' % (id, i)) def readSerialPhrases(self, msgin, id): """ khanat-opennel-code/code/ryzom/server/src/entities_game_service/player_manager/character.cpp:13586 void CCharacter::sendPhrasesToClient() 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 = 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, '%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 = self.readSint32(msgin, id + '_len') for i in range(0, size): 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, databaseXml): """ khanat-opennel-code/code/ryzom/server/src/entities_game_service/player_manager/character.cpp:13586 void CCharacter::sendPhrasesToClient() """ logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') # 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 class ImpulsePosition(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/POSITION') def read(self, name, msgin, world, databaseXml): # khanat-opennel-code/code/ryzom/server/src/gpm_service/client_messages.cpp void cbClientPosition( CMessage& msgin, const string &serviceName, NLNET::TServiceId serviceId ) logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') #self.readBool(msgin, '') self.readSint32(msgin, 'X') self.readSint32(msgin, 'Y') self.readSint32(msgin, 'Z') self.readFloat(msgin, 'Heading') class ImpulseSringDynString(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/STRING/DYN_STRING') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') self.readUint32(msgin, 'phraseId') class ImpulseSringManagerReloadCache(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/STRING_MANAGER/RELOAD_CACHE') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') self.readUint32(msgin, 'timestamp') class ImpulseSringManagerPhraseSend(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/STRING_MANAGER/PHRASE_SEND') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') 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): super().__init__() self.set_header_notice('MsgXML/STRING_MANAGER/STRING_RESP') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') self.readUint32(msgin, 'stringId') self.readUtf8String(msgin, 'strUtf8') class ImpulseSringManagerStringRq(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/STRING_MANAGER/STRING_RQ') def read(self, name, msgin, world, databaseXml): logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') self.readUint32(msgin, 'stringId') class impulseGuildUpdatePlayerTitle(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/GUILD/UPDATE_PLAYER_TITLE') def read(self, name, msgin, world, databaseXml): 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__() self.set_header_notice('MsgXML/DEATH/RESPAWN_POINT') def read(self, name, msgin, world, databaseXml): 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__() self.set_header_notice('MsgXML/ENCYCLOPEDIA/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, databaseXml): 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__() self.set_header_notice('MsgXML/DB_INIT/INV') def read(self, name, msgin, world, databaseXml): # 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 ImpulseConnectionUserChars(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/CONNECTION/USER_CHARS') def read(self, name, msgin, world, databaseXml): # 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__() self.set_header_notice('MsgXML/DB_INIT/PLR') def read(self, name, msgin, world, databaseXml): # 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) data = {} 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): # _ = self.readUint32(msgin, '%s_property' % id) for i in range(0, propertyCount): logging.getLogger(LOGGER).debug("read i:%d" % i) logging.getLogger(LOGGER).debug("#" * 80) state, data = databaseXml.execute(msgin, world) if state: # DecodeDatabase.print_dico(data) self.append_notice(data) # for key, value in data: # ret.setdefault(key, value) #raise "TODO" if msgin.needRead() > 5: logging.getLogger(LOGGER).debug(msgin.showAllData()) logging.getLogger(LOGGER).debug(msgin.showAllData()) #raise "TODO" #self.append_notice(data) class ImpulseConnectionDeleteChar(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/CONNECTION/DELETE_CHAR') def read(self, name, msgin, world, databaseXml): id = "ConnectionDeleteChar" logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') self.readUint8(msgin, '%s_slot' % id) class impulseTeamContactInit(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/TEAM/CONTACT_INIT') def read(self, name, msgin, world, databaseXml): id = "TeamContactInit" logging.getLogger(LOGGER).debug("read") self.name = name.replace(':', '_') friend_string_ids_len = self.readUint32(msgin, '%s_friend_string_ids_len' % id) for i in range(0, friend_string_ids_len): _ = self.readUint32(msgin, '%s_friend_string_ids_%d' % (id, i)) nb_state = self.readUint32(msgin, '%s_nb_state' % id) for i in range(0, nb_state): _ = self.readUint32(msgin, '%s_friend_online_status_%d' % (id, i)) ignore_list_len = self.readUint32(msgin, '%s_ignore_list_len' % id) for i in range(0, ignore_list_len): _ = self.readUString(msgin, '%s_ignore_list_%d' % (id, i)) class impulseNpcIconGetDesc(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/NPC_ICON/GET_DESC') def read(self, name, msgin, world, databaseXml): # khanat-opennel-code/code/ryzom/server/src/frontend_service/id_impulsions.cpp void cbImpulsionGetNpcIconDesc( CEntityId& sender, CBitMemStream &bms, TGameCycle gamecycle, uint16 serviceId ) id = "ClientNpcIcon" logging.getLogger(LOGGER).debug("read %s" % id) self.name = name.replace(':', '_') nb8 = self.readUint8(msgin, '%s_nb8' % id) for i in range(0, nb8): _ = self.readUint32(msgin, '%s_NPCIconCacheKey_%d' % (id, i)) class impulseUserBars(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/USER/BARS') def read(self, name, msgin, world, databaseXml): # khanat-opennel-code/code/ryzom/server/src/entities_game_service/player_manager/character.cpp void CCharacter::barUpdate() id = "UserBars" logging.getLogger(LOGGER).debug("read %s" % id) self.name = name.replace(':', '_') _ = self.readUint8(msgin, '%s_barsenttoplayermsgnumber' % id) _ = self.readSint32(msgin, '%s_oldchascore1barsenttoplayer' % id) _ = self.readSint32(msgin, '%s_oldchascore2barsenttoplayer' % id) _ = self.readSint32(msgin, '%s_oldchascore3barsenttoplayer' % id) _ = self.readSint32(msgin, '%s_oldchascore4barsenttoplayer' % id) class impulseDbGroupInitBank(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/DB_GROUP/INIT_BANK') def read(self, name, msgin, world, databaseXml): # khanat/khanat-opennel-code/code/ryzom/client/src/net_manager.cpp void impulseDatabaseInitBank(NLMISC::CBitMemStream &impulse) id = "DbGroupInitBank" logging.getLogger(LOGGER).debug("read %s" % id) self.name = name.replace(':', '_') _ = self.readUint32(msgin, '%s_serverTick' % id) bank = self.readSerialEnum(msgin, Enum.TCDBBank.NB_BITS_FOR_CDBBANK, '%s_bank' % id, Enum.TCDBBank) propertyCount = self.readUint16(msgin, '%s_propertyCount' % id) for i in range(0, propertyCount): raise "TODO" class impulseDatabaseUpdatePlayer(ImpulseBase): def __init__(self): super().__init__() self.set_header_notice('MsgXML/DB_UPD_PLR') def read(self, name, msgin, world, databaseXml): # khanat/khanat-opennel-code/code/ryzom/client/src/net_manager.cpp void impulseDatabaseUpdatePlayer(NLMISC::CBitMemStream &impulse) data = {} id = "DbUpdPlr" logging.getLogger(LOGGER).debug("read %s" % id) self.name = name.replace(':', '_') _ = self.readUint32(msgin, '%s_serverTick' % id) propertyCount = self.readUint16(msgin, '%s_propertyCount' % id) for i in range(0, propertyCount): state, data = databaseXml.execute(msgin, world) if state: DecodeDatabase.print_dico(data) # for key, value in data: # ret.setdefault(key, value) #raise "TODO" if msgin.needRead() > 5: logging.getLogger(LOGGER).debug(msgin.showAllData()) #raise "TODO" #raise "TODO" self.append_notice(data) class DecodeImpulseSimple: def __init__(self): ''' khanat-opennel-code/code/ryzom/client/src/net_manager.cpp # void initializeNetwork() ''' self.msgXml = None self.databaseXml = None self.GenericMsgHeaderMngr = {} self.initializeNetwork() def initializeNetwork(self): # Send by client self.GenericMsgHeaderMngr.setdefault( "BOTCHAT:SET_FILTERS", ImpulseBotchatSetFilters ) self.GenericMsgHeaderMngr.setdefault( "CONNECTION:ASK_NAME", ImpulseConnectionAskName ) self.GenericMsgHeaderMngr.setdefault( "CONNECTION:CREATE_CHAR", ImpulseConnectionCreateChar ) self.GenericMsgHeaderMngr.setdefault( "CONNECTION:DELETE_CHAR", ImpulseConnectionDeleteChar ) self.GenericMsgHeaderMngr.setdefault( "CONNECTION:READY", ImpulseConnectionReady ) 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) self.GenericMsgHeaderMngr.setdefault( "GUILD:UPDATE_PLAYER_TITLE", impulseGuildUpdatePlayerTitle) self.GenericMsgHeaderMngr.setdefault( "GUILD:USE_FEMALE_TITLES", ImpulseGuildFemaleTitles ) self.GenericMsgHeaderMngr.setdefault( "NPC_ICON:SET_DESC", ImpulseNpcIconSetDesc ) self.GenericMsgHeaderMngr.setdefault( "PHRASE:DOWNLOAD", ImpulsePhraseDownload ) self.GenericMsgHeaderMngr.setdefault( "POSITION", ImpulsePosition ) self.GenericMsgHeaderMngr.setdefault( "STRING:DYN_STRING", ImpulseSringDynString ) self.GenericMsgHeaderMngr.setdefault( "STRING_MANAGER:RELOAD_CACHE", ImpulseSringManagerReloadCache ) 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) self.GenericMsgHeaderMngr.setdefault( "DB_INIT:PLR", impulseDatabaseInitPlayer) self.GenericMsgHeaderMngr.setdefault( "TEAM:CONTACT_INIT", impulseTeamContactInit) self.GenericMsgHeaderMngr.setdefault( "NPC_ICON:GET_DESC", impulseNpcIconGetDesc) self.GenericMsgHeaderMngr.setdefault( "USER:BARS", impulseUserBars) self.GenericMsgHeaderMngr.setdefault( "DB_GROUP:INIT_BANK", impulseDbGroupInitBank) self.GenericMsgHeaderMngr.setdefault( "DB_UPD_PLR", impulseDatabaseUpdatePlayer) def execute(self, msgin, world, references = [], name=""): ''' khanat-opennel-code/code/ryzom/client/src/net_manager.cpp:3746 void impulseCallBack(NLMISC::CBitMemStream &impulse, sint32 packet, void *arg) khanat-opennel-code/code/ryzom/common/src/game_share/generic_xml_msg_mngr.cpp:121 void CGenericXmlMsgHeaderManager::execute(CBitMemStream &strm) khanat-opennel-code/code/ryzom/common/src/game_share/generic_xml_msg_mngr.h:431 CNode *select(NLMISC::CBitMemStream &strm) uint32 index = 0; uint NbBits; strm.serialAndLog2(index, node->NbBits); ''' logging.getLogger(LOGGER).debug("execute") head = self.msgXml listpath = [] while True: nbBit = getPowerOf2.getPowerOf2(len(head)) #logging.getLogger(LOGGER).error("nbBit : %d " % nbBit) #for child in head: # print(child.tag, child.attrib) try: id = msgin.readSerial(nbBit, name='MsgXML', typeName='Number', emulate=True) except BitStream.OverflowError: raise ImpulseNoElement if id is None: raise ImpulseNoElement try: ele = head[id] except IndexError as e: logging.getLogger(LOGGER).error("Error to decode message: %s" % msgin.showAllData() ) raise e command = ele.attrib['name'] listpath.append(command) fullname = ':'.join(listpath) id = msgin.readSerial(nbBit, name='MsgXML', typeName='XML <' + command + '>') if fullname in self.GenericMsgHeaderMngr: logging.getLogger(LOGGER).debug("Found : %s" % fullname) impulse = self.GenericMsgHeaderMngr[fullname]() impulse.read(fullname, msgin, world, self.databaseXml) logging.getLogger(LOGGER).debug("MessageXML decoded: %s" % msgin.showAllData() ) impulse.add_value("command", fullname) for reference in references: impulse.add_reference(reference) impulse.add_value("Message", msgin.extractAllData()) # 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, not read:%d]" % (fullname, msgin.showAllData(), nbBitNotRead, a)) elif nbBitNotRead < 32: a = msgin.readSerial(nbBitNotRead, decode=False) if a == 0: return impulse 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)) return None else: #logging.getLogger(LOGGER).debug("Non trouve") for ele in head: if ele.attrib['name'] == command: head = ele break if head != ele: logging.getLogger(LOGGER).error("MessageXML not decoded: [%s] %s" % (fullname, msgin.showAllData() )) return None # End While logging.getLogger(LOGGER).error("MessageXML not decoded: [%s] %s" % (fullname, msgin.showAllData() )) return None def loadMsg(self, msgXml): logging.getLogger(LOGGER).debug("msgXml") self.msgXml = msgXml def loadDatabase(self, databaseXml): self.databaseXml = databaseXml