From 733000a09ca75706639954f8ec51febf7e7f85ce Mon Sep 17 00:00:00 2001 From: AleaJactaEst Date: Sun, 28 Jul 2019 00:39:49 +0200 Subject: [PATCH] adding select profile --- client.py | 147 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 123 insertions(+), 24 deletions(-) diff --git a/client.py b/client.py index 6bc9c32..3ee1674 100755 --- a/client.py +++ b/client.py @@ -49,6 +49,13 @@ import inspect INVALID_SLOT = 0xff +def convertUStringToString(name): + ret = '' + for car in name: + if ord(car) >= 32 and ord(car)<=127: + ret += car + return ret + class BitStream(): def __init__(self): self._pos = 0 @@ -485,13 +492,13 @@ class BitStream(): source.putRead(0) need = 8 - (self._pos % 8) if need != 8: - self.internalSerial(source.readSerial(need), need, decode=False) + self.internalSerial(source.readSerial(need, decode=False), need, decode=False) while source.needRead() >= 8: - self.pushUint8(source.readSerial(8, False), decode=False) + self.pushUint8(source.readSerial(8, decode=False), decode=False) need = source.needRead() if need > 0: - self.internalSerial(source.readSerial(need, False), need, decode=False) + self.internalSerial(source.readSerial(need, decode=False), need, decode=False) source.putRead(srcRead) p2 = self._pos @@ -657,7 +664,7 @@ class BitStream(): ret = BitStream() v1 = self._read for i in range(0, size): - ret.pushUint8(self.readUint8('', decode=False)) + ret.pushUint8(self.readUint8('', decode=False), decode=False) v2 = self._read self._groupRead.append((v1, v2, name, 'StreamUint8', '')) return ret @@ -1190,6 +1197,66 @@ class TType(IntEnum): NB_TYPE = 11 +class TState(IntEnum): + # initial state + st_start = 0 + # display login screen and options + st_login = 1 + # auto login using cmd lien parameters (used with patch reboot) + st_auto_login = 2 + # display the shard list + st_shard_list = 3 + # lauch the configurator and close ryzom + st_start_config = 4 + # run the scan data thread + st_scan_data = 5 + # display the eula and wait for validation + st_display_eula = 6 + # check the data to determine need for patch + st_check_patch = 7 + # display the list of optional patch category for patching + st_display_cat = 8 + # run the patch process and display progress + st_patch = 9 + # terminate the client and quit + st_close_client = 10 + # display the reboot screen and wait validation + st_reboot_screen = 11 + # restart the client with login bypass params + st_restart_client = 12 + # connect to the FS (start the 'in game' mode) + st_connect = 13 + # show the outgame browser + st_browser_screen = 14 + # ingame state + st_ingame = 15 + # leave the current shard (the exit action progress, Far TP part 1.1; Server Hop part 1-2) + st_leave_shard = 16 + # let the main loop finish the current frame and leave it (Far TP part 1.2) + st_enter_far_tp_main_loop = 17 + # disconnect from the FS (Far TP part 2) + st_disconnect = 18 + # connect to a new FS (Far TP & Server Hop part 3.1) + st_reconnect_fs = 19 + # after reconnecting, bypass character selection ui & select the same character (Far TP & Server Hop part 3.2) + st_reconnect_select_char = 20 + # after reconnecting and receiving ready, send ready (Far TP part 3.3) + st_reconnect_ready = 21 + # between global menu exit and sending ready (Server Hop part 3.3) + st_exit_global_menu = 22 + # error while reconnecting + st_reconnect_error = 23 + # Rate a ring session. should pop a web windows pointing the rate session page + st_rate_session = 24 + # create account + st_create_account = 25 + # try to login with alternate login system + st_alt_login = 26 + # pseudo state to leave the state machine + st_end = 27 + st_unknown = 28 + + class EGender(IntEnum): male = 0 female = 1 @@ -2112,7 +2179,7 @@ class CCharacterSummary(): ''' self.version = msgin.readUint8('version') self.Mainland = msgin.readUint32('Mainland') - self.Name = msgin.readUString('Name') + self.Name = convertUStringToString(msgin.readUString('Name')) self.People = msgin.readSint32('People') self.Location = msgin.readUint32('Location') self.sPropVisualA.read(msgin) @@ -2171,7 +2238,7 @@ def CodeMsgXml(msgXml, key): for ele in head: if ele.attrib['name'] == id: found = True - ret.append([nbBit, i]) + ret.append([nbBit, i, id]) break i +=1 if not found: @@ -2237,6 +2304,8 @@ class World(): self.UserPrivileges = '' self.FreeTrial = False self.HeadName = HeadName + self.CurrentState = TState.st_unknown + self.UseFemaleTitles = False def CreaterCharacter(self, msgXml): ''' @@ -2295,8 +2364,8 @@ class World(): msgout = BitStream() # GenericMsgHeaderMngr.pushNameToStream("CONNECTION:CREATE_CHAR", out)) ref = CodeMsgXml(msgXml, 'CONNECTION:CREATE_CHAR') - for size, value in ref: - msgout.internalSerial(value, size) + for size, value, id in ref: + msgout.internalSerial(value, size, typeName=id) # khanat-opennel-code/code/ryzom/common/src/game_share/msg_client_server.h # void serialBitMemStream(NLMISC::CBitMemStream &f) msgout.pushUint8(Slot) msgout.pushUint32(SheetId) @@ -2356,6 +2425,18 @@ class World(): #msgout = CMessage("CREATE_CHAR") #msgout.serial(uid, bms) + def SelectChar(self, msgXml, PlayerSelectedSlot): + ''' + khanat-opennel-code/code/ryzom/client/src/far_tp.cpp # void CFarTP::selectCharAndEnter() + ''' + msgout = BitStream() + ref = CodeMsgXml(msgXml, 'CONNECTION:SELECT_CHAR') + for size, value, id in ref: + msgout.internalSerial(value, size, typeName=id) + msgout.pushUint8(PlayerSelectedSlot) + return msgout + + class CPersistentDataRecord: def __init__(self, log): self.log = log @@ -3197,6 +3278,10 @@ class DecodeImpulse(): def impulsePhraseSend(self, msgin): + dynId = msgin.readUint32('dynId') + self.log.debug("dynId:%d" % dynId) + StringId = msgin.readUint32('StringId') + self.log.debug("dynId:%d StringId:%s" % (dynId, StringId)) self.log.debug("TODO") def impulseStringResp(self, msgin): @@ -3240,8 +3325,7 @@ class DecodeImpulse(): def impulseGuildUpdatePlayerTitle(self, msgin): self.log.debug("TODO") def impulseGuildUseFemaleTitles(self, msgin): - self.log.debug("TODO") - + self.world.UseFemaleTitles = msgin.readBool('UseFemaleTitles') def impulseCloseTempInv(self, msgin): self.log.debug("TODO") @@ -3514,11 +3598,11 @@ class DecodeImpulse(): return ret def execute(self, msgin): + self.log.debug("execute") head = self.msgXml listpath = [] while True: nbBit = getPowerOf2(len(head)) - # def readSerial(self, nbits, name="", decode=True, typeName='', emulate=False): id = msgin.readSerial(nbBit, name='MsgXML', typeName='Number', emulate=True) ele = head[id] @@ -3527,6 +3611,7 @@ class DecodeImpulse(): fullname = ':'.join(listpath) id = msgin.readSerial(nbBit, name='MsgXML', typeName='XML <' + name + '>') + self.log.debug(fullname) if fullname in self.GenericMsgHeaderMngr: self.log.debug("Found : %s" % fullname) self.GenericMsgHeaderMngr[fullname](msgin) @@ -3688,7 +3773,7 @@ class CActionGeneric(CAction): decodeImpulse.execute(self._Message) def __str__(self): - return "CActionGeneric" + super().__str__() + "[" + self._Message.showAllData() + ']' + return "CActionGeneric" + super().__str__() + "[read:" + self._Message.showAllData() + '/write:' + self._Message.showAllDataWrite() + ']' def size(self): size = super().size() @@ -3762,7 +3847,7 @@ class CActionGenericMultiPart(CAction): decodeImpulse.GenericMultiPartTemp.setGenericMultiPartTemp(self.Number, self.Part, self.NbBlock, self.PartCont, decodeImpulse) def __str__(self): - return "CActionGenericMultiPart" + super().__str__() + "[" + str(self.Number) + ',' + str(self.Part) + ',' + str(self.NbBlock) + ',' + self.PartCont.showAllData() + ']' + return "CActionGenericMultiPart" + super().__str__() + "[" + str(self.Number) + ',' + str(self.Part) + ',' + str(self.NbBlock) + ',read:' + self.PartCont.showAllData() + ',write:' + self.PartCont.showAllDataWrite() + ']' def size(self): size = super().size() @@ -3879,7 +3964,7 @@ class CActionBlock: self.Cycle = 0 self.FirstPacket = 0 self.Actions = [] - self.Sucess = True + self.Success = True def serial(self, msgout, actionFactory): msgout.pushUint32(self.Cycle) @@ -3908,6 +3993,8 @@ class CActionBlock: def push_back(self, action): self.Actions.append(action) + def __str__(self): + return "CActionBlock [Cycle:" + str(self.Cycle) + ', FirstPacket:' + str(self.FirstPacket) + ', Data:' + ', '.join([ str(x) for x in self.Actions]) + "]" class CImpulseDecoder: @@ -4040,6 +4127,7 @@ class ClientNetworkConnection: self._LastSendTime = 0 self._ImpulseMultiPartNumber = 0 self.clientTick = 0 + self.stepAction = 0 def signal_exit(self, sig, frame): self.log.warning("Receive signal to quit program") @@ -4307,8 +4395,8 @@ class ClientNetworkConnection: self.log.debug("Message not read (%d) %s" % (msgin.needRead(), msgin.showLastData() )) # remove all old actions that are acked - while self._Actions and self._Actions[0].FirstPacket != 0 and self._Actions[0].FirstPacket : - self.log.debug("remove old action") + while self._Actions and self._Actions[0].FirstPacket != 0 and self._Actions[0].FirstPacket < self._LastReceivedAck: + self.log.debug("remove old action [%d/%d] : %s" % (self._Actions[0].FirstPacket, self._LastReceivedAck, self._Actions[0])) self._Actions.pop(0) self._CurrentServerTick = self._CurrentReceivedNumber * 2 + self._Synchronize @@ -4657,6 +4745,7 @@ class ClientNetworkConnection: cycle = self._CurrentServerTick bitSize = 32*8 # block size is 32 (cycle) + 8 (number of actions if len(self._Actions) == 0 or self._Actions[-1].Cycle != 0: + self.log.debug("No Action") pass else: block = self._Actions[-1] @@ -4682,14 +4771,24 @@ class ClientNetworkConnection: # cmd = self.world.Commands.pop(0) def analyze(self): - if self.world.CShardNames != []: - if self.world.CharacterSummaries != [] and self.clientTick > 5: - if self.world.CharacterSummaries[0].People == TPeople.Unknown: - bms = self.world.CreaterCharacter(self.msgXml) - self.push(bms) - + if self.world.CurrentState == TState.st_connect: + if self.world.CShardNames != []: + if self.stepAction == 0 and self.world.CharacterSummaries != [] and self.clientTick > 0: + if self.world.CharacterSummaries[0].People == TPeople.Unknown: + bms = self.world.CreaterCharacter(self.msgXml) + self.push(bms) + self.stepAction = 1 + else: + self.stepAction = 1 + elif self.stepAction == 1 and self.world.CharacterSummaries != []: + if self.world.CharacterSummaries[0].People != TPeople.Unknown: + self.log.info("Account defined %s" % self.world.CharacterSummaries[0].Name) + bms = self.world.SelectChar(self.msgXml, 0) + self.push(bms) + self.stepAction = 2 def EmulateFirst(self, msgRawXml, databaseRawXml): + self.world.CurrentState = TState.st_start self.msgXml = ET.fromstring(msgRawXml) #ET.dump(msgXml) self.databaseXml = ET.fromstring(databaseRawXml) @@ -4701,16 +4800,16 @@ class ClientNetworkConnection: self.decodeImpulse.loadMsg(self.msgXml) self.decodeImpulse.loadDatabase(self.databaseXml) - #CodeMsgXml(self.msgXml, 'CONNECTION:CREATE_CHAR') self.connect() self.log.info("Client Login") self.sendSystemLogin() + self.world.CurrentState = TState.st_connect self.log.info("Receive Message") self.clientTick = 0 for _ in range(0, 50): #while True: - self.log.debug("%s [%s: %d] %s" % ("*" * 40, "Loop", self.clientTick,"*" * 40)) + self.log.debug("%s [%s: %d / %d] %s" % ("*" * 40, "Loop", self.clientTick, self.stepAction, "*" * 40)) self.update() self.analyze() self.send()