From 0b9c1367182d1d28019cc47e3869b679a5798932 Mon Sep 17 00:00:00 2001 From: AleaJactaEst Date: Fri, 14 Jun 2019 00:07:41 +0200 Subject: [PATCH] decode message CONNECTION:USER_CHARS --- client.py | 203 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 144 insertions(+), 59 deletions(-) diff --git a/client.py b/client.py index 55108cf..0d107b0 100755 --- a/client.py +++ b/client.py @@ -185,14 +185,13 @@ class BitStream(): # ------------------------------------ def readSerial(self, nbits, name="", decode=True, typeName='', emulate=False): + v1 = self._read if nbits == 0: return elif nbits > 32: raise "Out of range" if self._read + nbits > self._pos: raise "Stream Overflow" - if decode and not emulate: - self._groupRead.append((self._read, self._read+nbits, name, typeName)) if emulate: oldRead = self._read value = 0 @@ -208,10 +207,14 @@ class BitStream(): self._read += nbits if emulate: self._read = oldRead + if decode and not emulate: + self._groupRead.append((v1, v1+nbits, name, typeName, value)) return value def readBool(self, name): - v = self.readSerial(1, name=name, typeName='Bool') + v1 = self._read + v = self.readSerial(1, name=name, decode=False, typeName='Bool') + self._groupRead.append((v1, v1+1, name, 'Bool', 'True' if v != 0 else 'False')) if v != 0: return True else: @@ -225,8 +228,8 @@ class BitStream(): v = self.readSerial(32, name=name, decode=decode, typeName='Sint32') return c_int32(v).value - def readUint16(self, name): - v = self.readSerial(16, name=name, typeName='Uint16') + def readUint16(self, name, decode=True): + v = self.readSerial(16, name=name, decode=decode, typeName='Uint16') return v def readSint16(self, name): @@ -242,33 +245,38 @@ class BitStream(): return c_int8(v).value def readUint64(self, name): - self._groupRead.append((self._read, self._read+64, name, 'Uint64')) + v1 = self._read v = self.readSerial(32, decode=False) v1 = self.readSerial(32, decode=False) v2 = v | (v1 << 32) + self._groupRead.append((v1, v1+64, name, 'Uint64', v2)) return v2 def readSint64(self, name): - self._groupRead.append((self._read, self._read+64, name, 'Sint64')) + v1 = self._read v = self.readSerial(32, decode=False) v1 = self.readSerial(32, decode=False) v2 = v | (v1 << 32) + self._groupRead.append((v1, v1+64, name, 'Sint64', c_int64(v2).value)) return c_int64(v2).value def readFloat(self, name): - v = self.readSerial(32, name=name, typeName='Float') + v1 = self._read + v = self.readSerial(32, name=name, decode=False, typeName='Float') v1 = struct.pack('I', v) v2 = struct.unpack(' self._pos: raise ValueError if v1 < v2: - self._groupRead.append((v1, v2, name + ':string', 'String')) + self._groupRead.append((v1, v2, name + ':string', 'String', tmp)) + return tmp + + def readUString(self, name): + tmp = '' + _size = self.readUint32(name + ':size', decode=True) + v1 = self._read + while _size > 0: + x = self.readUint16(name='', decode=False) + tmp += chr(x) + _size -= 1 + v2 = self._read + if v2 > self._pos: + raise ValueError + if v1 < v2: + self._groupRead.append((v1, v2, name + ':ustring', 'UString', tmp)) return tmp def readArrayUint8(self, size, name): @@ -296,7 +319,7 @@ class BitStream(): for i in range(0, size): ret.append(self.readUint8('', decode=False)) v2 = self._read - self._groupRead.append((v1, v2, name, 'ArrayUint8')) + self._groupRead.append((v1, v2, name, 'ArrayUint8', '')) return ret def readBitStreamUint8(self, size, name): @@ -305,7 +328,7 @@ class BitStream(): for i in range(0, size): ret.pushUint8(self.readUint8('', decode=False)) v2 = self._read - self._groupRead.append((v1, v2, name, 'StreamUint8')) + self._groupRead.append((v1, v2, name, 'StreamUint8', '')) return ret def readCont(self, name): @@ -315,7 +338,7 @@ class BitStream(): for i in range(0, size): ret.pushBool(self.readSerial(1,name = '', decode=False)) v2 = self._read - self._groupRead.append((v1, v2, name + ':data', 'readCont')) + self._groupRead.append((v1, v2, name + ':data', 'readCont', '')) return size, ret # ------------------------------------ @@ -395,8 +418,8 @@ class BitStream(): ret2 = "" last = 0 - for x, y, name, typeName in self._groupRead: - ret2 += "[<" + str(x) + ':' + str(y-1) + "> " + str(name) + ' (' + typeName + ') = ' + ret[x:y] + "]" + for x, y, name, typeName, value in self._groupRead: + ret2 += "[<" + str(x) + ':' + str(y-1) + "> " + str(name) + ' (' + typeName + ') : ' + ret[x:y] + ' => ' + str(value) + "]" last = y if last < self._pos: ret2 += "{" + ret[last:] + "}" @@ -1414,7 +1437,7 @@ class ECharacterTitle(IntEnum): Title00077 = 225 # Title00078 = 226 # Title00079 = 227 # // Wayfarer - WIND = Title00079 # // Title for player come from old Windermmer community + WIND = Title00079 # // Title for player come from old Windermmer community FBT = 228 # BeginGmTitle = 229 # # SGM = BeginGmTitle # @@ -1435,17 +1458,17 @@ class SPropVisualA(): ''' khanat-opennel-code/code/ryzom/common/src/game_share/player_visual_properties.h # struct SPropVisualA ''' - self.Sex = False #: 1; // max: 2 current: 2 - self.JacketModel = 0 #: 8; // max: 256 current: 93 - self.JacketColor = 0 #: 3; // max: 8 current: 8 - self.TrouserModel = 0 #: 8; // max: 256 current: 104 - self.TrouserColor = 0 #: 3; // max: 8 current: 8 - self.WeaponRightHand = 0 #: 10; // max: 1024 current: 457 - self.WeaponLeftHand = 0 #: 8; // max: 256 current: 63 - self.ArmModel = 0 #: 8; // max: 256 current: 94 - self.ArmColor = 0 #: 3; // max: 8 current: 8 - self.HatModel = 0 #: 9; // max: 512 current: 192 - self.HatColor = 0 #: 3; // max: 8 current: 8 + self.Sex = False #: 1; // max: 2 current: 2 + self.JacketModel = 0 #: 8; // max: 256 current: 93 + self.JacketColor = 0 #: 3; // max: 8 current: 8 + self.TrouserModel = 0 #: 8; // max: 256 current: 104 + self.TrouserColor = 0 #: 3; // max: 8 current: 8 + self.WeaponRightHand = 0 #: 10; // max: 1024 current: 457 + self.WeaponLeftHand = 0 #: 8; // max: 256 current: 63 + self.ArmModel = 0 #: 8; // max: 256 current: 94 + self.ArmColor = 0 #: 3; // max: 8 current: 8 + self.HatModel = 0 #: 9; // max: 512 current: 192 + self.HatColor = 0 #: 3; // max: 8 current: 8 def read(self, msgin): self.Sex = msgin.readBool('Sex') @@ -1464,11 +1487,11 @@ class SPropVisualA(): class SPropVisualB(): def __init__(self): self.Name = "" #: 16; - self.HandsModel = 0 #: 9; // max: 512 current: 90 - self.HandsColor = 0 #: 3; // max: 8 current: 8 - self.FeetModel = 0 #: 9; // max: 512 current: 94 - self.FeetColor = 0 #: 3; // max: 8 current: 8 - self.RTrail = 0 #: 4; + self.HandsModel = 0 #: 9; // max: 512 current: 90 + self.HandsColor = 0 #: 3; // max: 8 current: 8 + self.FeetModel = 0 #: 9; // max: 512 current: 94 + self.FeetColor = 0 #: 3; // max: 8 current: 8 + self.RTrail = 0 #: 4; self.LTrail = 0 #: 3; self.NotUsed = 0 # 17 : # not used -> just to complete 64 bit def read(self, msgin): @@ -1484,21 +1507,21 @@ class SPropVisualB(): class SPropVisualC(): def __init__(self): - self.MorphTarget1 = 0 # : 3; // max: 8 current: 8 - self.MorphTarget2 = 0 # : 3; // max: 8 current: 8 - self.MorphTarget3 = 0 # : 3; // max: 8 current: 8 - self.MorphTarget4 = 0 # : 3; // max: 8 current: 8 - self.MorphTarget5 = 0 # : 3; // max: 8 current: 8 - self.MorphTarget6 = 0 # : 3; // max: 8 current: 8 - self.MorphTarget7 = 0 # : 3; // max: 8 current: 8 - self.MorphTarget8 = 0 # : 3; // max: 8 current: 8 - self.EyesColor = 0 # : 3; // max: 8 current: 8 - self.Tattoo = 0 # : 7; // max: 128 current: 64 - self.CharacterHeight = 0 # : 4; // max: 16 current: 16 - self.TorsoWidth = 0 # : 4; // max: 16 current: 16 - self.ArmsWidth = 0 # : 4; // max: 16 current: 16 - self.LegsWidth = 0 # : 4; // max: 16 current: 16 - self.BreastSize = 0 # : 4; // max: 16 current: 16 + self.MorphTarget1 = 0 # : 3; // max: 8 current: 8 + self.MorphTarget2 = 0 # : 3; // max: 8 current: 8 + self.MorphTarget3 = 0 # : 3; // max: 8 current: 8 + self.MorphTarget4 = 0 # : 3; // max: 8 current: 8 + self.MorphTarget5 = 0 # : 3; // max: 8 current: 8 + self.MorphTarget6 = 0 # : 3; // max: 8 current: 8 + self.MorphTarget7 = 0 # : 3; // max: 8 current: 8 + self.MorphTarget8 = 0 # : 3; // max: 8 current: 8 + self.EyesColor = 0 # : 3; // max: 8 current: 8 + self.Tattoo = 0 # : 7; // max: 128 current: 64 + self.CharacterHeight = 0 # : 4; // max: 16 current: 16 + self.TorsoWidth = 0 # : 4; // max: 16 current: 16 + self.ArmsWidth = 0 # : 4; // max: 16 current: 16 + self.LegsWidth = 0 # : 4; // max: 16 current: 16 + self.BreastSize = 0 # : 4; // max: 16 current: 16 self.NotUsed = 0 # 10 : # not used -> just to complete 64 bit def read(self, msgin): self.MorphTarget1 = msgin.readSerial(3, 'MorphTarget1') @@ -1555,11 +1578,37 @@ class CCharacterSummary(): self.HasEditSession = msgin.readBool('HasEditSession') self.InNewbieland = msgin.readBool('InNewbieland') -# f.serial (CharacterSlot); -# f.serial (InRingSession); -# f.serial (HasEditSession); -# if (serialNB) -# f.serial (InNewbieland); + +class CSessionId(): + def __init__(self): + self.id = 0 + def read(self, msgin): + self.id = msgin.readUint32('id') + + +class CMainlandSummary(): + def __init__(self): + self.Id = CSessionId() + self.Name = "" + self.Description = "" + self.LanguageCode = "" + self.Online = False + def read(self, msgin): + ''' + khanat-opennel-code/code/ryzom/common/src/game_share/mainland_summary.h # void serial(NLMISC::IStream &f) + ''' + self.Id.read(msgin) + self.Name = msgin.readUString('Name') + self.Description = msgin.readUString('Description') + self.LanguageCode = msgin.readString('LanguageCode') + self.Online = msgin.readBool('Online') + + +class CShardName(): + def __init__(self, SessionId, DisplayName, ShortName): + self.SessionId = SessionId + self.DisplayName = DisplayName + self.ShortName = ShortName class World(): @@ -1570,6 +1619,10 @@ class World(): self.ServerPeopleActive = 255 self.ServerCareerActive = 255 self.CharacterSummaries = [] + self.Mainlands = [] + self.CShardNames = [] + self.UserPrivileges = '' + self.FreeTrial = False def addGenericMultiPartTemp(self, id): self.GenericMultiPartTemp.setdefault(id, CGenericMultiPartTemp(self.log)) @@ -2263,6 +2316,20 @@ class DecodeImpulse(): self.GenericMsgHeaderMngr = {} self.initializeNetwork() self.world = world + def updatePatcherPriorityBasedOnCharacters(self): + self.log.debug('Load character') + hasMainlandChar = False + for ele in self.world.CharacterSummaries: + if ele.Name == "": + continue + if not ele.InNewbieland: + hasMainlandChar = True + break + # requestDownloadThreadPriority(hasMainlandChar ? BGDownloader::ThreadPriority_Normal : BGDownloader::ThreadPriority_Low, false); + # khanat-opennel-code/code/ryzom/client/src/bg_downloader_access.cpp # void CBGDownloaderAccess::requestDownloadThreadPriority(BGDownloader::TThreadPriority newPriority, bool freezeUI) + msgout = BitStream() + self.log.debug("TODO") + def impulseDatabaseUpdatePlayer(self, msgin): self.log.debug("TODO:%s" % msgin) @@ -2284,20 +2351,38 @@ class DecodeImpulse(): ''' self.world.ServerPeopleActive = msgin.readUint8('ServerPeopleActive') self.world.ServerCareerActive = msgin.readUint8('ServerCareerActive') + # impulse.serialCont (CharacterSummaries); self.world.CharacterSummaries = [] size = msgin.readUint32('CharacterSummaries:len') for _ in range(0, size): tmp = CCharacterSummary() tmp.read(msgin) self.world.CharacterSummaries.append(tmp) - #_, CharacterSummaries = msgin.readCont('CharacterSummaries') - _, shardNames = msgin.readCont('shardNames') + # impulse.serialCont (shardNames); + size = msgin.readUint32('shardNames:len') + shardNames = [] + for i in range(0, size): + shardNames.append(msgin.readString('shardNames_' + str(i))) + # CShardNames::getInstance().loadShardNames(shardNames); + # int(shardNames[i*3+0]) = SessionId / shardNames[i*3+1] = DisplayName / shardNames[i*3+2] = ShortName + for i in range(0, size // 3): + tmp = CShardName(int(shardNames[i*3+0]), shardNames[i*3+1], shardNames[i*3+2]) + self.world.CShardNames.append(tmp) + + #_, shardNames = msgin.readCont('shardNames') # readPrivileges(impulse); - UserPrivileges = msgin.readString('UserPrivileges') - FreeTrial = msgin.readBool('FreeTrial') - _, Mainlands = msgin.readCont('Mainlands') - self.log.debug("Mesage UserChars: %s" % msgin.showAllData()) - self.log.debug("TODO") + self.world.UserPrivileges = msgin.readString('UserPrivileges') + self.world.FreeTrial = msgin.readBool('FreeTrial') + self.world.FreeTrial = False # We read and ignore this param :) + + # impulse.serialCont(Mainlands); + self.Mainlands = [] + size = msgin.readUint32('Mainlands:len') + for _ in range(0, size): + tmp = CMainlandSummary() + tmp.read(msgin) + self.world.Mainlands.append(tmp) + self.updatePatcherPriorityBasedOnCharacters(); # Load player config from server to client def impulseUserChar(self, msgin): self.log.debug("TODO")