mirror of
https://port.numenaute.org/aleajactaest/clientbot.git
synced 2024-11-25 08:36:18 +00:00
adding spy tools & update clientbot
This commit is contained in:
parent
733000a09c
commit
3121a918bb
36 changed files with 6431 additions and 4818 deletions
416
spykhanat.py
Executable file
416
spykhanat.py
Executable file
|
@ -0,0 +1,416 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# script to read pcap file (communcation with khanat)
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# Ex.:
|
||||||
|
# sudo tcpdump -i docker0 -w capture2.pcap
|
||||||
|
# ./spykhanat.py --pcap-file=../capture2.pcap --msg-xml=../khanat-opennel-code/code/ryzom/common/data_common/msg.xml
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
from pcapfile import savefile
|
||||||
|
from pcapfile.protocols.linklayer import ethernet
|
||||||
|
from pcapfile.protocols.network import ip
|
||||||
|
from pcapfile.protocols.transport import udp
|
||||||
|
from pcapfile.protocols.transport import tcp
|
||||||
|
import binascii
|
||||||
|
import re
|
||||||
|
from tools import BitStream
|
||||||
|
from tools import Enum
|
||||||
|
from tools import CActionFactory
|
||||||
|
from tools import CBitSet
|
||||||
|
from tools import DecodeImpulse
|
||||||
|
from tools import World
|
||||||
|
from tools import CGenericMultiPartTemp
|
||||||
|
from tools import CImpulseDecoder
|
||||||
|
from tools import CStringManager
|
||||||
|
from tools import CAction
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
LOGGER = 'SpyKhanat'
|
||||||
|
|
||||||
|
#file = open('capture2.pcap' , 'rb')
|
||||||
|
#pcapfile = savefile.load_savefile(file,verbose=True)
|
||||||
|
#pkt = pcapfile.packets[0]
|
||||||
|
#print(pkt.raw())
|
||||||
|
#print(pkt.timestamp)
|
||||||
|
#eth_frame = ethernet.Ethernet(pkt.raw())
|
||||||
|
#print(eth_frame)
|
||||||
|
#ip_packet = ip.IP(binascii.unhexlify(eth_frame.payload))
|
||||||
|
#print(ip_packet)
|
||||||
|
|
||||||
|
class SpyPcap():
|
||||||
|
def __init__(self, khanat_host_service, pcap_file, msg_xml, filter_host_service, show_raw_packet, show_message_decoded):
|
||||||
|
if khanat_host_service:
|
||||||
|
self.khanat_host_service = re.compile(khanat_host_service)
|
||||||
|
else:
|
||||||
|
self.khanat_host_service = None
|
||||||
|
self.pcap_file = pcap_file
|
||||||
|
self.msg_xml = msg_xml
|
||||||
|
if filter_host_service:
|
||||||
|
self.filter_host_service = re.compile(filter_host_service)
|
||||||
|
else:
|
||||||
|
self.filter_host_service = None
|
||||||
|
self.show_raw_packet = show_raw_packet
|
||||||
|
self.show_message_decoded = show_message_decoded
|
||||||
|
self.actionFactory = CActionFactory.CActionFactory(None)
|
||||||
|
self.client_state = {}
|
||||||
|
self.decodeImpulse = DecodeImpulse.DecodeImpulse()
|
||||||
|
|
||||||
|
fp = open(msg_xml , 'rt')
|
||||||
|
msgRawXml = fp.read()
|
||||||
|
self.msgXml = ET.fromstring(msgRawXml)
|
||||||
|
self.decodeImpulse.loadMsg(self.msgXml)
|
||||||
|
|
||||||
|
def readRaw(self):
|
||||||
|
file = open( self.pcap_file , 'rb')
|
||||||
|
pcapfile = savefile.load_savefile(file,verbose=False)
|
||||||
|
for pkt in pcapfile.packets:
|
||||||
|
print("pkt:", dir(pkt))
|
||||||
|
print("pkt.header:", dir(pkt.header))
|
||||||
|
print("pkt.packet:", dir(pkt.packet))
|
||||||
|
logging.getLogger(LOGGER).debug("raw: %s" % pkt.raw())
|
||||||
|
logging.getLogger(LOGGER).debug("timestamp: %s" % pkt.timestamp)
|
||||||
|
eth_frame = ethernet.Ethernet(pkt.raw())
|
||||||
|
logging.getLogger(LOGGER).debug("eth_frame: %s" % eth_frame)
|
||||||
|
if eth_frame.type == 2048:
|
||||||
|
ip_packet = ip.IP(binascii.unhexlify(eth_frame.payload))
|
||||||
|
logging.getLogger(LOGGER).debug("ip packet: %s" % ip_packet)
|
||||||
|
print("ip_packet:", dir(ip_packet))
|
||||||
|
logging.getLogger(LOGGER).debug("ip packet: %s ->%s" % (ip_packet.src.decode(), ip_packet.dst.decode()) )
|
||||||
|
if ip_packet.p == 17:
|
||||||
|
# UDP
|
||||||
|
logging.getLogger(LOGGER).debug("ip packet: protocol UDP (%s)" % ip_packet.p)
|
||||||
|
udp_packet = udp.UDP(binascii.unhexlify(ip_packet.payload))
|
||||||
|
print("udp_packet:", dir(udp_packet))
|
||||||
|
logging.getLogger(LOGGER).debug("UDP packet: %s" % udp_packet)
|
||||||
|
data = udp_packet.payload
|
||||||
|
print("data:", dir(data))
|
||||||
|
logging.getLogger(LOGGER).debug("data packet: %s" % data)
|
||||||
|
data = udp_packet.payload
|
||||||
|
logging.getLogger(LOGGER).info("data packet: timestamp:%s src:%s:%d dst:%s:%d data:%s" % (pkt.timestamp,
|
||||||
|
ip_packet.src.decode(), udp_packet.src_port,
|
||||||
|
ip_packet.dst.decode(), udp_packet.dst_port,
|
||||||
|
data.decode()))
|
||||||
|
|
||||||
|
elif ip_packet.p == 6:
|
||||||
|
# TCP
|
||||||
|
logging.getLogger(LOGGER).debug("ip packet: protocol TCP (%s)" % ip_packet.p)
|
||||||
|
tcp_packet = tcp.TCP(binascii.unhexlify(ip_packet.payload))
|
||||||
|
data = tcp_packet.payload
|
||||||
|
logging.getLogger(LOGGER).info("data packet: timestamp:%s src:%s:%d dst:%s:%d data:%s" % (pkt.timestamp,
|
||||||
|
ip_packet.src.decode(), tcp_packet.src_port,
|
||||||
|
ip_packet.dst.decode(), tcp_packet.dst_port,
|
||||||
|
data.decode()))
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug("ip packet: protocol (%s)" % ip_packet.p)
|
||||||
|
|
||||||
|
def detect_khanat_server(self, packets):
|
||||||
|
hostdetected = {}
|
||||||
|
for pkt in packets:
|
||||||
|
eth_frame = ethernet.Ethernet(pkt.raw())
|
||||||
|
if eth_frame.type == 2048:
|
||||||
|
ip_packet = ip.IP(binascii.unhexlify(eth_frame.payload))
|
||||||
|
if ip_packet.p == 17: # UDP
|
||||||
|
udp_packet = udp.UDP(binascii.unhexlify(ip_packet.payload))
|
||||||
|
data = udp_packet.payload
|
||||||
|
host = "%s:%d" % (ip_packet.src.decode(), udp_packet.src_port)
|
||||||
|
hostdetected.setdefault(host, 0)
|
||||||
|
if len(data) == 20:
|
||||||
|
hostdetected[host] += 1
|
||||||
|
id = None
|
||||||
|
max = 0
|
||||||
|
for host in hostdetected:
|
||||||
|
if id:
|
||||||
|
if max < hostdetected[host]:
|
||||||
|
max = hostdetected[host]
|
||||||
|
id = host
|
||||||
|
else:
|
||||||
|
max = hostdetected[host]
|
||||||
|
id = host
|
||||||
|
logging.getLogger(LOGGER).info("khanat host :%s" % id)
|
||||||
|
return id
|
||||||
|
|
||||||
|
def initialize_client(self, clientid):
|
||||||
|
self.client_state.setdefault(clientid, {'CurrentReceivedNumber': 0,
|
||||||
|
'CurrentSendNumber': 0,
|
||||||
|
'LastReceivedAck': 0,
|
||||||
|
'RegisteredAction': {},
|
||||||
|
'world': World.World(),
|
||||||
|
'GenericMultiPartTemp': CGenericMultiPartTemp.GenericMultiPartTemp(),
|
||||||
|
'CImpulseDecoder': None,
|
||||||
|
'LastAck0': [-1],
|
||||||
|
'LastAck1': [-1, -1],
|
||||||
|
'LastAck2': [-1, -1, -1, -1]})
|
||||||
|
self.client_state[clientid]['CImpulseDecoder'] = CImpulseDecoder.CImpulseDecoder(self.client_state[clientid]['world'])
|
||||||
|
|
||||||
|
def add_registered_action(self, clientid, action):
|
||||||
|
self.client_state[clientid]['RegisteredAction'].setdefault(action.Code, [])
|
||||||
|
self.client_state[clientid]['RegisteredAction'][action.Code].append(action)
|
||||||
|
|
||||||
|
def decode_server(self, clientid, msgin, receivedPacket, receivedAck, nextSentPacket=0):
|
||||||
|
actions = []
|
||||||
|
for level in range(0, 3):
|
||||||
|
if level == 0:
|
||||||
|
lAck = self.client_state[clientid]['LastAck0']
|
||||||
|
channel = 0
|
||||||
|
elif level == 1:
|
||||||
|
lAck = self.client_state[clientid]['LastAck1']
|
||||||
|
channel = receivedPacket & 1
|
||||||
|
elif level == 2:
|
||||||
|
lAck = self.client_state[clientid]['LastAck2']
|
||||||
|
channel = receivedPacket & 3
|
||||||
|
keep = True
|
||||||
|
checkOnce = False
|
||||||
|
num = 0
|
||||||
|
#logging.getLogger(LOGGER).debug("level:%d channel:%d lAck:%s" %(level, channel, ':'.join([str(x) for x in lAck])))
|
||||||
|
# lastAck = lAck[channel]
|
||||||
|
while True:
|
||||||
|
next = msgin.readBool('next:' + str(level) + ':' + str(channel))
|
||||||
|
if not next:
|
||||||
|
break
|
||||||
|
if not checkOnce:
|
||||||
|
checkOnce = True
|
||||||
|
keep = receivedAck >= lAck[channel]
|
||||||
|
logging.getLogger(LOGGER).debug("keep:%s [%d => %d]" % (str(keep), receivedAck, lAck[channel]))
|
||||||
|
if keep:
|
||||||
|
lAck[channel] = nextSentPacket
|
||||||
|
logging.getLogger(LOGGER).debug("lAck:%s" % ':'.join([str(x) for x in lAck]))
|
||||||
|
pass
|
||||||
|
num += 1
|
||||||
|
#actionFactory = CAction.CActionFactory(None)
|
||||||
|
action = self.actionFactory.unpack(msgin)
|
||||||
|
logging.getLogger(LOGGER).debug("action:%s" % action)
|
||||||
|
#action = self._CActionFactory.unpack(msgin)
|
||||||
|
if keep:
|
||||||
|
logging.getLogger(LOGGER).debug("keep Code:%s" % str(action.Code))
|
||||||
|
actions.append(action)
|
||||||
|
elif action:
|
||||||
|
logging.getLogger(LOGGER).debug("append Code:%s" % str(action.Code))
|
||||||
|
self.add_registered_action(clientid, action)
|
||||||
|
return actions
|
||||||
|
|
||||||
|
def decode_client_receive_normal_message(self, msgin, clientid, dst):
|
||||||
|
actions = self.client_state[clientid]['CImpulseDecoder'].decode(msgin, self.client_state[clientid]['CurrentReceivedNumber'], self.client_state[clientid]['LastReceivedAck'], self.client_state[clientid]['CurrentSendNumber'] )
|
||||||
|
logging.getLogger(LOGGER).info("[Client -> Khanat] actions:%s" % str(actions))
|
||||||
|
# decodeVisualProperties( msgin );
|
||||||
|
|
||||||
|
|
||||||
|
def decode_client_message(self, msgin, clientid, dst):
|
||||||
|
CurrentReceivedNumber = msgin.readSint32('CurrentReceivedNumber')
|
||||||
|
SystemMode = msgin.readBool('SystemMode')
|
||||||
|
logging.getLogger(LOGGER).debug("[Client -> Khanat] {CurrentReceivedNumber:%d, SystemMode:%d, src:%s, dst:%s}" % (CurrentReceivedNumber, SystemMode, clientid, dst))
|
||||||
|
self.initialize_client(clientid)
|
||||||
|
self.client_state[clientid]['CurrentReceivedNumber'] = CurrentReceivedNumber
|
||||||
|
if not SystemMode:
|
||||||
|
LastReceivedAck = msgin.readSint32('LastReceivedAck')
|
||||||
|
self.client_state[clientid]['LastReceivedAck'] = LastReceivedAck
|
||||||
|
logging.getLogger(LOGGER).info("[Client -> Khanat] Normal Mode {CurrentReceivedNumber:%d, src:%s, dst:%s, LastReceivedAck:%d}" % (CurrentReceivedNumber, clientid, dst, LastReceivedAck))
|
||||||
|
#self.decode_server(msgin, _CurrentReceivedNumber, _CurrentReceivedNumber-1)
|
||||||
|
self.decode_client_receive_normal_message(msgin, clientid, dst)
|
||||||
|
else:
|
||||||
|
message = msgin.readUint8('message')
|
||||||
|
try:
|
||||||
|
typeMessage = Enum.CLFECOMMON(message).name
|
||||||
|
except ValueError:
|
||||||
|
typeMessage = "Unknown"
|
||||||
|
if message == Enum.CLFECOMMON.SYSTEM_LOGIN_CODE:
|
||||||
|
UserAddr = msgin.readUint32('UserAddr')
|
||||||
|
UserKey = msgin.readUint32('UserKey')
|
||||||
|
UserId = msgin.readUint32('UserId')
|
||||||
|
LanguageCode = msgin.readString('LanguageCode')
|
||||||
|
logging.getLogger(LOGGER).info("[Client -> Khanat] System Mode:%s {CurrentReceivedNumber:%d, src:%s, dst:%s, UserAddr:%d, UserId:%d, UserAddr:%d LanguageCode:%s}" %
|
||||||
|
(typeMessage, CurrentReceivedNumber, clientid, dst, UserAddr, UserKey, UserId, LanguageCode))
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_PROBE_CODE:
|
||||||
|
LatestProbe = msgin.readSint32('LatestProbe')
|
||||||
|
logging.getLogger(LOGGER).info("[Client -> Khanat] System Mode:%s probe:%d {CurrentReceivedNumber:%d, src:%s, dst:%s}" % (typeMessage,
|
||||||
|
LatestProbe, CurrentReceivedNumber, clientid, dst))
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_SYNC_CODE:
|
||||||
|
Synchronize = msgin.readUint32('Synchronize')
|
||||||
|
stime = msgin.readSint64('stime')
|
||||||
|
LatestSync = msgin.readUint32('LatestSync')
|
||||||
|
MsgData = msgin.readArrayUint8(16, 'MsgData')
|
||||||
|
md5Msg = bytes(MsgData)
|
||||||
|
DatabaseData = msgin.readArrayUint8(16, 'DatabaseData')
|
||||||
|
md5Database = bytes(DatabaseData)
|
||||||
|
logging.getLogger(LOGGER).info("[Client -> Khanat] System Mode:%s {CurrentReceivedNumber:%d, src:%s, dst:%s, Synchronize:%d, stime:%d, LatestSync:%d, MsgData:%s, DatabaseData:%s}" % (
|
||||||
|
typeMessage, CurrentReceivedNumber, clientid, dst, Synchronize, stime, LatestSync, binascii.hexlify(md5Msg).decode(), binascii.hexlify(md5Database).decode()))
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_ACK_SYNC_CODE:
|
||||||
|
LastReceivedNumber = msgin.readSint32('LastReceivedNumber')
|
||||||
|
LastAckInLongAck = msgin.readSint32('LastAckInLongAck')
|
||||||
|
LongAckBitField = CBitSet.CBitSet()
|
||||||
|
LongAckBitField.readSerial(msgin, 'LongAckBitField')
|
||||||
|
LatestSync = msgin.readSint32('LatestSync')
|
||||||
|
logging.getLogger(LOGGER).info("[Client -> Khanat] System Mode:%s {CurrentReceivedNumber:%d, src:%s, dst:%s, LastReceivedNumber:%d, LastAckInLongAck:%d, LatestSync:%d, LongAckBitField:%s}" % (
|
||||||
|
typeMessage, CurrentReceivedNumber, clientid, dst, LastReceivedNumber, LastAckInLongAck, LatestSync, LongAckBitField))
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_ACK_PROBE_CODE:
|
||||||
|
SizeLatestProbes = msgin.readSint32('SizeLatestProbes')
|
||||||
|
LatestProbes = []
|
||||||
|
for data in range(0, SizeLatestProbes):
|
||||||
|
LatestProbes.append(msgin.readSint32('LatestProbes'))
|
||||||
|
logging.getLogger(LOGGER).info("[Client -> Khanat] System Mode:%s (%d) {CurrentReceivedNumber:%d, src:%s, dst:%s, SizeLatestProbes:%d, LatestProbes:%s}" % (typeMessage, message, CurrentReceivedNumber, clientid, dst, SizeLatestProbes, str(LatestProbes)))
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).info("[Client -> Khanat] System Mode:%s (%d) {CurrentReceivedNumber:%d, src:%s, dst:%s}" % (typeMessage, message, CurrentReceivedNumber, clientid, dst))
|
||||||
|
logging.getLogger(LOGGER).debug("[Client -> Khanat] msg:%s" % msgin.showAllData())
|
||||||
|
|
||||||
|
def decode_khanat_message(self, msgin, src, dst):
|
||||||
|
CurrentSendNumber = msgin.readSint32('CurrentSendNumber')
|
||||||
|
logging.getLogger(LOGGER).debug("[Khanat -> Client] {CurrentSendNumber:%d, src:%s, dst:%s}" % (CurrentSendNumber, src, dst))
|
||||||
|
SystemMode = msgin.readBool('SystemMode')
|
||||||
|
self.initialize_client(dst)
|
||||||
|
self.client_state[dst]['CurrentSendNumber'] = CurrentSendNumber
|
||||||
|
if not SystemMode:
|
||||||
|
_LastReceivedAck = msgin.readSint32('LastReceivedAck');
|
||||||
|
logging.getLogger(LOGGER).debug("[Khanat -> Client] Normal Mode {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d}" % (CurrentSendNumber, src, dst, _LastReceivedAck))
|
||||||
|
actions = self.decode_server(dst, msgin, CurrentSendNumber, CurrentSendNumber-1)
|
||||||
|
if actions:
|
||||||
|
logging.getLogger(LOGGER).debug('list actions: [' + str(len(actions)) + '] ' +','.join( [ str(x) for x in actions] ) )
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug('list actions: None')
|
||||||
|
|
||||||
|
# Decode the actions received in the impulsions
|
||||||
|
logging.getLogger(LOGGER).debug('=' * 80)
|
||||||
|
for action in actions:
|
||||||
|
logging.getLogger(LOGGER).debug('-' * 80)
|
||||||
|
logging.getLogger(LOGGER).debug('Analyse actions:%s', action)
|
||||||
|
if action.Code == Enum.TActionCode.ACTION_DISCONNECTION_CODE:
|
||||||
|
logging.getLogger(LOGGER).info("Action : ACTION_DISCONNECTION_CODE")
|
||||||
|
elif action.Code == Enum.TActionCode.ACTION_GENERIC_CODE:
|
||||||
|
action.genericAction(self.decodeImpulse, self.client_state[dst]['world'], self.client_state[dst]['GenericMultiPartTemp'])
|
||||||
|
logging.getLogger(LOGGER).info("[Khanat -> Client] ACTION_GENERIC_CODE : {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d, action:%s}" % (CurrentSendNumber, src, dst, _LastReceivedAck, action))
|
||||||
|
elif action.Code == Enum.TActionCode.ACTION_GENERIC_MULTI_PART_CODE:
|
||||||
|
action.genericAction(self.decodeImpulse, self.client_state[dst]['world'], self.client_state[dst]['GenericMultiPartTemp'])
|
||||||
|
logging.getLogger(LOGGER).debug("[Khanat -> Client] ACTION_GENERIC_MULTI_PART_CODE : %s" % action)
|
||||||
|
for id in self.client_state[dst]['GenericMultiPartTemp'].data:
|
||||||
|
if self.client_state[dst]['GenericMultiPartTemp'].data[id].isAvailable():
|
||||||
|
logging.getLogger(LOGGER).info("[Khanat -> Client] ACTION_GENERIC_MULTI_PART_CODE {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d, id:%d, msg:%s}" % (CurrentSendNumber, src, dst, _LastReceivedAck, id, self.client_state[dst]['GenericMultiPartTemp'].data[id].read().showAllData()))
|
||||||
|
elif action.Code == Enum.TActionCode.ACTION_DUMMY_CODE:
|
||||||
|
logging.getLogger(LOGGER).info("Action : ACTION_DUMMY_CODE")
|
||||||
|
self.add_registered_action(dst, action)
|
||||||
|
# # remove all old actions that are acked
|
||||||
|
# while self._Actions and self._Actions[0].FirstPacket != 0 and self._Actions[0].FirstPacket < self._LastReceivedAck:
|
||||||
|
# logging.getLogger(LOGGER).debug("remove old action [%d/%d] : %s" % (self._Actions[0].FirstPacket, self._LastReceivedAck, self._Actions[0]))
|
||||||
|
# self._Actions.pop(0)
|
||||||
|
else:
|
||||||
|
message = msgin.readUint8('message')
|
||||||
|
logging.getLogger(LOGGER).debug("[Khanat -> Client] System Mode {CurrentSendNumber:%d, src:%s, dst:%s, message:%d" % (CurrentSendNumber, src, dst, message))
|
||||||
|
if message == Enum.CLFECOMMON.SYSTEM_SYNC_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("[Khanat -> Client] Synchronize")
|
||||||
|
Synchronize = msgin.readUint32('Synchronize')
|
||||||
|
stime = msgin.readSint64('stime')
|
||||||
|
LatestSync = msgin.readUint32('LatestSync')
|
||||||
|
MsgData = msgin.readArrayUint8(16, 'MsgData')
|
||||||
|
DatabaseData = msgin.readArrayUint8(16, 'DatabaseData')
|
||||||
|
logging.getLogger(LOGGER).info("[Khanat -> Client] System Mode / Synchronize {CurrentSendNumber:%d, src:%s, dst:%s, message:%d, Synchronize:%d, stime:%d, LatestSync:%d, MsgData:%s, DatabaseData:%s}" % (CurrentSendNumber, src, dst, message, Synchronize, stime, LatestSync, str(MsgData), str(DatabaseData)))
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_STALLED_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("[Khanat -> Client] Stalled")
|
||||||
|
logging.getLogger(LOGGER).info("[Khanat -> Client] System Mode / Stalled {CurrentSendNumber:%d, src:%s, dst:%s, message:%d}" % (CurrentSendNumber, src, dst, message))
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_PROBE_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("[Khanat -> Client] Probe")
|
||||||
|
LatestProbe = msgin.readSint32('LatestProbe')
|
||||||
|
logging.getLogger(LOGGER).info("[Khanat -> Client] System Mode / Probe {CurrentSendNumber:%d, src:%s, dst:%s, message:%d, LatestProbe:%d}" % (CurrentSendNumber, src, dst, message, LatestProbe))
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
|
||||||
|
logging.getLogger(LOGGER).info("[Khanat -> Client] System Mode / BACK-END DOWN {CurrentSendNumber:%d, src:%s, dst:%s, message:%d}" % (CurrentSendNumber, src, dst, message))
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning("CNET: received system %d in state Login" % message)
|
||||||
|
#cActionFactory = CAction.CActionFactory(None)
|
||||||
|
#cActionFactory.unpack(msgin)
|
||||||
|
logging.getLogger(LOGGER).debug("[Khanat -> Client] msg:%s" % msgin.showAllData())
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
file = open( self.pcap_file , 'rb')
|
||||||
|
pcapfile = savefile.load_savefile(file,verbose=False)
|
||||||
|
khanat_host = self.detect_khanat_server(pcapfile.packets)
|
||||||
|
for pkt in pcapfile.packets:
|
||||||
|
eth_frame = ethernet.Ethernet(pkt.raw())
|
||||||
|
if eth_frame.type == 2048:
|
||||||
|
ip_packet = ip.IP(binascii.unhexlify(eth_frame.payload))
|
||||||
|
if ip_packet.p == 17:
|
||||||
|
# UDP
|
||||||
|
udp_packet = udp.UDP(binascii.unhexlify(ip_packet.payload))
|
||||||
|
data = udp_packet.payload
|
||||||
|
if udp_packet.src_port == 53 or udp_packet.dst_port == 53:
|
||||||
|
continue
|
||||||
|
if not self.filter_host_service or self.filter_host_service.match("%s:%d" % (ip_packet.src.decode(), udp_packet.src_port)) or self.filter_host_service.match("%s:%d" % (ip_packet.dst.decode(), udp_packet.dst_port)):
|
||||||
|
logging.getLogger(LOGGER).debug("-" * 80)
|
||||||
|
if self.show_raw_packet:
|
||||||
|
logging.getLogger(LOGGER).debug("[raw packet] timestamp:%s src:%s:%d dst:%s:%d data:%s" % (pkt.timestamp,
|
||||||
|
ip_packet.src.decode(), udp_packet.src_port,
|
||||||
|
ip_packet.dst.decode(), udp_packet.dst_port,
|
||||||
|
data.decode()))
|
||||||
|
msgin = BitStream.BitStream()
|
||||||
|
msgin.fromBytes(binascii.unhexlify(data))
|
||||||
|
src = "%s:%d" % (ip_packet.src.decode(), udp_packet.src_port)
|
||||||
|
dst = "%s:%d" % (ip_packet.dst.decode(), udp_packet.dst_port)
|
||||||
|
if (self.khanat_host_service and self.khanat_host_service.match(src)) or ( not self.khanat_host_service and khanat_host == src):
|
||||||
|
self.decode_khanat_message(msgin, src, dst)
|
||||||
|
else:
|
||||||
|
self.decode_client_message(msgin, src, dst)
|
||||||
|
if self.show_message_decoded:
|
||||||
|
logging.getLogger(LOGGER).debug("[message decoded] %s" % msgin.showAllData())
|
||||||
|
for client in self.client_state:
|
||||||
|
logging.getLogger(LOGGER).debug("%s [server tick:%d, client tick:%d]" %(client, self.client_state[client]['CurrentSendNumber'], self.client_state[client]['CurrentReceivedNumber']))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
FORMAT = '%(asctime)-15s %(levelname)s %(filename)s:%(lineno)d %(message)s'
|
||||||
|
logging.basicConfig(format=FORMAT)
|
||||||
|
|
||||||
|
logger = []
|
||||||
|
logger.append(logging.getLogger(LOGGER))
|
||||||
|
logger.append(logging.getLogger(CImpulseDecoder.LOGGER))
|
||||||
|
#logger.append(logging.getLogger(DecodeImpuls.LOGGER))
|
||||||
|
#logger.append(logging.getLogger(BitStream.LOGGER))
|
||||||
|
logger.append(logging.getLogger(CStringManager.LOGGER))
|
||||||
|
logger.append(logging.getLogger(CAction.LOGGER))
|
||||||
|
logger.append(logging.getLogger(CActionFactory.LOGGER))
|
||||||
|
CImpulseDecoder
|
||||||
|
# logger.append(logging.getLogger('CGenericMultiPartTemp'))
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--khanat-host-service", help="filter to detect khanat host:service (FES)")
|
||||||
|
parser.add_argument("--filter-host-service", help="filter host:service")
|
||||||
|
parser.add_argument("-d", "--debug", help="show debug message", action='store_true')
|
||||||
|
parser.add_argument("-p", "--pcap-file", help="file pcap to read", required=True)
|
||||||
|
parser.add_argument("-m", "--msg-xml", help="file msg.xml (from server khanat)", required=True)
|
||||||
|
parser.add_argument("-r", "--raw", help="show message raw", action='store_true')
|
||||||
|
parser.add_argument("--show-raw-packet", help="show packet (raw data)", action='store_true')
|
||||||
|
parser.add_argument("--show-message-decoded", help="show packet (raw data)", action='store_true')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.debug:
|
||||||
|
level = logging.getLevelName('DEBUG')
|
||||||
|
else:
|
||||||
|
level = logging.getLevelName('INFO')
|
||||||
|
|
||||||
|
for logid in logger:
|
||||||
|
logid.setLevel(level)
|
||||||
|
logging.getLogger(LOGGER).info("Begin")
|
||||||
|
|
||||||
|
spy = SpyPcap(khanat_host_service=args.khanat_host_service, pcap_file=args.pcap_file, msg_xml=args.msg_xml, filter_host_service=args.filter_host_service,
|
||||||
|
show_raw_packet=args.show_raw_packet, show_message_decoded=args.show_message_decoded)
|
||||||
|
if args.raw:
|
||||||
|
spy.readRaw()
|
||||||
|
else:
|
||||||
|
spy.read()
|
||||||
|
logging.getLogger(LOGGER).info("End")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
980
tools/BitStream.py
Normal file
980
tools/BitStream.py
Normal file
|
@ -0,0 +1,980 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module BitStream
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from ctypes import *
|
||||||
|
import sys
|
||||||
|
import inspect
|
||||||
|
import copy
|
||||||
|
|
||||||
|
|
||||||
|
class OverflowError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class BitStream():
|
||||||
|
def __init__(self):
|
||||||
|
self._pos = 0
|
||||||
|
self._read = 0
|
||||||
|
self._tampon = []
|
||||||
|
self._groupRead = []
|
||||||
|
self._groupWrite = []
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return (self._pos + 7) // 8
|
||||||
|
|
||||||
|
def __deepcopy__(self, memo):
|
||||||
|
ret = BitStream()
|
||||||
|
ret._pos = self._pos
|
||||||
|
ret._read = self._read
|
||||||
|
ret._tampon = copy.deepcopy(self._tampon, memo)
|
||||||
|
ret._groupRead = copy.deepcopy(self._groupRead, memo)
|
||||||
|
ret._groupWrite = copy.deepcopy(self._groupWrite, memo)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def needRead(self):
|
||||||
|
return self._pos - self._read
|
||||||
|
|
||||||
|
def sizeData(self):
|
||||||
|
return self._pos
|
||||||
|
|
||||||
|
def sizeRead(self):
|
||||||
|
return self._read
|
||||||
|
|
||||||
|
def getRead(self):
|
||||||
|
return self._read
|
||||||
|
|
||||||
|
def getPos(self):
|
||||||
|
return self._pos
|
||||||
|
|
||||||
|
def buffer(self):
|
||||||
|
return self._tampon
|
||||||
|
|
||||||
|
def putRead(self, value):
|
||||||
|
if value > self._pos:
|
||||||
|
raise ValueError
|
||||||
|
self._read = value
|
||||||
|
|
||||||
|
# ------------------------------------
|
||||||
|
def internalSerial(self, value, nbits, decode=True, typeName=''):
|
||||||
|
p1 = self._pos
|
||||||
|
if nbits == 0:
|
||||||
|
return
|
||||||
|
elif nbits > 32:
|
||||||
|
raise "Out of range"
|
||||||
|
pos = self._pos % 8
|
||||||
|
if pos == 0:
|
||||||
|
self._tampon.append(0)
|
||||||
|
value = c_uint32(value).value
|
||||||
|
if nbits != 32:
|
||||||
|
mask = (1 << nbits) - 1;
|
||||||
|
v = value & mask;
|
||||||
|
else:
|
||||||
|
v = value;
|
||||||
|
_FreeBits = 8 - (self._pos % 8)
|
||||||
|
if nbits > _FreeBits:
|
||||||
|
self._tampon[-1] |= (v >> ( nbits - _FreeBits))
|
||||||
|
self._pos += _FreeBits
|
||||||
|
self.internalSerial( v , nbits - _FreeBits, decode=False)
|
||||||
|
else:
|
||||||
|
self._tampon[-1] |= (v << ( _FreeBits - nbits))
|
||||||
|
self._pos += nbits
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+nbits, name, typeName, value))
|
||||||
|
|
||||||
|
def pushBool(self, value, decode=True):
|
||||||
|
p1 = self._pos
|
||||||
|
if value:
|
||||||
|
v = 1
|
||||||
|
else:
|
||||||
|
v = 0
|
||||||
|
self.internalSerial(v, 1, decode=False)
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+1, name, 'Bool', value))
|
||||||
|
|
||||||
|
def pushUint32(self, value, decode=True, typeName='Uint32'):
|
||||||
|
p1 = self._pos
|
||||||
|
self.internalSerial(value, 32, decode=False)
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+32, name, typeName, value))
|
||||||
|
|
||||||
|
def pushSint32(self, value, decode=True):
|
||||||
|
p1 = self._pos
|
||||||
|
self.internalSerial(value, 32, decode=False)
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+32, name, 'Sint32', value))
|
||||||
|
|
||||||
|
def pushUint16(self, value, decode=True):
|
||||||
|
p1 = self._pos
|
||||||
|
self.internalSerial(value, 16, decode=False)
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+16, name, 'Uint16', value))
|
||||||
|
|
||||||
|
def pushSint16(self, value, decode=True):
|
||||||
|
p1 = self._pos
|
||||||
|
self.internalSerial(value, 16, decode=False)
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+16, name, 'Sint16', value))
|
||||||
|
|
||||||
|
def pushUint8(self, value, decode=True):
|
||||||
|
p1 = self._pos
|
||||||
|
self.internalSerial(value, 8, decode=False)
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+8, name, 'Uint8', value))
|
||||||
|
|
||||||
|
def pushSint8(self, value, decode=True):
|
||||||
|
p1 = self._pos
|
||||||
|
self.internalSerial(value, 8, decode=False)
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+8, name, 'Sint8', value))
|
||||||
|
|
||||||
|
def pushUint64(self, value, decode=True):
|
||||||
|
p1 = self._pos
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
self.internalSerial(value>>32, 32, decode=False)
|
||||||
|
self.internalSerial(value, 32, decode=False)
|
||||||
|
else:
|
||||||
|
self.internalSerial(value, 32, decode=False)
|
||||||
|
self.internalSerial(value>>32, 32, decode=False)
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+64, name, 'Uint64', value))
|
||||||
|
|
||||||
|
def pushSint64(self, value, decode=True):
|
||||||
|
p1 = self._pos
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
self.internalSerial(value>>32, 32, decode=False)
|
||||||
|
self.internalSerial(value, 32, decode=False)
|
||||||
|
else:
|
||||||
|
self.internalSerial(value, 32, decode=False)
|
||||||
|
self.internalSerial(value>>32, 32, decode=False)
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+64, name, 'Sint64', value))
|
||||||
|
|
||||||
|
def pushFloat(self, value, decode=True):
|
||||||
|
p1 = self._pos
|
||||||
|
v = c_float(value).value
|
||||||
|
v1 = struct.pack('f', v)
|
||||||
|
v2 = struct.unpack('<i',v1)[0]
|
||||||
|
self.internalSerial(v2, 32, decode=False)
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+32, name, 'Float', value))
|
||||||
|
|
||||||
|
def pushDouble(self, value, decode=True):
|
||||||
|
p1 = self._pos
|
||||||
|
v = c_double(value).value
|
||||||
|
v1 = struct.pack('d', v)
|
||||||
|
v2 = struct.unpack('<Q',v1)[0]
|
||||||
|
#self.internalSerial(v2, 32)
|
||||||
|
self.internalSerial(v2, 32, decode=False)
|
||||||
|
self.internalSerial(v2 >> 32, 32, decode=False)
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+64, name, 'Float', value))
|
||||||
|
|
||||||
|
def pushChar(self, value, decode=True):
|
||||||
|
p1 = self._pos
|
||||||
|
v = ord(value)
|
||||||
|
self.internalSerial(v, 8, decode=False)
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p1+8, name, 'Char', value))
|
||||||
|
|
||||||
|
def pushString(self, value, decode=True):
|
||||||
|
lenValue = len(value)
|
||||||
|
self.pushUint32(lenValue, decode=True, typeName='String:len')
|
||||||
|
p1 = self._pos
|
||||||
|
for _char in value:
|
||||||
|
self.pushChar(_char, decode=False)
|
||||||
|
p2 = self._pos
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p2, name, 'String', value))
|
||||||
|
|
||||||
|
def pushUString(self, value, decode=True):
|
||||||
|
lenValue = len(value)
|
||||||
|
self.pushUint32(lenValue, decode=True, typeName='UString:len')
|
||||||
|
p1 = self._pos
|
||||||
|
for x in value:
|
||||||
|
_char16bit = ord(x)
|
||||||
|
self.internalSerial(_char16bit, 16, decode=False)
|
||||||
|
p2 = self._pos
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p2, name, 'UString', value))
|
||||||
|
|
||||||
|
def pushArrayUint8(self, value, decode=True):
|
||||||
|
' ex.: pushArrayChar([0,1,3,4]) '
|
||||||
|
p1 = self._pos
|
||||||
|
for i in value:
|
||||||
|
self.pushUint8(i, decode=False)
|
||||||
|
p2 = self._pos
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p2, name, 'ArrayUint8', value))
|
||||||
|
|
||||||
|
def pushBuffer(self, source, decode=True):
|
||||||
|
'''
|
||||||
|
Push BitStream with all byte (extend to byte if necessary)
|
||||||
|
'''
|
||||||
|
p1 = self._pos
|
||||||
|
srcRead = source.getRead()
|
||||||
|
source.putRead(0)
|
||||||
|
for ele in source._tampon:
|
||||||
|
self.pushUint8(ele, decode=False)
|
||||||
|
source.putRead(srcRead)
|
||||||
|
p2 = self._pos
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p2, name, 'Buffer', ''))
|
||||||
|
|
||||||
|
def pushBitStream(self, source, decode=True):
|
||||||
|
p1 = self._pos
|
||||||
|
srcRead = source.getRead()
|
||||||
|
source.putRead(0)
|
||||||
|
need = 8 - (self._pos % 8)
|
||||||
|
if need != 8:
|
||||||
|
self.internalSerial(source.readSerial(need, decode=False), need, decode=False)
|
||||||
|
while source.needRead() >= 8:
|
||||||
|
self.pushUint8(source.readSerial(8, decode=False), decode=False)
|
||||||
|
|
||||||
|
need = source.needRead()
|
||||||
|
if need > 0:
|
||||||
|
self.internalSerial(source.readSerial(need, decode=False), need, decode=False)
|
||||||
|
|
||||||
|
source.putRead(srcRead)
|
||||||
|
p2 = self._pos
|
||||||
|
if decode:
|
||||||
|
frame = inspect.currentframe()
|
||||||
|
frame = inspect.getouterframes(frame)[1]
|
||||||
|
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
|
||||||
|
args = string[string.find('(') + 1:-1].split(',')
|
||||||
|
name = '?'
|
||||||
|
for i in args:
|
||||||
|
if i.find('=') != -1:
|
||||||
|
if i.split('=')[0].strip() == "value":
|
||||||
|
name = i.split('=')[1].strip()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
name = i
|
||||||
|
break
|
||||||
|
name = name.strip().split(' ')[0].strip()
|
||||||
|
self._groupWrite.append((p1, p2, name, '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:
|
||||||
|
print("Error: Stream Overflow - nbits:%d/%d name:'%s' decode:'%s' typeName:'%s' emulate:%s msg:%s" %(nbits, self._pos-self._read, name, str(decode), typeName, str(emulate), self.showAllData()), file=sys.stderr)
|
||||||
|
raise OverflowError
|
||||||
|
if emulate:
|
||||||
|
oldRead = self._read
|
||||||
|
value = 0
|
||||||
|
pos = self._read // 8
|
||||||
|
_FreeBits = 8 - (self._read % 8)
|
||||||
|
v = self._tampon[pos] & ((1 << _FreeBits) - 1)
|
||||||
|
if nbits > _FreeBits:
|
||||||
|
value |= (v << (nbits-_FreeBits))
|
||||||
|
self._read += _FreeBits
|
||||||
|
value |= self.readSerial(nbits - _FreeBits, decode=False)
|
||||||
|
else:
|
||||||
|
value |= (v >> (_FreeBits-nbits))
|
||||||
|
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):
|
||||||
|
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:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def readUint32(self, name, decode=True, typeName='Uint32'):
|
||||||
|
v = self.readSerial(32, name=name, decode=decode, typeName=typeName)
|
||||||
|
return v
|
||||||
|
|
||||||
|
def readSint32(self, name, decode=True):
|
||||||
|
v = self.readSerial(32, name=name, decode=decode, typeName='Sint32')
|
||||||
|
return c_int32(v).value
|
||||||
|
|
||||||
|
def readUint16(self, name, decode=True):
|
||||||
|
v = self.readSerial(16, name=name, decode=decode, typeName='Uint16')
|
||||||
|
return v
|
||||||
|
|
||||||
|
def readSint16(self, name):
|
||||||
|
v = self.readSerial(16, name=name, typeName='Sint16')
|
||||||
|
return c_int16(v).value
|
||||||
|
|
||||||
|
def readUint8(self, name, decode=True, typeName='Uint8'):
|
||||||
|
v = self.readSerial(8, decode=decode, name=name, typeName=typeName)
|
||||||
|
return v
|
||||||
|
|
||||||
|
def readSint8(self, name):
|
||||||
|
v = self.readSerial(8, name=name, typeName='Sint8')
|
||||||
|
return c_int8(v).value
|
||||||
|
|
||||||
|
def readUint64(self, name):
|
||||||
|
p1 = self._read
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
v1 = self.readSerial(32, decode=False)
|
||||||
|
v2 = self.readSerial(32, decode=False)
|
||||||
|
else:
|
||||||
|
v2 = self.readSerial(32, decode=False)
|
||||||
|
v1 = self.readSerial(32, decode=False)
|
||||||
|
v3 = (v1 << 32) | v2
|
||||||
|
self._groupRead.append((p1, p1+64, name, 'Uint64', v3))
|
||||||
|
return v3
|
||||||
|
|
||||||
|
def readSint64(self, name):
|
||||||
|
p1 = self._read
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
v1 = self.readSerial(32, decode=False)
|
||||||
|
v2 = self.readSerial(32, decode=False)
|
||||||
|
else:
|
||||||
|
v2 = self.readSerial(32, decode=False)
|
||||||
|
v1 = self.readSerial(32, decode=False)
|
||||||
|
v3 = (v1 << 32) | v2
|
||||||
|
self._groupRead.append((p1, p1+64, name, 'Sint64', c_int64(v3).value))
|
||||||
|
return c_int64(v3).value
|
||||||
|
|
||||||
|
def readFloat(self, name):
|
||||||
|
p1 = self._read
|
||||||
|
v = self.readSerial(32, name=name, decode=False, typeName='Float')
|
||||||
|
v1 = struct.pack('I', v)
|
||||||
|
v2 = struct.unpack('<f',v1)[0]
|
||||||
|
self._groupRead.append((p1, p1+32, name, 'Float', v2))
|
||||||
|
return v2
|
||||||
|
|
||||||
|
def readDouble(self, name):
|
||||||
|
p1 = self._read
|
||||||
|
v = self.readSerial(32, decode=False)
|
||||||
|
v1 = struct.pack('I', v)
|
||||||
|
w = self.readSerial(32, decode=False)
|
||||||
|
w1 = struct.pack('I', w)
|
||||||
|
x = v1 + w1
|
||||||
|
x1 = struct.unpack('<d', x)[0]
|
||||||
|
self._groupRead.append((p1, p1+64, name, 'Double', x1))
|
||||||
|
return x1
|
||||||
|
|
||||||
|
def readChar(self, name, decode=True):
|
||||||
|
v = self.readUint8(name=name, decode=decode, typeName='Char')
|
||||||
|
return chr(v)
|
||||||
|
|
||||||
|
def readString(self, name):
|
||||||
|
tmp = ''
|
||||||
|
_size = self.readUint32(name + ':size', decode=True)
|
||||||
|
v1 = self._read
|
||||||
|
while _size > 0:
|
||||||
|
x = self.readChar('', decode=False)
|
||||||
|
tmp += x
|
||||||
|
_size -= 1
|
||||||
|
v2 = self._read
|
||||||
|
if v2 > self._pos:
|
||||||
|
raise ValueError
|
||||||
|
if v1 < v2:
|
||||||
|
self._groupRead.append((v1, v2, name + ':string', 'String', tmp))
|
||||||
|
return tmp
|
||||||
|
|
||||||
|
def readUtf8String(self, name):
|
||||||
|
tmp = b''
|
||||||
|
_size = self.readUint32(name + ':size', decode=True)
|
||||||
|
v1 = self._read
|
||||||
|
while _size > 0:
|
||||||
|
x = self.readUint8(name='', decode=False)
|
||||||
|
tmp += bytes(chr(x), encoding='latin1')
|
||||||
|
_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.decode(encoding='utf-8')
|
||||||
|
|
||||||
|
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):
|
||||||
|
ret = []
|
||||||
|
v1 = self._read
|
||||||
|
for i in range(0, size):
|
||||||
|
ret.append(self.readUint8('', decode=False))
|
||||||
|
v2 = self._read
|
||||||
|
self._groupRead.append((v1, v2, name, 'ArrayUint8', ''))
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def readBitStreamUint8(self, size, name):
|
||||||
|
ret = BitStream()
|
||||||
|
v1 = self._read
|
||||||
|
for i in range(0, size):
|
||||||
|
ret.pushUint8(self.readUint8('', decode=False), decode=False)
|
||||||
|
v2 = self._read
|
||||||
|
self._groupRead.append((v1, v2, name, 'StreamUint8', ''))
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def readCont(self, name):
|
||||||
|
ret = BitStream()
|
||||||
|
size = self.readSint32(name = name + ':len', decode=True)
|
||||||
|
v1 = self._read
|
||||||
|
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', ''))
|
||||||
|
return size, ret
|
||||||
|
|
||||||
|
def getNotRead(self):
|
||||||
|
ret = BitStream()
|
||||||
|
readBefore = self._read
|
||||||
|
while self._read < self._pos:
|
||||||
|
if self._pos - self._read >= 8:
|
||||||
|
nsize = 8
|
||||||
|
else:
|
||||||
|
nsize = self._pos - self._read
|
||||||
|
data = self.readSerial(nsize, decode=False)
|
||||||
|
ret.internalSerial(data, nsize, decode=False)
|
||||||
|
self._read = readBefore
|
||||||
|
return ret
|
||||||
|
# ------------------------------------
|
||||||
|
def __str__(self):
|
||||||
|
return ''.join([ chr(x) for x in self._tampon])
|
||||||
|
|
||||||
|
def message(self):
|
||||||
|
# return str(self._pos) + ':' + '.'.join([ format(x, "02x") for x in self._tampon])
|
||||||
|
return str(self._pos) + ':' + '.'.join([ "{0:08b}".format(x) for x in self._tampon])
|
||||||
|
|
||||||
|
def toBytes(self):
|
||||||
|
return bytes( self._tampon )
|
||||||
|
|
||||||
|
def fromBytes(self, data):
|
||||||
|
self._read = 0
|
||||||
|
self._tampon = [int(x) for x in data]
|
||||||
|
self._pos = len(self._tampon) * 8
|
||||||
|
|
||||||
|
def showLastData(self):
|
||||||
|
ret = ""
|
||||||
|
readBefore = self._read
|
||||||
|
while self._read < self._pos:
|
||||||
|
if self._pos - self._read >= 8:
|
||||||
|
nsize = 8
|
||||||
|
else:
|
||||||
|
nsize = self._pos - self._read
|
||||||
|
data = self.readSerial(nsize, decode=False)
|
||||||
|
if nsize == 1:
|
||||||
|
ret += "{0:01b}".format(data)
|
||||||
|
elif nsize == 2:
|
||||||
|
ret += "{0:02b}".format(data)
|
||||||
|
elif nsize == 3:
|
||||||
|
ret += "{0:03b}".format(data)
|
||||||
|
elif nsize == 4:
|
||||||
|
ret += "{0:04b}".format(data)
|
||||||
|
elif nsize == 5:
|
||||||
|
ret += "{0:05b}".format(data)
|
||||||
|
elif nsize == 6:
|
||||||
|
ret += "{0:06b}".format(data)
|
||||||
|
elif nsize == 7:
|
||||||
|
ret += "{0:07b}".format(data)
|
||||||
|
else:
|
||||||
|
ret += "{0:08b}".format(data)
|
||||||
|
if ret != "":
|
||||||
|
ret += "."
|
||||||
|
ret += "{0:08b}".format(data)
|
||||||
|
self._read = readBefore
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def showAllData(self):
|
||||||
|
ret = ""
|
||||||
|
readBefore = self._read
|
||||||
|
self._read = 0
|
||||||
|
while self._read < self._pos:
|
||||||
|
if self._pos - self._read >= 8:
|
||||||
|
nsize = 8
|
||||||
|
else:
|
||||||
|
nsize = self._pos - self._read
|
||||||
|
data = self.readSerial(nsize, decode=False)
|
||||||
|
if nsize == 1:
|
||||||
|
ret += "{0:01b}".format(data)
|
||||||
|
elif nsize == 2:
|
||||||
|
ret += "{0:02b}".format(data)
|
||||||
|
elif nsize == 3:
|
||||||
|
ret += "{0:03b}".format(data)
|
||||||
|
elif nsize == 4:
|
||||||
|
ret += "{0:04b}".format(data)
|
||||||
|
elif nsize == 5:
|
||||||
|
ret += "{0:05b}".format(data)
|
||||||
|
elif nsize == 6:
|
||||||
|
ret += "{0:06b}".format(data)
|
||||||
|
elif nsize == 7:
|
||||||
|
ret += "{0:07b}".format(data)
|
||||||
|
else:
|
||||||
|
ret += "{0:08b}".format(data)
|
||||||
|
self._read = readBefore
|
||||||
|
ret2 = ""
|
||||||
|
|
||||||
|
last = 0
|
||||||
|
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:] + "}"
|
||||||
|
|
||||||
|
return ret2
|
||||||
|
|
||||||
|
def showAllDataWrite(self):
|
||||||
|
ret = ""
|
||||||
|
readBefore = self._read
|
||||||
|
self._read = 0
|
||||||
|
while self._read < self._pos:
|
||||||
|
if self._pos - self._read >= 8:
|
||||||
|
nsize = 8
|
||||||
|
else:
|
||||||
|
nsize = self._pos - self._read
|
||||||
|
data = self.readSerial(nsize, decode=False)
|
||||||
|
if nsize == 1:
|
||||||
|
ret += "{0:01b}".format(data)
|
||||||
|
elif nsize == 2:
|
||||||
|
ret += "{0:02b}".format(data)
|
||||||
|
elif nsize == 3:
|
||||||
|
ret += "{0:03b}".format(data)
|
||||||
|
elif nsize == 4:
|
||||||
|
ret += "{0:04b}".format(data)
|
||||||
|
elif nsize == 5:
|
||||||
|
ret += "{0:05b}".format(data)
|
||||||
|
elif nsize == 6:
|
||||||
|
ret += "{0:06b}".format(data)
|
||||||
|
elif nsize == 7:
|
||||||
|
ret += "{0:07b}".format(data)
|
||||||
|
else:
|
||||||
|
ret += "{0:08b}".format(data)
|
||||||
|
self._read = readBefore
|
||||||
|
ret2 = ""
|
||||||
|
|
||||||
|
last = 0
|
||||||
|
for x, y, name, typeName, value in self._groupWrite:
|
||||||
|
ret2 += "[<" + str(x) + ':' + str(y-1) + "> " + str(name) + ' (' + typeName + ') : ' + ret[x:y] + ' => ' + str(value) + "]"
|
||||||
|
last = y
|
||||||
|
if last < self._pos:
|
||||||
|
ret2 += "{" + ret[last:] + "}"
|
||||||
|
|
||||||
|
return ret2
|
||||||
|
|
||||||
|
def showAllDataRaw(self):
|
||||||
|
ret = ""
|
||||||
|
readBefore = self._read
|
||||||
|
self._read = 0
|
||||||
|
while self._read < self._pos:
|
||||||
|
if self._pos - self._read >= 8:
|
||||||
|
nsize = 8
|
||||||
|
else:
|
||||||
|
nsize = self._pos - self._read
|
||||||
|
data = self.readSerial(nsize, decode=False)
|
||||||
|
if nsize == 1:
|
||||||
|
ret += "{0:01b}".format(data)
|
||||||
|
elif nsize == 2:
|
||||||
|
ret += "{0:02b}".format(data)
|
||||||
|
elif nsize == 3:
|
||||||
|
ret += "{0:03b}".format(data)
|
||||||
|
elif nsize == 4:
|
||||||
|
ret += "{0:04b}".format(data)
|
||||||
|
elif nsize == 5:
|
||||||
|
ret += "{0:05b}".format(data)
|
||||||
|
elif nsize == 6:
|
||||||
|
ret += "{0:06b}".format(data)
|
||||||
|
elif nsize == 7:
|
||||||
|
ret += "{0:07b}".format(data)
|
||||||
|
else:
|
||||||
|
ret += "{0:08b}".format(data)
|
||||||
|
if ret != "":
|
||||||
|
ret += "."
|
||||||
|
self._read = readBefore
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def getPosInBit(self):
|
||||||
|
return self._pos
|
||||||
|
|
||||||
|
def TestBitStream():
|
||||||
|
a = BitStream()
|
||||||
|
vrai = True
|
||||||
|
a.pushBool(decode=True, value=vrai)
|
||||||
|
a.pushBool(False)
|
||||||
|
a.pushBool(True)
|
||||||
|
a.pushBool(True)
|
||||||
|
a.pushUint32(1234567890)
|
||||||
|
a.pushSint32(-1234567890)
|
||||||
|
a.pushUint16(12345)
|
||||||
|
a.pushSint16(-12345)
|
||||||
|
a.pushUint8(123)
|
||||||
|
a.pushSint8(-123)
|
||||||
|
#-3.4E+38) # 1.2339999675750732)
|
||||||
|
a.pushFloat(-3.3999999521443642e+38)
|
||||||
|
a.pushDouble(-1.7E+308)
|
||||||
|
a.pushUint64(16045690709418696365)
|
||||||
|
a.pushSint64(-1)
|
||||||
|
a.pushChar('a')
|
||||||
|
a.pushString("Test A Faire")
|
||||||
|
print("-" * 40)
|
||||||
|
print(a.showAllData())
|
||||||
|
print('raw:')
|
||||||
|
print(a.showAllDataRaw())
|
||||||
|
print("-" * 20)
|
||||||
|
print("-" * 80)
|
||||||
|
print(a.readBool('a1'))
|
||||||
|
print(a.readBool('a2'))
|
||||||
|
print(a.readBool('a3'))
|
||||||
|
print(a.readBool('a4'))
|
||||||
|
print(a.readUint32('a5'))
|
||||||
|
print(a.readSint32('a6'))
|
||||||
|
print(a.readUint16('a7'))
|
||||||
|
print(a.readSint16('a8'))
|
||||||
|
print(a.readUint8('a9'))
|
||||||
|
print(a.readSint8('a10'))
|
||||||
|
print(a.readFloat('a11'))
|
||||||
|
print(a.readDouble('a12'))
|
||||||
|
print(a.readUint64('a13'))
|
||||||
|
print(a.readSint64('a14'))
|
||||||
|
print(a.readChar('a15'))
|
||||||
|
print(a.readString('a16'))
|
||||||
|
print(a.toBytes())
|
||||||
|
print("-" * 40)
|
||||||
|
print(a.showAllData())
|
||||||
|
print("-" * 80)
|
||||||
|
b = BitStream()
|
||||||
|
b.fromBytes(a.toBytes())
|
||||||
|
print(b.readBool('b1'))
|
||||||
|
print(b.readBool('b2'))
|
||||||
|
print(b.readBool('b3'))
|
||||||
|
print(b.readBool('b4'))
|
||||||
|
print(b.readUint32('b5'))
|
||||||
|
print(b.readSint32('b6'))
|
||||||
|
print(b.readUint16('b7'))
|
||||||
|
print(b.readSint16('b8'))
|
||||||
|
print(b.readUint8('b9'))
|
||||||
|
print(b.readSint8('b10'))
|
||||||
|
print(b.readFloat('b11'))
|
||||||
|
print(b.readDouble('b12'))
|
||||||
|
print(b.readUint64('b13'))
|
||||||
|
print(b.readSint64('b14'))
|
||||||
|
print(b.readChar('b15'))
|
||||||
|
print(b.readString('b16'))
|
||||||
|
print(b.toBytes())
|
||||||
|
print("-" * 40)
|
||||||
|
print(b.showAllData())
|
||||||
|
print("-" * 80)
|
||||||
|
c = BitStream()
|
||||||
|
c.pushBool(True)
|
||||||
|
c.pushBitStream(a)
|
||||||
|
c.pushBitStream(b)
|
||||||
|
print(c.readBool('c1'))
|
||||||
|
print("-" * 80)
|
||||||
|
print(c.readBool('c2'))
|
||||||
|
print(c.readBool('c3'))
|
||||||
|
print(c.readBool('c4'))
|
||||||
|
print(c.readBool('c5'))
|
||||||
|
print(c.readUint32('c6'))
|
||||||
|
print(c.readSint32('c7'))
|
||||||
|
print(c.readUint16('c8'))
|
||||||
|
print(c.readSint16('c9'))
|
||||||
|
print(c.readUint8('c10'))
|
||||||
|
print(c.readSint8('c11'))
|
||||||
|
print(c.readFloat('c12'))
|
||||||
|
print(c.readDouble('c13'))
|
||||||
|
print(c.readUint64('c14'))
|
||||||
|
print(c.readSint64('c15'))
|
||||||
|
print(c.readChar('c16'))
|
||||||
|
print(c.readString('c17'))
|
||||||
|
print(c.toBytes())
|
||||||
|
print("-" * 50)
|
||||||
|
print(c.showAllData())
|
||||||
|
print("-" * 50)
|
||||||
|
print(c.readBool('c18'))
|
||||||
|
print(c.readBool('c19'))
|
||||||
|
print(c.readBool('c20'))
|
||||||
|
print(c.readBool('c21'))
|
||||||
|
print(c.readUint32('c22'))
|
||||||
|
print(c.readSint32('c23'))
|
||||||
|
print(c.readUint16('c24'))
|
||||||
|
print(c.readSint16('c25'))
|
||||||
|
print(c.readUint8('c26'))
|
||||||
|
print(c.readSint8('c27'))
|
||||||
|
print(c.readFloat('c28'))
|
||||||
|
print(c.readDouble('c29'))
|
||||||
|
print(c.readUint64('c30'))
|
||||||
|
print(c.readSint64('c31'))
|
||||||
|
print(c.readChar('c32'))
|
||||||
|
print("-" * 40)
|
||||||
|
print(c.showAllData())
|
||||||
|
print(c.readString('c33'))
|
||||||
|
print("-" * 40)
|
||||||
|
print(c.showAllData())
|
||||||
|
print(c.toBytes())
|
||||||
|
print("-" * 40)
|
||||||
|
print(c.showAllDataRaw())
|
||||||
|
print("-" * 20)
|
||||||
|
print(c.showAllData())
|
||||||
|
print("-" * 80)
|
375
tools/CAction.py
Normal file
375
tools/CAction.py
Normal file
|
@ -0,0 +1,375 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CActionFactory
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#from tools import Enum
|
||||||
|
import logging
|
||||||
|
from tools import TPropIndex
|
||||||
|
from tools import TPVPMode
|
||||||
|
|
||||||
|
LOGGER='CActionFactory'
|
||||||
|
INVALID_SLOT = 0xff
|
||||||
|
|
||||||
|
class CAction:
|
||||||
|
def __init__(self, slot, code, world):
|
||||||
|
self.Code = code
|
||||||
|
self.PropertyCode = code
|
||||||
|
self.Slot = slot
|
||||||
|
self._Priority = 1
|
||||||
|
self.Timeout = 0
|
||||||
|
self.GameCycle = 0
|
||||||
|
self.world = world
|
||||||
|
|
||||||
|
def unpack(self, message):
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def pack(self, msgout):
|
||||||
|
if self.Code < 4:
|
||||||
|
modeShort = True
|
||||||
|
msgout.pushBool(modeShort)
|
||||||
|
code = self.Code
|
||||||
|
msgout.internalSerial(self.Code, 2)
|
||||||
|
else:
|
||||||
|
modeShort = False
|
||||||
|
msgout.pushBool(modeShort)
|
||||||
|
code = self.Code
|
||||||
|
msgout.pushUint8(code)
|
||||||
|
|
||||||
|
def serialIn(self, msgin):
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def serialOut(self, msgout):
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def size(self):
|
||||||
|
headerBitSize = 0
|
||||||
|
if self.Code < 4:
|
||||||
|
headerBitSize = 1 + 2
|
||||||
|
else:
|
||||||
|
headerBitSize = 1 + (1 * 8)
|
||||||
|
return headerBitSize
|
||||||
|
|
||||||
|
def getMaxSizeInBit(self):
|
||||||
|
logging.getLogger(LOGGER).debug("New Object but missing method reset")
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def setPriority(self, prio):
|
||||||
|
logging.getLogger(LOGGER).debug("New Object but missing method reset")
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def priority(self):
|
||||||
|
logging.getLogger(LOGGER).debug("New Object but missing method reset")
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def getValue(self):
|
||||||
|
logging.getLogger(LOGGER).debug("New Object but missing method reset")
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def setValue(self, value):
|
||||||
|
logging.getLogger(LOGGER).debug("New Object but missing method reset")
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def isContinuous(self):
|
||||||
|
logging.getLogger(LOGGER).debug("New Object but missing method reset")
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
logging.getLogger(LOGGER).debug("New Object but missing method reset")
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "[%d,%d]" % (self.Code , self.Slot)
|
||||||
|
|
||||||
|
class CActionPosition(CAction):
|
||||||
|
def __init__(self, slot, code, world):
|
||||||
|
super().__init__(slot, code, world)
|
||||||
|
self.Position = [0, 0, 0]
|
||||||
|
self.Position16 = [0, 0, 0]
|
||||||
|
self.IsRelative = False
|
||||||
|
self.Interior = False
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "CActionPosition" + super().__str__() + " x:" + str(self.Position16[0]) + " y:" + str(self.Position16[1]) + " z:" + str(self.Position16[2]) + " IsRelative:" + str(self.IsRelative) + " Interior:" + str(self.Interior)
|
||||||
|
|
||||||
|
def unpack(self, message):
|
||||||
|
self.Position16[0] = message.readUint16('px')
|
||||||
|
self.Position16[1] = message.readUint16('py')
|
||||||
|
self.Position16[2] = message.readUint16('pz')
|
||||||
|
self.IsRelative = (self.Position16[2] & 0x1) != 0
|
||||||
|
self.Interior = (self.Position16[2] & 0x2) != 0
|
||||||
|
|
||||||
|
# message.serialAndLog1( Position16[0] );
|
||||||
|
# message.serialAndLog1( Position16[1] );
|
||||||
|
# message.serialAndLog1( Position16[2] );
|
||||||
|
# IsRelative = (Position16[2] & (uint16)0x1)!=0;
|
||||||
|
# Interior = (Position16[2] & (uint16)0x2)!=0;
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class CActionSync(CAction):
|
||||||
|
def __init__(self, slot, code, world):
|
||||||
|
super().__init__(slot, code, world)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "CActionSync" + super().__str__()
|
||||||
|
|
||||||
|
class CActionDisconnection(CAction):
|
||||||
|
def __init__(self, slot, code, world):
|
||||||
|
super().__init__(slot, code, world)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "CActionDisconnection" + super().__str__()
|
||||||
|
|
||||||
|
class CActionAssociation(CAction):
|
||||||
|
def __init__(self, slot, code, world):
|
||||||
|
super().__init__(slot, code, world)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "CActionAssociation" + super().__str__()
|
||||||
|
|
||||||
|
class CActionDummy(CAction):
|
||||||
|
def __init__(self, slot, code, world):
|
||||||
|
super().__init__(slot, code, world)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "CActionDummy" + super().__str__()
|
||||||
|
|
||||||
|
class CActionLogin(CAction):
|
||||||
|
def __init__(self, slot, code, world):
|
||||||
|
super().__init__(slot, code, world)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "CActionLogin" + super().__str__()
|
||||||
|
|
||||||
|
class CActionTargetSlot(CAction):
|
||||||
|
def __init__(self, slot, code, world):
|
||||||
|
super().__init__(slot, code, world)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "CActionTargetSlot" + super().__str__()
|
||||||
|
|
||||||
|
class CActionGeneric(CAction):
|
||||||
|
def __init__(self, slot, code, world):
|
||||||
|
super().__init__(slot, code, world)
|
||||||
|
self._Message = None
|
||||||
|
self.decoded = False
|
||||||
|
|
||||||
|
def set(self, message):
|
||||||
|
self._Message = message
|
||||||
|
|
||||||
|
def unpack(self, message):
|
||||||
|
size = message.readUint32('size')
|
||||||
|
self._Message = message.readBitStreamUint8(size, 'message')
|
||||||
|
|
||||||
|
def pack(self, msgout):
|
||||||
|
super().pack(msgout)
|
||||||
|
sizeMessage = len(self._Message)
|
||||||
|
msgout.pushUint32(sizeMessage)
|
||||||
|
msgout.pushBuffer(self._Message)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self._Message = None
|
||||||
|
|
||||||
|
def genericAction(self, decodeImpulse, world, cGenericMultiPartTemp):
|
||||||
|
decodeImpulse.execute(self._Message, world)
|
||||||
|
self.decoded = True
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.decoded:
|
||||||
|
return "CActionGeneric" + super().__str__() + ' => ' + self._Message.showAllData()
|
||||||
|
else:
|
||||||
|
return "CActionGeneric" + super().__str__() + "[read:" + self._Message.showAllData() + '/write:' + self._Message.showAllDataWrite() + ']'
|
||||||
|
|
||||||
|
def size(self):
|
||||||
|
size = super().size()
|
||||||
|
if self._Message:
|
||||||
|
return 4 + len(self._Message) * 8 + size
|
||||||
|
else:
|
||||||
|
return 4 + size
|
||||||
|
|
||||||
|
class CActionGenericMultiPart(CAction):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/common/src/game_share/action_generic_multi_part.h # class CActionGenericMultiPart
|
||||||
|
'''
|
||||||
|
def __init__(self, slot, code, world):
|
||||||
|
super().__init__(slot, code, world)
|
||||||
|
self.PartCont = []
|
||||||
|
self.Number = 0
|
||||||
|
self.Part = 0
|
||||||
|
self.NbBlock = 0
|
||||||
|
|
||||||
|
def set(self, number, part, buffer, bytelen, size, nbBlock):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/common/src/game_share/action_generic_multi_part.h # void set (uint8 number, uint16 part, const uint8 *buffer, uint32 bytelen, uint32 size, uint16 nbBlock)
|
||||||
|
'''
|
||||||
|
logging.getLogger(LOGGER).debug("number:%d part:%d bytelen:%d size:%d nbBlock:%d" %(number, part, bytelen, size, nbBlock))
|
||||||
|
start = part*size
|
||||||
|
end = start + size
|
||||||
|
logging.getLogger(LOGGER).debug("start:%d end:%d bytelen:%d" % (start, end, bytelen))
|
||||||
|
if end > bytelen:
|
||||||
|
end = bytelen
|
||||||
|
|
||||||
|
logging.getLogger(LOGGER).debug("start:%d end:%d" % (start, end))
|
||||||
|
self.PartCont = []
|
||||||
|
# memcpy( &PartCont[0], buffer + start, end - start );
|
||||||
|
for i in range(start, end):
|
||||||
|
logging.getLogger(LOGGER).debug("Append : %d/%d" % (i, len(buffer)))
|
||||||
|
self.PartCont.append(buffer[i])
|
||||||
|
self.Number = number
|
||||||
|
self.Part = part
|
||||||
|
self.NbBlock = nbBlock
|
||||||
|
|
||||||
|
def unpack(self, message):
|
||||||
|
self.Number = message.readUint8('Number')
|
||||||
|
self.Part = message.readUint16('Part')
|
||||||
|
self.NbBlock = message.readUint16('NbBlock')
|
||||||
|
|
||||||
|
size = message.readUint32('size')
|
||||||
|
self.PartCont = message.readBitStreamUint8(size, 'PartCont')
|
||||||
|
logging.getLogger(LOGGER).debug("unpack - Number:%d Part:%d NbBlock:%d" % (self.Number, self.Part, self.NbBlock))
|
||||||
|
|
||||||
|
def pack(self, msgout):
|
||||||
|
super().pack(msgout)
|
||||||
|
msgout.pushUint8(self.Number)
|
||||||
|
msgout.pushUint16(self.Part)
|
||||||
|
msgout.pushUint16(self.NbBlock)
|
||||||
|
msgout.pushArrayUint8(self.PartCont)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.PartCont = []
|
||||||
|
self.Number = 0
|
||||||
|
self.Part = 0
|
||||||
|
self.NbBlock = 0
|
||||||
|
|
||||||
|
def genericAction(self, decodeImpulse, world, cGenericMultiPartTemp):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::genericAction (CActionGenericMultiPart *agmp)
|
||||||
|
'''
|
||||||
|
logging.getLogger(LOGGER).debug("Number:%d Part:%d NbBlock:%d" % (self.Number, self.Part, self.NbBlock))
|
||||||
|
cGenericMultiPartTemp.addGenericMultiPartTemp(self.Number)
|
||||||
|
cGenericMultiPartTemp.setGenericMultiPartTemp(self.Number, self.Part, self.NbBlock, self.PartCont, decodeImpulse, world)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
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()
|
||||||
|
bytesize = 1 + 2 + 2 + 4 # header
|
||||||
|
# self.PartCont
|
||||||
|
for ele in self.PartCont:
|
||||||
|
bytesize += len(ele)
|
||||||
|
return bytesize * 8 + size
|
||||||
|
|
||||||
|
|
||||||
|
class CActionSint64(CAction):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/common/src/game_share/action_sint64.cpp
|
||||||
|
|
||||||
|
|
||||||
|
A lire :
|
||||||
|
/home/jerome/Projets/khanat/khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1311 receiveNormalMessage(CBitMemStream &msgin)
|
||||||
|
/home/jerome/Projets/khanat/khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1472 receiveNormalMessage(CBitMemStream &msgin)
|
||||||
|
'''
|
||||||
|
def __init__(self, slot, code, world):
|
||||||
|
super().__init__(slot, code, world)
|
||||||
|
self.value = 0
|
||||||
|
self.NbBits = 0
|
||||||
|
self.PropertyToNbBit = { TPropIndex.TPropIndex.PROPERTY_ORIENTATION: 32,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_SHEET: 52,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_BEHAVIOUR: 48,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_NAME_STRING_ID: 32,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_TARGET_ID: 8,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_MODE: 44,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_VPA: 64,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_VPB: 47,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_VPC: 58,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_ENTITY_MOUNTED_ID: 8 , # slot
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_RIDER_ENTITY_ID: 8 , # slot
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_CONTEXTUAL: 16 ,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_BARS: 32 , # please do not lower it (or tell Olivier: used for forage sources)
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_TARGET_LIST: TPropIndex.USER_DEFINED_PROPERTY_NB_BITS ,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_VISUAL_FX: 11 , # please do not lower it (or tell Olivier: used for forage sources)
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_GUILD_SYMBOL: 60 ,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_GUILD_NAME_ID: 32 ,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_EVENT_FACTION_ID: 32 ,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_PVP_MODE: TPVPMode.NbBits ,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_PVP_CLAN: 32 ,
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_OWNER_PEOPLE: 3 , # 4 races and unknow
|
||||||
|
TPropIndex.TPropIndex.PROPERTY_OUTPOST_INFOS: 16 } # 15+1
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "CActionSint64" + super().__str__()
|
||||||
|
|
||||||
|
def unpack(self, msgin):
|
||||||
|
logging.getLogger(LOGGER).debug("msgin:%s" % msgin.showAllData())
|
||||||
|
self.value = msgin.readUint64('value')
|
||||||
|
logging.getLogger(LOGGER).debug("msgin:%s" % msgin.showAllData())
|
||||||
|
#self.NbBits = msgin.readUint32('NbBits')
|
||||||
|
logging.getLogger(LOGGER).debug("value:%u" % self.value)
|
||||||
|
logging.getLogger(LOGGER).debug("msgin:%s" % msgin.showAllData())
|
||||||
|
|
||||||
|
|
||||||
|
def pack(self, msgout):
|
||||||
|
super().pack(msgout)
|
||||||
|
msgout.pushUint64(self.value)
|
||||||
|
#msgout.pushUint32(self.NbBits)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.value = 0
|
||||||
|
self.NbBits = 0
|
||||||
|
|
||||||
|
|
||||||
|
class CActionBlock:
|
||||||
|
def __init__(self):
|
||||||
|
self.Cycle = 0
|
||||||
|
self.FirstPacket = 0
|
||||||
|
self.Actions = []
|
||||||
|
self.Success = True
|
||||||
|
|
||||||
|
def serial(self, msgout, actionFactory):
|
||||||
|
msgout.pushUint32(self.Cycle)
|
||||||
|
msgout.pushUint8(len(self.Actions))
|
||||||
|
for action in self.Actions:
|
||||||
|
# msgPosBefore = msgout.getPosInBit()
|
||||||
|
actionFactory.pack(action, msgout)
|
||||||
|
# msgPosAfter = msgout.getPosInBit()
|
||||||
|
# actionSize = actionFactory.size(action)
|
||||||
|
|
||||||
|
def writeSerial(self, msgout):
|
||||||
|
msgout.pushUint32(self.Cycle)
|
||||||
|
numberActions = len(self.Actions)
|
||||||
|
msgout.pushUint8(numberActions)
|
||||||
|
for action in self.Actions:
|
||||||
|
action.pack(msgout)
|
||||||
|
|
||||||
|
def insert(self, actions, begin, end):
|
||||||
|
for i in range(0, end):
|
||||||
|
if i>= begin:
|
||||||
|
self.Actions.append(actions[i])
|
||||||
|
|
||||||
|
def eraseToEnd(self, begin):
|
||||||
|
while len(self.Actions) >= begin:
|
||||||
|
self.Actions.pop()
|
||||||
|
|
||||||
|
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]) + "]"
|
||||||
|
|
117
tools/CActionFactory.py
Normal file
117
tools/CActionFactory.py
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CActionFactory
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from tools import Enum
|
||||||
|
from tools import CAction
|
||||||
|
|
||||||
|
LOGGER='CActionFactory'
|
||||||
|
|
||||||
|
class CActionFactory:
|
||||||
|
def __init__(self, world):
|
||||||
|
self.world = world
|
||||||
|
self.RegisteredAction = {}
|
||||||
|
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_POSITION_CODE, [])
|
||||||
|
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_GENERIC_CODE, [])
|
||||||
|
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_GENERIC_MULTI_PART_CODE, [])
|
||||||
|
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_SINT64, [])
|
||||||
|
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_SYNC_CODE, [])
|
||||||
|
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_DISCONNECTION_CODE, [])
|
||||||
|
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_ASSOCIATION_CODE, [])
|
||||||
|
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_LOGIN_CODE, [])
|
||||||
|
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_TARGET_SLOT_CODE, [])
|
||||||
|
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_DUMMY_CODE, [])
|
||||||
|
|
||||||
|
def createFactory(self, slot, code):
|
||||||
|
if code == Enum.TActionCode.ACTION_POSITION_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Create CActionPosition")
|
||||||
|
return CAction.CActionPosition(slot, code, self.world)
|
||||||
|
elif code == Enum.TActionCode.ACTION_GENERIC_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Create CActionGeneric")
|
||||||
|
return CAction.CActionGeneric(slot, code, self.world)
|
||||||
|
elif code == Enum.TActionCode.ACTION_GENERIC_MULTI_PART_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Create CActionGenericMultiPart")
|
||||||
|
return CAction.CActionGenericMultiPart(slot, code, self.world)
|
||||||
|
elif code == Enum.TActionCode.ACTION_SINT64:
|
||||||
|
logging.getLogger(LOGGER).debug("Create CActionSint64")
|
||||||
|
return CAction.CActionSint64(slot, code, self.world)
|
||||||
|
elif code == Enum.TActionCode.ACTION_SYNC_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Create CActionSync")
|
||||||
|
return CAction.CActionSync(slot, code, self.world)
|
||||||
|
elif code == Enum.TActionCode.ACTION_DISCONNECTION_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Create CActionDisconnection")
|
||||||
|
return CAction.CActionDisconnection(slot, code, self.world)
|
||||||
|
elif code == Enum.TActionCode.ACTION_ASSOCIATION_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Create CActionAssociation")
|
||||||
|
return CAction.CActionAssociation(slot, code, self.world)
|
||||||
|
elif code == Enum.TActionCode.ACTION_LOGIN_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Create CActionLogin")
|
||||||
|
return CAction.CActionLogin(slot, code, self.world)
|
||||||
|
elif code == Enum.TActionCode.ACTION_TARGET_SLOT_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Create CActionTargetSlot")
|
||||||
|
return CAction.CActionTargetSlot(slot, code, self.world)
|
||||||
|
elif code == Enum.TActionCode.ACTION_DUMMY_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Create CActionDummy")
|
||||||
|
return CAction.CActionDummy(slot, code, self.world)
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning('create() try to create an unknown action (%u)' % code)
|
||||||
|
raise RuntimeError
|
||||||
|
|
||||||
|
def create(self, slot, code):
|
||||||
|
if code not in self.RegisteredAction:
|
||||||
|
logging.getLogger(LOGGER).warning('try to create an unknown action (code:%u)' % code)
|
||||||
|
raise None
|
||||||
|
elif not self.RegisteredAction[code]:
|
||||||
|
logging.getLogger(LOGGER).debug('new CAction (code:%u)' % code)
|
||||||
|
action = self.createFactory(slot, code)
|
||||||
|
action.reset()
|
||||||
|
return action
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug("update CAction")
|
||||||
|
action = self.RegisteredAction[code][-1]
|
||||||
|
action.reset()
|
||||||
|
action.PropertyCode = code
|
||||||
|
action.Slot = slot
|
||||||
|
return action
|
||||||
|
|
||||||
|
def unpack(self, msgin):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/common/src/game_share/action_factory.cpp : CAction *CActionFactory::unpack (NLMISC::CBitMemStream &message, NLMISC::TGameCycle /* currentCycle */ )
|
||||||
|
'''
|
||||||
|
if msgin.needRead() >= 8:
|
||||||
|
shortcode = msgin.readBool('shortcode')
|
||||||
|
if shortcode:
|
||||||
|
code = msgin.readSerial(2, 'code')
|
||||||
|
else:
|
||||||
|
code = msgin.readUint8('code')
|
||||||
|
action = self.create(CAction.INVALID_SLOT, code)
|
||||||
|
if action:
|
||||||
|
try:
|
||||||
|
action.unpack (msgin);
|
||||||
|
except RuntimeError:
|
||||||
|
log = logging.getLogger('myLogger')
|
||||||
|
log.warning('Missing code to unpack (code :%u)' % code)
|
||||||
|
raise RuntimeError
|
||||||
|
else:
|
||||||
|
log = logging.getLogger('myLogger')
|
||||||
|
log.warning('Unpacking an action with unknown code, skip it (%u)' % code)
|
||||||
|
return action
|
||||||
|
|
||||||
|
|
319
tools/CArg.py
Normal file
319
tools/CArg.py
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CArg
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from ctypes import *
|
||||||
|
from tools import Enum
|
||||||
|
|
||||||
|
# #####################################################
|
||||||
|
# persistent_data.h:140 # struct CArg
|
||||||
|
# #####################################################
|
||||||
|
class CArgV1(Structure):
|
||||||
|
_fields_ = [("i32_1", c_uint),
|
||||||
|
("i32_2", c_uint)]
|
||||||
|
|
||||||
|
|
||||||
|
class CArgV2(Structure):
|
||||||
|
_fields_ = [("ex32_1", c_uint),
|
||||||
|
("ex32_2", c_uint)]
|
||||||
|
|
||||||
|
|
||||||
|
class CArgV3(Union):
|
||||||
|
_fields_ = [("ex32", CArgV2),
|
||||||
|
("ExData32", c_uint),
|
||||||
|
("ExData64", c_ulong)]
|
||||||
|
|
||||||
|
|
||||||
|
class CArgV4(Structure):
|
||||||
|
_fields_ = [("ExType", c_uint),
|
||||||
|
("ex", CArgV3)]
|
||||||
|
|
||||||
|
|
||||||
|
class CArgV5(Union):
|
||||||
|
_fields_ = [("i", CArgV1),
|
||||||
|
("ii32", c_int),
|
||||||
|
("ii64", c_long),
|
||||||
|
("i32", c_uint),
|
||||||
|
("i64", c_ulong),
|
||||||
|
("f32", c_float),
|
||||||
|
("f64", c_double),
|
||||||
|
("ex", CArgV4)]
|
||||||
|
|
||||||
|
class CArg:
|
||||||
|
# union
|
||||||
|
# {
|
||||||
|
# struct
|
||||||
|
# {
|
||||||
|
# uint32 i32_1;
|
||||||
|
# uint32 i32_2;
|
||||||
|
# } i;
|
||||||
|
#
|
||||||
|
# sint32 i32;
|
||||||
|
# sint64 i64;
|
||||||
|
# float f32;
|
||||||
|
# double f64;
|
||||||
|
#
|
||||||
|
# struct
|
||||||
|
# {
|
||||||
|
# uint32 ExType;
|
||||||
|
# union
|
||||||
|
# {
|
||||||
|
# struct
|
||||||
|
# {
|
||||||
|
# uint32 ex32_1;
|
||||||
|
# uint32 ex32_2;
|
||||||
|
# };
|
||||||
|
#
|
||||||
|
# uint32 ExData32;
|
||||||
|
# uint64 ExData64;
|
||||||
|
# } ex;
|
||||||
|
# } ex;
|
||||||
|
# } _Value;
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._value = CArgV5()
|
||||||
|
self._value.ii64 = 0
|
||||||
|
self._value.i64 = 0
|
||||||
|
self._type = 0
|
||||||
|
self._string = 0
|
||||||
|
self._type64 = False
|
||||||
|
|
||||||
|
def read_Type(self):
|
||||||
|
return self._type
|
||||||
|
|
||||||
|
def write_Type(self, value):
|
||||||
|
self._type = value
|
||||||
|
|
||||||
|
def write_Type64(self, value):
|
||||||
|
self._type64 = value
|
||||||
|
|
||||||
|
def read_String(self):
|
||||||
|
return self._string
|
||||||
|
|
||||||
|
def write_String(self, value):
|
||||||
|
self._string = value
|
||||||
|
|
||||||
|
def read_i32_1(self):
|
||||||
|
return self._value.i.i32_1
|
||||||
|
|
||||||
|
def write_i32_1(self, value):
|
||||||
|
self._value.i.i32_1 = value
|
||||||
|
|
||||||
|
def read_i32_2(self):
|
||||||
|
return self._value.i.i32_2
|
||||||
|
|
||||||
|
def write_i32_2(self, value):
|
||||||
|
self._value.i.i32_2 = value
|
||||||
|
|
||||||
|
def read_i32(self):
|
||||||
|
return self._value.i32
|
||||||
|
|
||||||
|
def write_i32(self, value):
|
||||||
|
self._value.i32 = value
|
||||||
|
|
||||||
|
def read_i64(self):
|
||||||
|
return self._value.i64
|
||||||
|
|
||||||
|
def write_i64(self, value):
|
||||||
|
self._value.i64 = value
|
||||||
|
|
||||||
|
def read_f32(self):
|
||||||
|
return self._value.f32
|
||||||
|
|
||||||
|
def write_f32(self, value):
|
||||||
|
self._value.f32 = value
|
||||||
|
|
||||||
|
def read_f64(self):
|
||||||
|
return self._value.f64
|
||||||
|
|
||||||
|
def write_f64(self, value):
|
||||||
|
self._value.f64 = value
|
||||||
|
|
||||||
|
def read_ExType(self):
|
||||||
|
return self._value.ex.ExType
|
||||||
|
|
||||||
|
def write_ExType(self, value):
|
||||||
|
self._value.ex.ExType = value
|
||||||
|
|
||||||
|
def read_ex32_1(self):
|
||||||
|
return self._value.ex.ex.ex32.ex32_1
|
||||||
|
|
||||||
|
def write_ex32_1(self, value):
|
||||||
|
self._value.ex.ex.ex32.ex32_1 = value
|
||||||
|
|
||||||
|
def read_ex32_2(self):
|
||||||
|
return self._value.ex.ex.ex32.ex32_2
|
||||||
|
|
||||||
|
def write_ex32_2(self, value):
|
||||||
|
self._value.ex.ex.ex32.ex32_2 = value
|
||||||
|
|
||||||
|
def read_ExData32(self):
|
||||||
|
return self._value.ex.ex.ExData32
|
||||||
|
|
||||||
|
def write_ExData32(self, value):
|
||||||
|
self._value.ex.ex.ExData32 = value
|
||||||
|
|
||||||
|
def read_ExData64(self):
|
||||||
|
return self._value.ex.ex.ExData64
|
||||||
|
|
||||||
|
def write_ExData64(self, value):
|
||||||
|
self._value.ex.ex.ExData64 = value
|
||||||
|
|
||||||
|
def isExtended(self):
|
||||||
|
if self._type == Enum.TType.EXTEND_TYPE:
|
||||||
|
return True
|
||||||
|
elif self._type == Enum.TType.STRUCT_BEGIN:
|
||||||
|
self.log.error("Can't extract a value from a structure delimiter")
|
||||||
|
sys.exit(2)
|
||||||
|
elif self._type == Enum.TType.STRUCT_END:
|
||||||
|
self.log.error("Can't extract a value from a structure delimiter")
|
||||||
|
sys.exit(2)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def isFlag(self):
|
||||||
|
if self._type == Enum.TType.FLAG:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def asUint(self):
|
||||||
|
if self._type == Enum.TType.STRUCT_BEGIN or self._type == Enum.TType.STRUCT_END:
|
||||||
|
self.log.error("Can't extract a value from a structure delimiter")
|
||||||
|
sys.exit(2)
|
||||||
|
elif self._type == Enum.TType.SINT32:
|
||||||
|
return self.read_i32()
|
||||||
|
elif self._type == Enum.TType.UINT32:
|
||||||
|
return self.read_i32()
|
||||||
|
elif self._type == Enum.TType.SINT64:
|
||||||
|
return self.read_i64()
|
||||||
|
elif self._type == Enum.TType.UINT64:
|
||||||
|
return self.read_i64()
|
||||||
|
elif self._type == Enum.TType.FLOAT32:
|
||||||
|
return self.read_i32()
|
||||||
|
elif self._type == Enum.TType.FLOAT64:
|
||||||
|
return self.read_i64()
|
||||||
|
elif self._type == Enum.TType.STRING:
|
||||||
|
return int(self._string)
|
||||||
|
elif self._type == Enum.TType.FLAG:
|
||||||
|
return "1"
|
||||||
|
elif self._type == Enum.TType.EXTEND_TYPE:
|
||||||
|
if self.read_ExType() == TExtendType.ET_SHEET_ID:
|
||||||
|
return self.read_ExData32()
|
||||||
|
elif self.read_ExType() == TExtendType.ET_ENTITY_ID:
|
||||||
|
return self.read_ExData64()
|
||||||
|
log = logging.getLogger('myLogger')
|
||||||
|
log.error("This should never happen!")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
log = logging.getLogger('myLogger')
|
||||||
|
log.debug(self._type)
|
||||||
|
if self._type == Enum.TType.STRUCT_BEGIN or self._type == Enum.TType.STRUCT_END:
|
||||||
|
return ''
|
||||||
|
elif self._type64:
|
||||||
|
# To be confirm for extend
|
||||||
|
return str(self.read_ExData64())
|
||||||
|
elif self._type == Enum.TType.SINT32:
|
||||||
|
return str(self.read_i32())
|
||||||
|
elif self._type == Enum.TType.UINT32:
|
||||||
|
return str(self.read_i32())
|
||||||
|
elif self._type == Enum.TType.SINT64:
|
||||||
|
return str(self.read_i64())
|
||||||
|
elif self._type == Enum.TType.UINT64:
|
||||||
|
return str(self.read_i64())
|
||||||
|
elif self._type == Enum.TType.FLOAT32:
|
||||||
|
return str(self.read_i32())
|
||||||
|
elif self._type == Enum.TType.FLOAT64:
|
||||||
|
return str(self.read_i64())
|
||||||
|
elif self._type == Enum.TType.STRING:
|
||||||
|
return self._string
|
||||||
|
elif self._type == Enum.TType.FLAG:
|
||||||
|
return "1"
|
||||||
|
return '?'
|
||||||
|
|
||||||
|
def asSint(self):
|
||||||
|
self.log.error("TODO")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def asFloat(self):
|
||||||
|
self.log.error("TODO")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def asDouble(self):
|
||||||
|
self.log.error("TODO")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def asString(self):
|
||||||
|
if self._type == Enum.TType.STRUCT_BEGIN or self._type == Enum.TType.STRUCT_END:
|
||||||
|
self.log.error("Can't extract a value from a structure delimiter")
|
||||||
|
sys.exit(2)
|
||||||
|
elif self._type == Enum.TType.SINT32:
|
||||||
|
return str(self.read_ii32())
|
||||||
|
elif self._type == Enum.TType.UINT32:
|
||||||
|
return str(self.read_i32())
|
||||||
|
elif self._type == Enum.TType.SINT64:
|
||||||
|
return str(self.read_ii64())
|
||||||
|
elif self._type == Enum.TType.UINT64:
|
||||||
|
return str(self.read_i64())
|
||||||
|
elif self._type == Enum.TType.FLOAT32:
|
||||||
|
return str(self.read_f32())
|
||||||
|
elif self._type == Enum.TType.FLOAT64:
|
||||||
|
return str(self.read_f64())
|
||||||
|
elif self._type == Enum.TType.STRING:
|
||||||
|
return self._string
|
||||||
|
elif self._type == Enum.TType.FLAG:
|
||||||
|
return "1"
|
||||||
|
elif self._type == Enum.TType.EXTEND_TYPE:
|
||||||
|
self.log.error("TODO")
|
||||||
|
sys.exit(2)
|
||||||
|
# switch(_Value.ExType)
|
||||||
|
# {
|
||||||
|
# case ET_SHEET_ID:
|
||||||
|
# {
|
||||||
|
# NLMISC::CSheetId sheetId(_Value.ExData32);
|
||||||
|
# return sheetId.toString(true);
|
||||||
|
# }
|
||||||
|
# case ET_ENTITY_ID:
|
||||||
|
# {
|
||||||
|
# NLMISC::CEntityId entityId(_Value.ExData64);
|
||||||
|
# return entityId.toString();
|
||||||
|
# }
|
||||||
|
# default:
|
||||||
|
# break;
|
||||||
|
# }
|
||||||
|
self.log.error("This should never happen!")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def asUCString(self):
|
||||||
|
self.log.error("TODO")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def asEntityId(self):
|
||||||
|
self.log.error("TODO")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def asSheetId(self):
|
||||||
|
self.log.error("TODO")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def typeName(self):
|
||||||
|
self.log.error("TODO")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
# #####################################################
|
33
tools/CBNPCategorySet.py
Normal file
33
tools/CBNPCategorySet.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CBNPCategorySet
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
class CBNPCategorySet:
|
||||||
|
def __init__(self):
|
||||||
|
self._Name = ""
|
||||||
|
self._IsOptional = False
|
||||||
|
self._UnpackTo = ""
|
||||||
|
self._IsIncremental = False
|
||||||
|
self._CatRequired = ""
|
||||||
|
self._Hidden = False
|
||||||
|
self._Files = []
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self._Name + ' (IsOptional:' + str(self._IsOptional) + ', UnpackTo:' + self._UnpackTo + ', IsIncremental:' + str(self._IsIncremental) + ', CatRequired:' + self._CatRequired + ', Hidden:' + str(self._Hidden) + ', Files:' + str(self._Files) + ')'
|
||||||
|
|
32
tools/CBNPFile.py
Normal file
32
tools/CBNPFile.py
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CBNPFile
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
class CBNPFile:
|
||||||
|
def __init__(self):
|
||||||
|
self.FileName = None
|
||||||
|
self.Versions = []
|
||||||
|
self.IsIncremental = False
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.FileName) +' (' + ', '.join( [str(x) for x in self.Versions]) + ')'
|
||||||
|
|
||||||
|
def update(self, FileName):
|
||||||
|
self.FileName = FileName
|
||||||
|
|
32
tools/CBNPFileVersion.py
Normal file
32
tools/CBNPFileVersion.py
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CBNPFileVersion
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
class CBNPFileVersion:
|
||||||
|
def __init__(self):
|
||||||
|
self.VersionNumber = None
|
||||||
|
self.FileTime = None
|
||||||
|
self.FileSize = None
|
||||||
|
self.v7ZFileSize = None
|
||||||
|
self.PatchSize = None
|
||||||
|
self.HashKey = []
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "VersionNumber:" + str(self.VersionNumber) + ", FileTime:" + str(self.FileTime) + ", FileSize:" + str(self.FileSize) + ", 7ZFileSize:" + str(self.v7ZFileSize) + ", PatchSize:" + str(self.PatchSize) + ", HashKey:" + str(self.HashKey)
|
||||||
|
|
110
tools/CBitSet.py
Normal file
110
tools/CBitSet.py
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CBitSet
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
class CBitSet:
|
||||||
|
def __init__(self, NL_BITLEN=32):
|
||||||
|
self.NumBits = 0
|
||||||
|
self.MaskLast = 0
|
||||||
|
self.NL_BITLEN = NL_BITLEN
|
||||||
|
self.data = self.resize(1024)
|
||||||
|
|
||||||
|
def resize(self, numBits):
|
||||||
|
self.data = [ 0 for _ in range(0, (numBits + self.NL_BITLEN - 1) // self.NL_BITLEN) ]
|
||||||
|
self.NumBits = numBits
|
||||||
|
nLastBits = self.NumBits & (self.NL_BITLEN-1)
|
||||||
|
if nLastBits == 0:
|
||||||
|
self.MaskLast = ~0
|
||||||
|
else:
|
||||||
|
self.MaskLast = (1 << nLastBits)-1
|
||||||
|
self.clearAll()
|
||||||
|
|
||||||
|
def clearData(self):
|
||||||
|
self.data = []
|
||||||
|
self.NumBits = 0
|
||||||
|
self.MaskLast = 0
|
||||||
|
|
||||||
|
def clearAll(self):
|
||||||
|
for i in range(0, len(self.data)):
|
||||||
|
self.data[i] = 0
|
||||||
|
|
||||||
|
def set(self, bitNumber, value):
|
||||||
|
#logging.getLogger('myLogger').debug("CBitSet::set %d %s" % (bitNumber, str(value)))
|
||||||
|
mask = bitNumber & (self.NL_BITLEN-1)
|
||||||
|
mask = 1 << mask
|
||||||
|
if value:
|
||||||
|
self.data[bitNumber >> 5] |= mask
|
||||||
|
else:
|
||||||
|
self.data[bitNumber >> 5] &= ~mask
|
||||||
|
|
||||||
|
def get(self, bitNumber):
|
||||||
|
mask= bitNumber&(self.NL_BITLEN-1);
|
||||||
|
mask= 1<<mask;
|
||||||
|
return self.data[bitNumber >> 5] & mask != 0
|
||||||
|
|
||||||
|
def setBit(self, bitNumber):
|
||||||
|
self.set(bitNumber, True)
|
||||||
|
|
||||||
|
def clearBit(self, bitNumber):
|
||||||
|
self.set(bitNumber, False)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '.'.join([hex(x) for x in self.data])
|
||||||
|
def writeSerial(self, msgout):
|
||||||
|
# v = 0 # currentVersion
|
||||||
|
# if v >= 0xff:
|
||||||
|
# msgout.pushUint8(0xff)
|
||||||
|
# msgout.pushUint8(v)
|
||||||
|
# else:
|
||||||
|
# msgout.pushUint8(v)
|
||||||
|
|
||||||
|
#log = logging.getLogger('myLogger')
|
||||||
|
#log.debug("CBitSet::writeSerial NumBits:%d len:%d" % (self.NumBits, len(self.data)))
|
||||||
|
|
||||||
|
currentVersion = 0
|
||||||
|
msgout.pushUint8(currentVersion)
|
||||||
|
msgout.pushUint32(self.NumBits)
|
||||||
|
# il est lié à 'self.NumBits' dommage que l'on envoie celui-la
|
||||||
|
msgout.pushUint32(len(self.data))
|
||||||
|
for x in self.data:
|
||||||
|
msgout.pushUint32(x)
|
||||||
|
|
||||||
|
def readSerial(self, msgin, name):
|
||||||
|
_ = msgin.readSint8(name+':currentVersion')
|
||||||
|
NumBits = msgin.readUint32(name+':NumBits')
|
||||||
|
Size = msgin.readUint32(name+':Size')
|
||||||
|
self.resize(NumBits)
|
||||||
|
for i in range(0, Size):
|
||||||
|
y = msgin.readUint32( name+':Data' )
|
||||||
|
self.data[i] = y
|
||||||
|
|
||||||
|
def TestCBitSet():
|
||||||
|
cBitSet = CBitSet()
|
||||||
|
cBitSet.resize(1024)
|
||||||
|
cBitSet.set(1, True)
|
||||||
|
cBitSet.set(3, True)
|
||||||
|
cBitSet.set(2, False)
|
||||||
|
cBitSet.set(13, True)
|
||||||
|
cBitSet.set(128, True)
|
||||||
|
cBitSet.set(1023, True)
|
||||||
|
print(cBitSet)
|
||||||
|
print(cBitSet.get(3))
|
||||||
|
cBitSet.set(3, False)
|
||||||
|
print(cBitSet)
|
||||||
|
print(cBitSet.get(3))
|
146
tools/CCharacterSummary.py
Normal file
146
tools/CCharacterSummary.py
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CCharacterSummary
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from tools import Enum
|
||||||
|
from tools import convertUStringToString
|
||||||
|
|
||||||
|
class SPropVisualA():
|
||||||
|
def __init__(self):
|
||||||
|
'''
|
||||||
|
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
|
||||||
|
|
||||||
|
def read(self, msgin):
|
||||||
|
self.Sex = msgin.readBool('Sex')
|
||||||
|
self.JacketModel = msgin.readUint8('JacketModel')
|
||||||
|
self.JacketColor = msgin.readSerial(3, 'JacketModel')
|
||||||
|
self.TrouserModel = msgin.readSerial(8, 'TrouserModel')
|
||||||
|
self.TrouserColor = msgin.readSerial(3, 'TrouserColor')
|
||||||
|
self.WeaponRightHand = msgin.readSerial(10, 'WeaponRightHand')
|
||||||
|
self.WeaponLeftHand = msgin.readSerial(8, 'WeaponLeftHand')
|
||||||
|
self.ArmModel = msgin.readSerial(8, 'ArmModel')
|
||||||
|
self.ArmColor = msgin.readSerial(3, 'ArmColor')
|
||||||
|
self.HatModel = msgin.readSerial(9, 'HatModel')
|
||||||
|
self.HatColor = msgin.readSerial(3, 'HatColor')
|
||||||
|
|
||||||
|
|
||||||
|
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.LTrail = 0 #: 3;
|
||||||
|
self.NotUsed = 0 # 17 : # not used -> just to complete 64 bit
|
||||||
|
def read(self, msgin):
|
||||||
|
self.Name = msgin.readSerial(16, 'Name')
|
||||||
|
self.HandsModel = msgin.readSerial(9, 'HandsModel')
|
||||||
|
self.HandsColor = msgin.readSerial(3, 'HandsColor')
|
||||||
|
self.FeetModel = msgin.readSerial(9, 'FeetModel')
|
||||||
|
self.FeetColor = msgin.readSerial(3, 'FeetColor')
|
||||||
|
self.RTrail = msgin.readSerial(4, 'RTrail')
|
||||||
|
self.LTrail = msgin.readSerial(3, 'LTrail')
|
||||||
|
self.NotUsed = msgin.readSerial(17, 'NotUsed')
|
||||||
|
|
||||||
|
|
||||||
|
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.NotUsed = 0 # 10 : # not used -> just to complete 64 bit
|
||||||
|
def read(self, msgin):
|
||||||
|
self.MorphTarget1 = msgin.readSerial(3, 'MorphTarget1')
|
||||||
|
self.MorphTarget2 = msgin.readSerial(3, 'MorphTarget2')
|
||||||
|
self.MorphTarget3 = msgin.readSerial(3, 'MorphTarget3')
|
||||||
|
self.MorphTarget4 = msgin.readSerial(3, 'MorphTarget4')
|
||||||
|
self.MorphTarget5 = msgin.readSerial(3, 'MorphTarget5')
|
||||||
|
self.MorphTarget6 = msgin.readSerial(3, 'MorphTarget6')
|
||||||
|
self.MorphTarget7 = msgin.readSerial(3, 'MorphTarget7')
|
||||||
|
self.MorphTarget8 = msgin.readSerial(3, 'MorphTarget8')
|
||||||
|
self.EyesColor = msgin.readSerial(3, 'EyesColor')
|
||||||
|
self.Tattoo = msgin.readSerial(7, 'Tattoo')
|
||||||
|
self.CharacterHeight = msgin.readSerial(4, 'CharacterHeight')
|
||||||
|
self.TorsoWidth = msgin.readSerial(4, 'TorsoWidth')
|
||||||
|
self.ArmsWidth = msgin.readSerial(4, 'ArmsWidth')
|
||||||
|
self.LegsWidth = msgin.readSerial(4, 'LegsWidth')
|
||||||
|
self.BreastSize = msgin.readSerial(4, 'BreastSize')
|
||||||
|
self.NotUsed = msgin.readSerial(10, 'NotUsed')
|
||||||
|
|
||||||
|
class CCharacterSummary():
|
||||||
|
def __init__(self):
|
||||||
|
self.version = -1
|
||||||
|
self.Mainland = 0 # CSessionId
|
||||||
|
self.Name = ""
|
||||||
|
self.People = Enum.TPeople.Unknown
|
||||||
|
self.Location = 0
|
||||||
|
self.sPropVisualA = SPropVisualA()
|
||||||
|
self.sPropVisualB = SPropVisualB()
|
||||||
|
self.sPropVisualC = SPropVisualC()
|
||||||
|
self.sheetId = 0
|
||||||
|
self.Title = Enum.ECharacterTitle.NB_CHARACTER_TITLE
|
||||||
|
self.CharacterSlot = 255
|
||||||
|
self.InRingSession = False
|
||||||
|
self.HasEditSession = False
|
||||||
|
self.InNewbieland = False
|
||||||
|
|
||||||
|
def read(self, msgin):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/common/src/game_share/character_summary.cpp # void CCharacterSummary::serial(NLMISC::IStream &f)
|
||||||
|
'''
|
||||||
|
self.version = msgin.readUint8('version')
|
||||||
|
self.Mainland = msgin.readUint32('Mainland')
|
||||||
|
self.Name = convertUStringToString.convertUStringToString(msgin.readUString('Name'))
|
||||||
|
self.People = msgin.readSint32('People')
|
||||||
|
self.Location = msgin.readUint32('Location')
|
||||||
|
self.sPropVisualA.read(msgin)
|
||||||
|
self.sPropVisualB.read(msgin)
|
||||||
|
self.sPropVisualC.read(msgin)
|
||||||
|
self.sheetId = msgin.readUint32('SheetId')
|
||||||
|
self.Title = msgin.readSint32('Title') # see ECharacterTitle
|
||||||
|
self.CharacterSlot = msgin.readUint8('CharacterSlot')
|
||||||
|
self.InRingSession = msgin.readBool('InRingSession')
|
||||||
|
self.HasEditSession = msgin.readBool('HasEditSession')
|
||||||
|
self.InNewbieland = msgin.readBool('InNewbieland')
|
28
tools/CFileChild.py
Normal file
28
tools/CFileChild.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CFileChild
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
class CFileChild():
|
||||||
|
def __init__(self, name, pos, size):
|
||||||
|
self.name = name
|
||||||
|
self.pos = pos
|
||||||
|
self.size = size
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name + '(pos:' + str(self.pos) + ', size:' + str(self.size) + ')'
|
79
tools/CFileContainer.py
Normal file
79
tools/CFileContainer.py
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CFileContainer
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from tools import CFileList
|
||||||
|
|
||||||
|
|
||||||
|
class CFileContainer():
|
||||||
|
def __init__(self):
|
||||||
|
self.log = logging.getLogger('myLogger')
|
||||||
|
self.list = []
|
||||||
|
|
||||||
|
def addSearchPath(self, path):
|
||||||
|
if not path:
|
||||||
|
return
|
||||||
|
self.log.debug("read path:" + str(path))
|
||||||
|
onlyfiles = [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]
|
||||||
|
self.log.debug("read files:" + ','.join(onlyfiles))
|
||||||
|
for filename in onlyfiles:
|
||||||
|
extension = os.path.splitext(filename)[1]
|
||||||
|
if extension == '.bnp':
|
||||||
|
# Container for multi file
|
||||||
|
fullpath = os.path.join(path, filename)
|
||||||
|
size = os.path.getsize(fullpath)
|
||||||
|
data = CFileList.CFileList(filename, fullpath)
|
||||||
|
with open(fullpath, 'rb') as fp:
|
||||||
|
fp.seek(size-4)
|
||||||
|
nOffsetFromBeginning = int.from_bytes(fp.read(4), byteorder='little', signed=False)
|
||||||
|
self.log.debug("[%s] nOffsetFromBeginning:%u" % (filename, nOffsetFromBeginning))
|
||||||
|
fp.seek(nOffsetFromBeginning)
|
||||||
|
nNbFile = int.from_bytes(fp.read(4), byteorder='little', signed=False)
|
||||||
|
self.log.debug("[%s] nNbFile:%u" % (filename, nNbFile))
|
||||||
|
for i in range(0, nNbFile):
|
||||||
|
nStringSize = int.from_bytes(fp.read(1), byteorder='little', signed=False)
|
||||||
|
FileName = fp.read(nStringSize).decode()
|
||||||
|
nFileSize2 = int.from_bytes(fp.read(4), byteorder='little', signed=False)
|
||||||
|
|
||||||
|
nFilePos = int.from_bytes(fp.read(4), byteorder='little', signed=False)
|
||||||
|
self.log.debug("[%s] (%d) sizestring:%d file:%s size2:%d pos:%d" % (filename, i, nStringSize, FileName, nFileSize2, nFilePos))
|
||||||
|
data.addchild(FileName, nFilePos, nFileSize2)
|
||||||
|
fp.close()
|
||||||
|
self.list.append(data)
|
||||||
|
|
||||||
|
def search(self, name):
|
||||||
|
for x in self.list:
|
||||||
|
for y in x.child:
|
||||||
|
if y.name == name:
|
||||||
|
self.log.debug("file:%s child:%s pos:%d size:%d", x.name, y.name, y.pos, y.size)
|
||||||
|
return x.fullpath, y.pos, y.size
|
||||||
|
self.log.debug('-'*80)
|
||||||
|
return None, None, None
|
||||||
|
|
||||||
|
def getdata(self, name):
|
||||||
|
fullpath, pos, size = self.search(name)
|
||||||
|
self.log.debug("file:%s pos:%d size:%d", fullpath, pos, size)
|
||||||
|
data = None
|
||||||
|
with open(fullpath, 'rb') as fp:
|
||||||
|
fp.seek(pos)
|
||||||
|
data = fp.read(size)
|
||||||
|
fp.close()
|
||||||
|
return data
|
34
tools/CFileList.py
Normal file
34
tools/CFileList.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CFileList
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from tools import CFileChild
|
||||||
|
|
||||||
|
class CFileList():
|
||||||
|
def __init__(self, name, fullpath):
|
||||||
|
self.name = name
|
||||||
|
self.fullpath = fullpath
|
||||||
|
self.child = []
|
||||||
|
|
||||||
|
def addchild(self, name, pos, size):
|
||||||
|
child = CFileChild.CFileChild(name, pos, size)
|
||||||
|
self.child.append(child)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name + '[' + ', '.join([str(x) for x in self.child]) + ']'
|
91
tools/CGenericMultiPartTemp.py
Normal file
91
tools/CGenericMultiPartTemp.py
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CGenericMultiPartTemp
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from tools import BitStream
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
def set(self, Number, Part, NbBlock, PartCont, decodeImpulse, world):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::CGenericMultiPartTemp::set (CActionGenericMultiPart *agmp, CNetworkConnection *parent)
|
||||||
|
'''
|
||||||
|
logging.getLogger(LOGGER).debug("set Number:%d Part:%d NbBlock:%d" % (Number, Part, NbBlock))
|
||||||
|
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).warning('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:
|
||||||
|
# reform the total action
|
||||||
|
bms = BitStream.BitStream()
|
||||||
|
|
||||||
|
self.NbBlock == 0xFFFFFFFF
|
||||||
|
for data in self.Temp:
|
||||||
|
bms.pushBitStream(data)
|
||||||
|
decodeImpulse.execute(bms, world)
|
||||||
|
logging.getLogger(LOGGER).debug("CGenericMultiPartTemp : data : %s" % bms.showAllData())
|
||||||
|
self.MsgDecoded = bms
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug("CGenericMultiPartTemp : Wait other block")
|
||||||
|
|
||||||
|
def isAvailable(self):
|
||||||
|
if self.MsgDecoded and not self.FirstRead:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
self.FirstRead = True
|
||||||
|
return self.MsgDecoded
|
||||||
|
|
||||||
|
|
||||||
|
class GenericMultiPartTemp():
|
||||||
|
def __init__(self):
|
||||||
|
self.data = {}
|
||||||
|
|
||||||
|
def addGenericMultiPartTemp(self, Number):
|
||||||
|
self.data.setdefault(Number, CGenericMultiPartTemp())
|
||||||
|
|
||||||
|
def setGenericMultiPartTemp(self, Number, Part, NbBlock, PartCont, decodeImpulse, world):
|
||||||
|
self.data[Number].set(Number, Part, NbBlock, PartCont, decodeImpulse, world)
|
31
tools/CI18N.py
Normal file
31
tools/CI18N.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CI18N
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# Data from ryzom/tools/translation/translated/[en|fr|...].uxt
|
||||||
|
|
||||||
|
class CI18N:
|
||||||
|
def __init__(self):
|
||||||
|
self.message = {}
|
||||||
|
self.message.setdefault("uiMissionTimerHour", "[h]")
|
||||||
|
self.message.setdefault("uiMissionTimerMinute", "[m]")
|
||||||
|
self.message.setdefault("uiMissionTimerSecond", "[s]")
|
||||||
|
|
||||||
|
def get(self, key):
|
||||||
|
return self.message[key]
|
89
tools/CImpulseDecoder.py
Normal file
89
tools/CImpulseDecoder.py
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CImpulseDecoder
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import copy
|
||||||
|
from tools import CActionFactory
|
||||||
|
|
||||||
|
LOGGER='CImpulseDecoder'
|
||||||
|
|
||||||
|
class CImpulseDecoder:
|
||||||
|
'''
|
||||||
|
see : khanat-opennel-code/code/ryzom/client/src/impulse_decoder.cpp
|
||||||
|
'''
|
||||||
|
def __init__(self, world):
|
||||||
|
self.world = world
|
||||||
|
self.reset()
|
||||||
|
self._CActionFactory = CActionFactory.CActionFactory(world)
|
||||||
|
|
||||||
|
def removeCAction(self, action):
|
||||||
|
self._CActionFactory.RegisteredAction[action.Code].append(action)
|
||||||
|
|
||||||
|
def decode(self, msgin, receivedPacket, receivedAck, nextSentPacket):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/impulse_decoder.cpp:38 oid CImpulseDecoder::decode(CBitMemStream &inbox, TPacketNumber receivedPacket, TPacketNumber receivedAck, TPacketNumber nextSentPacket, vector<CLFECOMMON::CAction *> &actions)
|
||||||
|
'''
|
||||||
|
logging.getLogger(LOGGER).debug("*" * 80)
|
||||||
|
logging.getLogger(LOGGER).debug("receivedPacket:%d receivedAck:%d nextSentPacket:%d" %(receivedPacket, receivedAck, nextSentPacket))
|
||||||
|
actions = []
|
||||||
|
for level in range(0, 3):
|
||||||
|
logging.getLogger(LOGGER).debug("*" * 60)
|
||||||
|
if level == 0:
|
||||||
|
lAck = self._LastAck0
|
||||||
|
channel = 0
|
||||||
|
elif level == 1:
|
||||||
|
lAck = self._LastAck1
|
||||||
|
channel = receivedPacket & 1
|
||||||
|
elif level == 2:
|
||||||
|
lAck = self._LastAck2
|
||||||
|
channel = receivedPacket & 3
|
||||||
|
keep = True
|
||||||
|
checkOnce = False
|
||||||
|
num = 0
|
||||||
|
logging.getLogger(LOGGER).debug("level:%d channel:%d lAck:%s" %(level, channel, ':'.join([str(x) for x in lAck])))
|
||||||
|
# lastAck = lAck[channel]
|
||||||
|
while True:
|
||||||
|
logging.getLogger(LOGGER).debug("*" * 40)
|
||||||
|
next = msgin.readBool('next:' + str(level) + ':' + str(channel))
|
||||||
|
if not next:
|
||||||
|
break
|
||||||
|
if not checkOnce:
|
||||||
|
checkOnce = True
|
||||||
|
keep = receivedAck >= lAck[channel]
|
||||||
|
logging.getLogger(LOGGER).debug("keep:%s [%d => %d]" % (str(keep), receivedAck, lAck[channel]))
|
||||||
|
if keep:
|
||||||
|
lAck[channel] = nextSentPacket
|
||||||
|
logging.getLogger(LOGGER).debug("lAck:%s" % ':'.join([str(x) for x in lAck]))
|
||||||
|
num += 1
|
||||||
|
action = self._CActionFactory.unpack(msgin)
|
||||||
|
if keep:
|
||||||
|
logging.getLogger(LOGGER).debug("keep : %s" % str(action))
|
||||||
|
actions.append(copy.copy(action))
|
||||||
|
elif action:
|
||||||
|
logging.getLogger(LOGGER).debug("append : %s" % str(action))
|
||||||
|
self.removeCAction(copy.copy(action))
|
||||||
|
logging.getLogger(LOGGER).debug('actions: ' +','.join( [ str(x) for x in actions] ) )
|
||||||
|
logging.getLogger(LOGGER).debug("*" * 80)
|
||||||
|
return actions
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self._LastAck0 = [-1]
|
||||||
|
self._LastAck1 = [-1, -1]
|
||||||
|
self._LastAck2 = [-1, -1, -1, -1]
|
39
tools/CMainlandSummary.py
Normal file
39
tools/CMainlandSummary.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CMainlandSummary
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from tools import CSessionId
|
||||||
|
|
||||||
|
|
||||||
|
class CMainlandSummary():
|
||||||
|
def __init__(self):
|
||||||
|
self.Id = CSessionId.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')
|
695
tools/CPersistentDataRecord.py
Normal file
695
tools/CPersistentDataRecord.py
Normal file
|
@ -0,0 +1,695 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CPersistentDataRecord
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from tools import Enum
|
||||||
|
from tools import CArg
|
||||||
|
from tools import TExtendType
|
||||||
|
from tools import CBNPCategorySet
|
||||||
|
from tools import CBNPFile
|
||||||
|
from tools import CBNPFileVersion
|
||||||
|
|
||||||
|
LOGGER='CPersistentDataRecord'
|
||||||
|
|
||||||
|
class CPersistentDataRecord:
|
||||||
|
def __init__(self):
|
||||||
|
self.TokenTable = []
|
||||||
|
self.ArgTable = []
|
||||||
|
self.StringTable = [ ]
|
||||||
|
self.ReadingStructStack = []
|
||||||
|
self.offsetToken = 0
|
||||||
|
self.ArgOffset = 0
|
||||||
|
self.version = 0
|
||||||
|
self.totalSize = 0
|
||||||
|
self.tokenCount = 0
|
||||||
|
self.argCount = 0
|
||||||
|
self.stringCount = 0
|
||||||
|
self.stringsSize = 0
|
||||||
|
self.CBNPFile = []
|
||||||
|
self.Categories = []
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
for x in self.CBNPFile:
|
||||||
|
logging.getLogger(LOGGER).debug("File:%s" % str(x))
|
||||||
|
for x in self.Categories:
|
||||||
|
logging.getLogger(LOGGER).debug("Categorie:%s" % str(x))
|
||||||
|
|
||||||
|
# ---------------- Manipulate Token ----------------
|
||||||
|
|
||||||
|
# +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||||||
|
# | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
|
||||||
|
# +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||||||
|
# | Token ID | Token Type |
|
||||||
|
# +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|
||||||
|
|
||||||
|
def token2Type(self, token, extend): # persistent_data_inline.h:1102 CPersistentDataRecord::CArg::TType CPersistentDataRecord::CArg::token2Type(uint32 token,bool extend)
|
||||||
|
logging.getLogger(LOGGER).debug("token:%d, extend:%d" % (token, extend))
|
||||||
|
if token == Enum.Card.BEGIN_TOKEN:
|
||||||
|
return Enum.TType.STRUCT_BEGIN
|
||||||
|
elif token == Enum.Card.END_TOKEN:
|
||||||
|
return Enum.TType.STRUCT_END
|
||||||
|
elif token == Enum.Card.FLAG_TOKEN:
|
||||||
|
return Enum.TType.FLAG
|
||||||
|
elif token == Enum.Card.SINT_TOKEN:
|
||||||
|
if extend:
|
||||||
|
return Enum.TType.SINT64
|
||||||
|
else:
|
||||||
|
return Enum.TType.SINT32
|
||||||
|
elif token == Enum.Card.UINT_TOKEN:
|
||||||
|
if extend:
|
||||||
|
return Enum.TType.UINT64
|
||||||
|
else:
|
||||||
|
return Enum.TType.UINT32
|
||||||
|
elif token == Enum.Card.FLOAT_TOKEN:
|
||||||
|
if extend:
|
||||||
|
return Enum.TType.FLOAT64
|
||||||
|
else:
|
||||||
|
return Enum.TType.FLOAT32
|
||||||
|
elif token == Enum.Card.STRING_TOKEN:
|
||||||
|
if extend:
|
||||||
|
return Enum.TType.EXTEND_TYPE
|
||||||
|
else:
|
||||||
|
return Enum.TType.STRING
|
||||||
|
logging.getLogger(LOGGER).error('This should never happen!')
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def type2Token(self, type): # persistent_data_inline.h:1118 CPersistentDataRecord::TToken CPersistentDataRecord::CArg::type2Token(uint32 type)
|
||||||
|
logging.getLogger(LOGGER).debug("type: %d" %(type))
|
||||||
|
if type == Enum.TType.STRUCT_BEGIN:
|
||||||
|
return Enum.Card.BEGIN_TOKEN
|
||||||
|
elif type == Enum.TType.STRUCT_END:
|
||||||
|
return Enum.Card.END_TOKEN
|
||||||
|
elif type == Enum.TType.FLAG:
|
||||||
|
return Enum.Card.FLAG_TOKEN
|
||||||
|
elif type == Enum.TType.SINT32:
|
||||||
|
return Enum.Card.SINT_TOKEN
|
||||||
|
elif type == Enum.TType.UINT32:
|
||||||
|
return Enum.Card.UINT_TOKEN
|
||||||
|
elif type == Enum.TType.FLOAT32:
|
||||||
|
return Enum.Card.FLOAT_TOKEN
|
||||||
|
elif type == Enum.TType.STRING:
|
||||||
|
return Enum.Card.STRING_TOKEN
|
||||||
|
elif type == Enum.TType.SINT64:
|
||||||
|
return Enum.Card.SINT_TOKEN
|
||||||
|
elif type == Enum.TType.UINT64:
|
||||||
|
return Enum.Card.UINT_TOKEN
|
||||||
|
elif type == Enum.TType.FLOAT64:
|
||||||
|
return Enum.Card.FLOAT_TOKEN
|
||||||
|
elif type == Enum.TType.EXTEND_TYPE:
|
||||||
|
return Enum.Card.STRING_TOKEN
|
||||||
|
logging.getLogger(LOGGER).error('This should never happen!')
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def peekNextToken(self):
|
||||||
|
token = self.TokenTable[self.offsetToken]
|
||||||
|
logging.getLogger(LOGGER).debug("[%d] token:%d" %(self.offsetToken, token))
|
||||||
|
return token // 8 # persistent_data_inline.h:308 CPersistentDataRecord::TToken CPersistentDataRecord::peekNextToken() # _TokenTable[_TokenOffset]>>3;
|
||||||
|
|
||||||
|
def peekNextTokenType(self): # persistent_data_limit.h:308 CPersistentDataRecord::TToken CPersistentDataRecord::peekNextToken() const
|
||||||
|
logging.getLogger(LOGGER).debug("peekNextTokenType - old offset token:%d" % self.offsetToken)
|
||||||
|
if self.isEndOfData():
|
||||||
|
logging.getLogger(LOGGER).error('Attempt to read past end of input data')
|
||||||
|
sys.exit(2)
|
||||||
|
token = self.TokenTable[self.offsetToken]
|
||||||
|
tokenType = token & 7
|
||||||
|
if tokenType == Enum.Card.EXTEND_TOKEN:
|
||||||
|
if self.offsetToken + 1 > self.tokenCount:
|
||||||
|
logging.getLogger(LOGGER).error('Attempt to read past end of input data')
|
||||||
|
sys.exit(2)
|
||||||
|
tokenType = self.TokenTable[self.offsetToken+1]
|
||||||
|
logging.getLogger(LOGGER).debug("peekNextTokenType [%d] token:%d type:%d" %(self.offsetToken, token, tokenType))
|
||||||
|
return self.token2Type(tokenType, True)
|
||||||
|
logging.getLogger(LOGGER).debug("peekNextTokenType [%d] token:%d type:%d" %(self.offsetToken, token, tokenType))
|
||||||
|
return self.token2Type(tokenType, False)
|
||||||
|
|
||||||
|
def isEndOfData(self):
|
||||||
|
if self.offsetToken == self.tokenCount:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def isEndOfStruct(self):
|
||||||
|
if self.isEndOfData():
|
||||||
|
logging.getLogger(LOGGER).debug("isEndOfData")
|
||||||
|
return True
|
||||||
|
elif len(self.ReadingStructStack) == 0:
|
||||||
|
logging.getLogger(LOGGER).debug("ReadingStructStack")
|
||||||
|
return False
|
||||||
|
elif self.peekNextTokenType() != Enum.TType.STRUCT_END:
|
||||||
|
logging.getLogger(LOGGER).debug("peekNextTokenType != Enum.TType.STRUCT_END")
|
||||||
|
return False
|
||||||
|
elif self.ReadingStructStack[-1] != self.peekNextToken():
|
||||||
|
logging.getLogger(LOGGER).error("Opening and closing structure tokens don't match")
|
||||||
|
sys.exit(2)
|
||||||
|
logging.getLogger(LOGGER).debug("isEndOfStruct")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def isStartOfStruct(self):
|
||||||
|
if self.peekNextTokenType() == Enum.TType.STRUCT_BEGIN:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def popStructBegin(self, token):
|
||||||
|
if self.peekNextToken() != token:
|
||||||
|
logging.getLogger(LOGGER).error('Attempting to enter a structure with the wrong delimiting token')
|
||||||
|
sys.exit(2)
|
||||||
|
if self.peekNextTokenType() != Enum.TType.STRUCT_BEGIN:
|
||||||
|
logging.getLogger(LOGGER).error('Attempting to leave a structure with the wrong delimiting token type')
|
||||||
|
sys.exit(2)
|
||||||
|
self.ReadingStructStack.append(token)
|
||||||
|
self.offsetToken += 1
|
||||||
|
|
||||||
|
def popStructEnd(self, token):
|
||||||
|
if len(self.ReadingStructStack) == 0:
|
||||||
|
logging.getLogger(LOGGER).error('Attempting to pop end of a structure with nothing left in the open structure stack')
|
||||||
|
sys.exit(2)
|
||||||
|
nextToken = self.peekNextToken()
|
||||||
|
topToken = self.ReadingStructStack[-1]
|
||||||
|
if topToken != token:
|
||||||
|
logging.getLogger(LOGGER).error('Attempting to pop end of a structure with the wrong delimiting token')
|
||||||
|
sys.exit(2)
|
||||||
|
if nextToken != token:
|
||||||
|
logging.getLogger(LOGGER).error('Attempting to pop end of a structure with the wrong delimiting token')
|
||||||
|
sys.exit(2)
|
||||||
|
if self.peekNextTokenType() != Enum.TType.STRUCT_END:
|
||||||
|
logging.getLogger(LOGGER).error('Attempting to leave a structure with the wrong delimiting token type')
|
||||||
|
sys.exit(2)
|
||||||
|
del self.ReadingStructStack[-1]
|
||||||
|
self.offsetToken += 1
|
||||||
|
|
||||||
|
# ---------------- Manipulate StringTable ----------------
|
||||||
|
def lookupString(self, idx):
|
||||||
|
if idx >= self.stringCount:
|
||||||
|
logging.getLogger(LOGGER).error("Attempting to access past end of string table")
|
||||||
|
sys.exit(2)
|
||||||
|
return self.StringTable[idx]
|
||||||
|
|
||||||
|
# ---------------- Manipulate Arg ----------------
|
||||||
|
def peekNextArg(self): # persistent_data_limit.h:339 CPersistentDataRecord::peekNextArg(CPersistentDataRecord::CArg& result) const
|
||||||
|
_type = self.peekNextTokenType()
|
||||||
|
result = CArg.CArg()
|
||||||
|
result.write_Type(_type)
|
||||||
|
result.write_Type64(False)
|
||||||
|
logging.getLogger(LOGGER).debug("peekNextArg - Type:%d ArgOffset:%d" % (_type, self.ArgOffset))
|
||||||
|
if result.isExtended():
|
||||||
|
logging.getLogger(LOGGER).debug("Extended")
|
||||||
|
result.write_i32_1(self.ArgTable[self.ArgOffset])
|
||||||
|
result.write_i32_2(self.ArgTable[self.ArgOffset+1])
|
||||||
|
if result.read_Type() == Enum.TType.EXTEND_TYPE and result.read_ExType() == TExtendType.TExtendType.ET_64_BIT_EXTENDED_TYPES:
|
||||||
|
result.write_ex32_2(self.ArgTable[self.ArgOffset+2]);
|
||||||
|
result.write_Type64(True)
|
||||||
|
elif not result.isFlag():
|
||||||
|
# result._Value.i32_1 = _ArgTable[_ArgOffset];
|
||||||
|
result.write_i32_1(self.ArgTable[self.ArgOffset])
|
||||||
|
logging.getLogger(LOGGER).debug("peekNextArg - id :%d" % result.read_i32_1())
|
||||||
|
if result.read_Type() == Enum.TType.STRING:
|
||||||
|
result.write_String(self.lookupString(result.read_i32_1()))
|
||||||
|
logging.getLogger(LOGGER).debug("peekNextArg - String:%s" % result.read_String())
|
||||||
|
return result
|
||||||
|
|
||||||
|
def popNextArg(self, token): # persistent_data_limit.h:414 CPersistentDataRecord::popNextArg(TToken token,CPersistentDataRecord::CArg& result)
|
||||||
|
result = self.peekNextArg()
|
||||||
|
if result.isFlag():
|
||||||
|
self.offsetToken += 1
|
||||||
|
elif result.isExtended():
|
||||||
|
self.ArgOffset += 2
|
||||||
|
self.offsetToken += 2
|
||||||
|
if result.read_Type() == Enum.TType.EXTEND_TYPE and result.read_ExType() == TExtendType.TExtendType.ET_64_BIT_EXTENDED_TYPES:
|
||||||
|
self.ArgOffset += 1
|
||||||
|
self.offsetToken += 1
|
||||||
|
else:
|
||||||
|
self.ArgOffset += 1
|
||||||
|
self.offsetToken += 1
|
||||||
|
logging.getLogger(LOGGER).debug("popNextArg - Arg:%d", result.read_i32_1())
|
||||||
|
return result
|
||||||
|
|
||||||
|
def popString(self, token):
|
||||||
|
TempArg = self.popNextArg(token)
|
||||||
|
return TempArg.asString()
|
||||||
|
|
||||||
|
def popUint32(self, token):
|
||||||
|
TempArg = self.popNextArg(token)
|
||||||
|
return TempArg.asUint()
|
||||||
|
|
||||||
|
def popBool(self, token):
|
||||||
|
TempArg = self.popNextArg(token)
|
||||||
|
return TempArg.asUint() != 0
|
||||||
|
|
||||||
|
# ---------------- Read Data ----------------
|
||||||
|
def readFromBinFile(self, filename): # persistent_data.cpp:835 # bool CPersistentDataRecord::fromBuffer(const char *src, uint32 bufferSize)
|
||||||
|
logging.getLogger(LOGGER).debug('Read Bin File %s' % filename)
|
||||||
|
with open(filename, "rb") as fp:
|
||||||
|
buffer = fp.read()
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
self.version = int.from_bytes(buffer[0:4], byteorder='little', signed=False)
|
||||||
|
self.totalSize = int.from_bytes(buffer[4:8], byteorder='little', signed=False)
|
||||||
|
self.tokenCount = int.from_bytes(buffer[8:12], byteorder='little', signed=False)
|
||||||
|
self.argCount = int.from_bytes(buffer[12:16], byteorder='little', signed=False)
|
||||||
|
self.stringCount = int.from_bytes(buffer[16:20], byteorder='little', signed=False)
|
||||||
|
self.stringsSize = int.from_bytes(buffer[20:24], byteorder='little', signed=False)
|
||||||
|
offset = 24
|
||||||
|
logging.getLogger(LOGGER).debug("version:%d, totalSize:%d, tokenCount:%d, argCount:%d, stringCount:%d, stringsSize:%d" % (self.version, self.totalSize, self.tokenCount, self.argCount, self.stringCount, self.stringsSize))
|
||||||
|
if len(buffer) != self.totalSize:
|
||||||
|
logging.getLogger(LOGGER).error("Failed to parse buffer due to invalid header (file:%s, size:%d, size define:%d)" % (filename, len(buffer), self.totalSize ))
|
||||||
|
sys.exit(2)
|
||||||
|
if self.version > 0:
|
||||||
|
logging.getLogger(LOGGER).error("PDR ERROR: Wrong file format version! (file:%s, version:%d)" % (filename, self.version))
|
||||||
|
sys.exit(2)
|
||||||
|
if (self.stringCount != 0 and self.stringsSize == 0) or (self.stringCount == 0 and self.stringsSize != 0):
|
||||||
|
logging.getLogger(LOGGER).error("PDR ERROR: Invalid string table parameters! (file:%s, stringCount:%d, stringsSize:%d)" % (filename, self.stringCount, self.stringsSize))
|
||||||
|
sys.exit(2)
|
||||||
|
# i = offset+tokenCount*sizeof(TToken)+argCount*sizeof(uint32)+stringsSize
|
||||||
|
i = offset + self.tokenCount * 2 + self.argCount * 4 + self.stringsSize;
|
||||||
|
if self.totalSize != i:
|
||||||
|
logging.getLogger(LOGGER).error("PDR ERROR: Invalid source data (file:%s, totalSize:%d != datasize:%s)" % (filename, self.totalSize, i))
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
# READ the tokens
|
||||||
|
self.TokenTable = []
|
||||||
|
for i in range(0, self.tokenCount):
|
||||||
|
tmp = int.from_bytes(buffer[offset:offset+2], byteorder='little', signed=False)
|
||||||
|
logging.getLogger(LOGGER).debug("token %5d => %3d id:%3d type:%d" %(i, tmp, tmp // 8, tmp & 7))
|
||||||
|
self.TokenTable.append(tmp)
|
||||||
|
offset += 2
|
||||||
|
|
||||||
|
# READ the arguments
|
||||||
|
self.ArgTable = []
|
||||||
|
for i in range(0, self.argCount):
|
||||||
|
tmp = int.from_bytes(buffer[offset:offset+4], byteorder='little', signed=False)
|
||||||
|
self.ArgTable.append(tmp)
|
||||||
|
offset += 4
|
||||||
|
|
||||||
|
# READ the string table data
|
||||||
|
if self.stringsSize != 0:
|
||||||
|
chaine = ''
|
||||||
|
self.StringTable = [ ]
|
||||||
|
while offset < self.totalSize:
|
||||||
|
car = buffer[offset:offset+1].decode()
|
||||||
|
if car != '\0':
|
||||||
|
chaine += car
|
||||||
|
else:
|
||||||
|
self.StringTable.append(chaine)
|
||||||
|
chaine = ''
|
||||||
|
offset += 1
|
||||||
|
logging.getLogger(LOGGER).debug(self.StringTable)
|
||||||
|
if chaine != '':
|
||||||
|
logging.getLogger(LOGGER).error("PDR ERROR: Too few strings found in string table (file:%s)" % (filename))
|
||||||
|
sys.exit(2)
|
||||||
|
logging.getLogger(LOGGER).debug("Red %s" % filename)
|
||||||
|
|
||||||
|
def decrypt_token(self):
|
||||||
|
i = 0
|
||||||
|
lvl = 0
|
||||||
|
posArg = 0
|
||||||
|
extend = False
|
||||||
|
extend64 = False
|
||||||
|
result = CArg.CArg()
|
||||||
|
|
||||||
|
print("^ Position ^ Token ^")
|
||||||
|
for value in self.TokenTable:
|
||||||
|
print("| %5d | %3d |" %(i, value))
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
print("^ Position ^ Argument ^")
|
||||||
|
for value in self.ArgTable:
|
||||||
|
print("| %5d | %3d |" %(i, value))
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
print("^ Position ^ String ^")
|
||||||
|
for value in self.StringTable:
|
||||||
|
print("| %5d | %s |" %(i, value))
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
print("^ Position ^ Niveau ^ Token ^ Token ID ^^ Token Type (Card) ^^^ Result ^")
|
||||||
|
print("^ ^^ (entrée) ^ Valeur ^ Quoi ^ Valeur ^ Card ^ Type ^ ^")
|
||||||
|
for token in self.TokenTable:
|
||||||
|
tokenId = token // 8
|
||||||
|
tokenTypeValue = token & 7
|
||||||
|
result.write_String("-")
|
||||||
|
if tokenTypeValue == 0:
|
||||||
|
tokenCard = 'BEGIN_TOKEN'
|
||||||
|
tokenType = 'STRUCT_BEGIN'
|
||||||
|
result.write_Type(Enum.TType.STRUCT_BEGIN)
|
||||||
|
if lvl <= 1:
|
||||||
|
print("| |||||||")
|
||||||
|
lvl += 1
|
||||||
|
elif tokenTypeValue == 1:
|
||||||
|
tokenCard = 'END_TOKEN'
|
||||||
|
tokenType = 'STRUCT_END'
|
||||||
|
result.write_Type(Enum.TType.STRUCT_END)
|
||||||
|
extend = False
|
||||||
|
extend64 = False
|
||||||
|
elif tokenTypeValue == 2:
|
||||||
|
tokenCard = 'SINT_TOKEN'
|
||||||
|
if extend:
|
||||||
|
tokenType = 'SINT64'
|
||||||
|
result.write_Type(Enum.TType.SINT64)
|
||||||
|
result.write_i32_1(self.ArgTable[posArg])
|
||||||
|
result.write_i32_2(self.ArgTable[posArg+1])
|
||||||
|
if extend64:
|
||||||
|
result.write_ex32_2(self.ArgTable[posArg+2]);
|
||||||
|
posArg += 3
|
||||||
|
else:
|
||||||
|
posArg += 2
|
||||||
|
else:
|
||||||
|
tokenType = 'SINT32'
|
||||||
|
result.write_Type(Enum.TType.SINT32)
|
||||||
|
result.write_i32_1(self.ArgTable[posArg])
|
||||||
|
posArg += 1
|
||||||
|
extend = False
|
||||||
|
extend64 = False
|
||||||
|
elif tokenTypeValue == 3:
|
||||||
|
tokenCard = 'UINT_TOKEN'
|
||||||
|
if extend:
|
||||||
|
tokenType = 'UINT64'
|
||||||
|
result.write_Type(Enum.TType.UINT64)
|
||||||
|
result.write_i32_1(self.ArgTable[posArg])
|
||||||
|
result.write_i32_2(self.ArgTable[posArg+1])
|
||||||
|
if extend64:
|
||||||
|
result.write_ex32_2(self.ArgTable[posArg+2]);
|
||||||
|
posArg += 3
|
||||||
|
else:
|
||||||
|
posArg += 2
|
||||||
|
else:
|
||||||
|
tokenType = 'UINT32'
|
||||||
|
result.write_Type(Enum.TType.UINT32)
|
||||||
|
result.write_i32_1(self.ArgTable[posArg])
|
||||||
|
posArg += 1
|
||||||
|
extend = False
|
||||||
|
extend64 = False
|
||||||
|
elif tokenTypeValue == 4:
|
||||||
|
tokenCard = 'FLOAT_TOKEN'
|
||||||
|
if extend:
|
||||||
|
tokenType = 'FLOAT64'
|
||||||
|
result.write_Type(Enum.TType.FLOAT64)
|
||||||
|
result.write_i32_1(self.ArgTable[posArg])
|
||||||
|
result.write_i32_2(self.ArgTable[posArg+1])
|
||||||
|
if extend64:
|
||||||
|
result.write_ex32_2(self.ArgTable[posArg+2]);
|
||||||
|
posArg += 3
|
||||||
|
else:
|
||||||
|
posArg += 2
|
||||||
|
else:
|
||||||
|
tokenType = 'FLOAT32'
|
||||||
|
result.write_Type(Enum.TType.FLOAT32)
|
||||||
|
result.write_i32_1(self.ArgTable[posArg])
|
||||||
|
posArg += 1
|
||||||
|
extend = False
|
||||||
|
extend64 = False
|
||||||
|
elif tokenTypeValue == 5:
|
||||||
|
tokenCard = 'STRING_TOKEN'
|
||||||
|
if extend:
|
||||||
|
tokenType = 'EXTEND_TYPE'
|
||||||
|
result.write_Type(Enum.TType.EXTEND_TYPE)
|
||||||
|
result.write_i32_1(self.ArgTable[posArg])
|
||||||
|
result.write_i32_2(self.ArgTable[posArg+1])
|
||||||
|
if extend64:
|
||||||
|
result.write_ex32_2(self.ArgTable[posArg+2]);
|
||||||
|
posArg += 3
|
||||||
|
else:
|
||||||
|
posArg += 2
|
||||||
|
else:
|
||||||
|
tokenType = 'STRING'
|
||||||
|
result.write_Type(Enum.TType.STRING)
|
||||||
|
result.write_i32_1(self.ArgTable[posArg])
|
||||||
|
tmp = result.read_i32_1()
|
||||||
|
result.write_String(self.StringTable[tmp])
|
||||||
|
posArg += 1
|
||||||
|
extend = False
|
||||||
|
extend64 = False
|
||||||
|
elif tokenType == 6:
|
||||||
|
tokenCard = 'FLAG_TOKEN'
|
||||||
|
tokenType = 'FLAG'
|
||||||
|
result.write_Type(Enum.TType.FLAG)
|
||||||
|
extend = False
|
||||||
|
extend64 = False
|
||||||
|
elif tokenTypeValue == 7:
|
||||||
|
if extend:
|
||||||
|
extend64 = True
|
||||||
|
tokenCard = 'EXTEND_TOKEN'
|
||||||
|
result.write_Type(Enum.TType.EXTEND_TYPE)
|
||||||
|
tokenType = ''
|
||||||
|
extend = True
|
||||||
|
# print("token %5d => %3d id:%3d [%s] type:%d [%s]" %(i, token, tokenId, self.StringTable[tokenId], tokenType, tokenCard))
|
||||||
|
print("| %5d | %3d | %3d | %3d | %s | %d | %s | %s | %s |" %(i, lvl, token, tokenId, self.StringTable[tokenId], tokenTypeValue, tokenCard , tokenType, result))
|
||||||
|
if tokenTypeValue == 1:
|
||||||
|
lvl -= 1
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
def addString(self, name): # persistent_data.cpp:100 uint16 CPersistentDataRecord::addString(const string& name)
|
||||||
|
for i in range(0, len(self.StringTable)):
|
||||||
|
if self.StringTable[i] == name:
|
||||||
|
return i
|
||||||
|
self.StringTable.append(name)
|
||||||
|
return len(self.StringTable) - 1
|
||||||
|
|
||||||
|
def CProductDescriptionForClient_apply(self): # persistent_data_template.h:459 # void PERSISTENT_CLASS::apply(CPersistentDataRecord &pdr _PERSISTENT_APPLY_ARGS)
|
||||||
|
__Tok__MapKey = self.addString("__Key__")
|
||||||
|
__Tok__MapVal = self.addString("__Val__")
|
||||||
|
__Tok_Files = self.addString("_Files")
|
||||||
|
__Tok_Categories = self.addString("_Categories")
|
||||||
|
logging.getLogger(LOGGER).debug("MapKey:%d, MapVal:%d, Files:%d, Categories:%d" %(__Tok__MapKey, __Tok__MapVal, __Tok_Files, __Tok_Categories))
|
||||||
|
while not self.isEndOfStruct():
|
||||||
|
nextToken = self.peekNextToken()
|
||||||
|
logging.getLogger(LOGGER).debug("nextToken:%d" % (nextToken))
|
||||||
|
if nextToken == __Tok_Files:
|
||||||
|
self.popStructBegin(__Tok_Files)
|
||||||
|
self.CBNPFileSet_apply()
|
||||||
|
self.popStructEnd(__Tok_Files)
|
||||||
|
continue
|
||||||
|
elif nextToken == __Tok_Categories:
|
||||||
|
self.popStructBegin(__Tok_Categories)
|
||||||
|
# (_Categories).apply(pdr);
|
||||||
|
self.CBNPCategorySet_apply()
|
||||||
|
self.popStructEnd(__Tok_Categories)
|
||||||
|
continue
|
||||||
|
logging.getLogger(LOGGER).error("TODO")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def CBNPFileSet_apply(self):
|
||||||
|
__Tok__MapKey = self.addString("__Key__")
|
||||||
|
__Tok__MapVal = self.addString("__Val__")
|
||||||
|
__Tok_Files = self.addString("_Files")
|
||||||
|
logging.getLogger(LOGGER).debug("MapKey:%d, MapVal:%d, Files:%d" %(__Tok__MapKey, __Tok__MapVal, __Tok_Files))
|
||||||
|
while not self.isEndOfStruct():
|
||||||
|
nextToken = self.peekNextToken()
|
||||||
|
logging.getLogger(LOGGER).debug("nextToken:%d" % (nextToken))
|
||||||
|
if nextToken == __Tok_Files:
|
||||||
|
self.popStructBegin(__Tok_Files)
|
||||||
|
self.CBNPFile.append(CBNPFile.CBNPFile())
|
||||||
|
self.CBNPFile_apply(self.CBNPFile[-1])
|
||||||
|
self.popStructEnd(__Tok_Files)
|
||||||
|
continue
|
||||||
|
logging.getLogger(LOGGER).error("TODO")
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
def CBNPFile_apply(self, _CBNPFile):
|
||||||
|
__Tok__MapKey = self.addString("__Key__")
|
||||||
|
__Tok__MapVal = self.addString("__Val__")
|
||||||
|
__Tok_FileName = self.addString("_FileName")
|
||||||
|
__Tok_Versions = self.addString("_Versions")
|
||||||
|
_FileName = None
|
||||||
|
logging.getLogger(LOGGER).debug("MapKey:%d, MapVal:%d, Filename:%d, Versions:%d" %(__Tok__MapKey, __Tok__MapVal, __Tok_FileName, __Tok_Versions))
|
||||||
|
while not self.isEndOfStruct():
|
||||||
|
nextToken = self.peekNextToken()
|
||||||
|
logging.getLogger(LOGGER).debug("nextToken:%d" % (nextToken))
|
||||||
|
if nextToken == __Tok_FileName:
|
||||||
|
_FileName = self.popString(nextToken)
|
||||||
|
_CBNPFile.FileName = _FileName
|
||||||
|
logging.getLogger(LOGGER).debug("filename: %s" % _FileName)
|
||||||
|
continue
|
||||||
|
if nextToken == __Tok_Versions:
|
||||||
|
self.popStructBegin(__Tok_Versions)
|
||||||
|
# vectAppend(_Versions).apply(pdr);
|
||||||
|
_CBNPFile.Versions.append(CBNPFileVersion.CBNPFileVersion())
|
||||||
|
self.CBNPFileVersion_apply(_CBNPFile.Versions[-1])
|
||||||
|
self.popStructEnd(__Tok_Versions)
|
||||||
|
continue
|
||||||
|
stack = []
|
||||||
|
while True:
|
||||||
|
if self.isStartOfStruct():
|
||||||
|
stack.append(self.peekNextToken())
|
||||||
|
self.popStructBegin(stack)
|
||||||
|
elif self.isEndOfStruct():
|
||||||
|
self.popStructEnd(stack[-1])
|
||||||
|
if len(stack) > 0:
|
||||||
|
del stack[-1]
|
||||||
|
else:
|
||||||
|
self.popNextArg(self.peekNextToken())
|
||||||
|
if self.isEndOfData() and len(stack) == 0:
|
||||||
|
break
|
||||||
|
logging.getLogger(LOGGER).debug("CBNPFile: %s" % _CBNPFile)
|
||||||
|
|
||||||
|
def CBNPFileVersion_apply(self, _CBNPFileVersion): # persistent_data_template.h:459 # void CBNPFileVersion::apply(CPersistentDataRecord &pdr )
|
||||||
|
__Tok__MapKey = self.addString("__Key__")
|
||||||
|
__Tok__MapVal = self.addString("__Val__")
|
||||||
|
__Tok_VersionNumber = self.addString("_VersionNumber")
|
||||||
|
__Tok_FileSize = self.addString("_FileSize")
|
||||||
|
__Tok_7ZFileSize = self.addString("_7ZFileSize")
|
||||||
|
__Tok_FileTime = self.addString("_FileTime")
|
||||||
|
__Tok_PatchSize = self.addString("_PatchSize")
|
||||||
|
__Tok_HashKey = self.addString("_HashKey")
|
||||||
|
logging.getLogger(LOGGER).debug("MapKey:%d, MapVal:%d, VersionNumber:%d, FileSize:%d, 7ZFileSize:%d, FileTime:%d, PatchSize:%d, HashKey:%d" %(__Tok__MapKey, __Tok__MapVal, __Tok_VersionNumber, __Tok_FileSize, __Tok_7ZFileSize, __Tok_FileTime, __Tok_PatchSize, __Tok_HashKey))
|
||||||
|
|
||||||
|
while not self.isEndOfStruct():
|
||||||
|
nextToken = self.peekNextToken()
|
||||||
|
logging.getLogger(LOGGER).debug("nextToken:%d" % (nextToken))
|
||||||
|
if nextToken == __Tok_VersionNumber:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_VersionNumber")
|
||||||
|
_CBNPFileVersion.VersionNumber = self.popUint32(__Tok_VersionNumber)
|
||||||
|
logging.getLogger(LOGGER).debug("VersionNumber: %s" % _CBNPFileVersion.VersionNumber)
|
||||||
|
continue
|
||||||
|
elif nextToken == __Tok_FileSize:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_FileSize")
|
||||||
|
_CBNPFileVersion.FileSize = self.popUint32(__Tok_FileSize)
|
||||||
|
logging.getLogger(LOGGER).debug("FileSize: %s" % _CBNPFileVersion.FileSize)
|
||||||
|
continue
|
||||||
|
elif nextToken == __Tok_7ZFileSize:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_7ZFileSize")
|
||||||
|
_CBNPFileVersion.v7ZFileSize = self.popUint32(__Tok_7ZFileSize)
|
||||||
|
logging.getLogger(LOGGER).debug("7ZFileSize: %s" % _CBNPFileVersion.v7ZFileSize)
|
||||||
|
continue
|
||||||
|
elif nextToken == __Tok_FileTime:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_FileTime")
|
||||||
|
_CBNPFileVersion.FileTime = self.popUint32(__Tok_FileTime)
|
||||||
|
logging.getLogger(LOGGER).debug("FileTime: %s" % _CBNPFileVersion.FileTime)
|
||||||
|
continue
|
||||||
|
elif nextToken == __Tok_PatchSize:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_PatchSize")
|
||||||
|
_CBNPFileVersion.PatchSize = self.popUint32(__Tok_PatchSize)
|
||||||
|
logging.getLogger(LOGGER).debug("PatchSize: %s" % _CBNPFileVersion.PatchSize)
|
||||||
|
continue
|
||||||
|
elif nextToken == __Tok_HashKey:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_HashKey")
|
||||||
|
_CBNPFileVersion.HashKey.append(self.popUint32(__Tok_HashKey))
|
||||||
|
logging.getLogger(LOGGER).debug("HashKey: %s" % _CBNPFileVersion.HashKey[-1])
|
||||||
|
continue
|
||||||
|
# Vidage des autres clefs (inconnues)
|
||||||
|
stack = []
|
||||||
|
while True:
|
||||||
|
if self.isStartOfStruct():
|
||||||
|
stack.append(self.peekNextToken())
|
||||||
|
self.popStructBegin(stack)
|
||||||
|
elif self.isEndOfStruct():
|
||||||
|
self.popStructEnd(stack[-1])
|
||||||
|
if len(stack) > 0:
|
||||||
|
del stack[-1]
|
||||||
|
else:
|
||||||
|
self.popNextArg(self.peekNextToken())
|
||||||
|
if self.isEndOfData() and len(stack) == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
def CBNPCategorySet_apply(self): # persistent_data_template.h:459 # void CBNPCategorySet::apply(CPersistentDataRecord &pdr )
|
||||||
|
#__Tok__MapKey = self.addString("__Key__")
|
||||||
|
#__Tok__MapVal = self.addString("__Val__")
|
||||||
|
__Tok_Category = self.addString("_Category")
|
||||||
|
while not self.isEndOfStruct():
|
||||||
|
nextToken = self.peekNextToken()
|
||||||
|
logging.getLogger(LOGGER).debug("nextToken:%d" % (nextToken))
|
||||||
|
if nextToken == __Tok_Category:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_Category")
|
||||||
|
self.popStructBegin(__Tok_Category)
|
||||||
|
self.Categories.append(CBNPCategorySet.CBNPCategorySet())
|
||||||
|
self.CBNPCategory_apply(self.Categories[-1])
|
||||||
|
self.popStructEnd(__Tok_Category)
|
||||||
|
continue
|
||||||
|
# Vidage des autres clefs (inconnues)
|
||||||
|
stack = []
|
||||||
|
while True:
|
||||||
|
if self.isStartOfStruct():
|
||||||
|
stack.append(self.peekNextToken())
|
||||||
|
self.popStructBegin(stack)
|
||||||
|
elif self.isEndOfStruct():
|
||||||
|
self.popStructEnd(stack[-1])
|
||||||
|
if len(stack) > 0:
|
||||||
|
del stack[-1]
|
||||||
|
else:
|
||||||
|
self.popNextArg(self.peekNextToken())
|
||||||
|
if self.isEndOfData() and len(stack) == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def CBNPCategory_apply(self, _CBNPCategory): # persistent_data_template.h:459 # void CBNPCategory::apply(CPersistentDataRecord &pdr )
|
||||||
|
__Tok__MapKey = self.addString("__Key__")
|
||||||
|
__Tok__MapVal = self.addString("__Val__")
|
||||||
|
__Tok_Name = self.addString("_Name")
|
||||||
|
__Tok_IsOptional = self.addString("_IsOptional")
|
||||||
|
__Tok_UnpackTo = self.addString("_UnpackTo")
|
||||||
|
__Tok_IsIncremental = self.addString("_IsIncremental")
|
||||||
|
__Tok_CatRequired = self.addString("_CatRequired")
|
||||||
|
__Tok_Hidden = self.addString("_Hidden")
|
||||||
|
__Tok_Files = self.addString("_Files")
|
||||||
|
logging.getLogger(LOGGER).debug("MapKey:%d, MapVal:%d, Name:%d, IsOptional:%d, UnpackTo:%d, IsIncremental:%d, CatRequired:%d, Hidden:%d, Files:%d" %(__Tok__MapKey, __Tok__MapVal, __Tok_Name, __Tok_IsOptional, __Tok_UnpackTo, __Tok_IsIncremental, __Tok_CatRequired, __Tok_Hidden, __Tok_Files))
|
||||||
|
while not self.isEndOfStruct():
|
||||||
|
nextToken = self.peekNextToken()
|
||||||
|
logging.getLogger(LOGGER).debug("nextToken:%d" % (nextToken))
|
||||||
|
if nextToken == __Tok_Name:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_Name")
|
||||||
|
_CBNPCategory._Name = self.popString(nextToken)
|
||||||
|
logging.getLogger(LOGGER).debug("_Name: %s" % _CBNPCategory._Name)
|
||||||
|
continue
|
||||||
|
elif nextToken == __Tok_IsOptional:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_IsOptional")
|
||||||
|
_CBNPCategory._IsOptional = self.popBool(nextToken)
|
||||||
|
logging.getLogger(LOGGER).debug("_IsOptional: %s" % str(_CBNPCategory._IsOptional))
|
||||||
|
continue
|
||||||
|
elif nextToken == __Tok_UnpackTo:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_UnpackTo")
|
||||||
|
_CBNPCategory._UnpackTo = self.popString(nextToken)
|
||||||
|
logging.getLogger(LOGGER).debug("_UnpackTo: %s" % str(_CBNPCategory._UnpackTo))
|
||||||
|
continue
|
||||||
|
elif nextToken == __Tok_IsIncremental:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_IsIncremental")
|
||||||
|
_CBNPCategory._IsIncremental = self.popBool(nextToken)
|
||||||
|
logging.getLogger(LOGGER).debug("_IsIncremental: %s" % str(_CBNPCategory._IsIncremental))
|
||||||
|
continue
|
||||||
|
elif nextToken == __Tok_CatRequired:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_CatRequired")
|
||||||
|
_CBNPCategory._CatRequired = self.popString(nextToken)
|
||||||
|
logging.getLogger(LOGGER).debug("_CatRequired: %s" % str(_CBNPCategory._CatRequired))
|
||||||
|
continue
|
||||||
|
elif nextToken == __Tok_Hidden:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_Hidden")
|
||||||
|
_CBNPCategory._Hidden = self.popBool(nextToken)
|
||||||
|
logging.getLogger(LOGGER).debug("_Hidden: %s" % str(_CBNPCategory._Hidden))
|
||||||
|
continue
|
||||||
|
elif nextToken == __Tok_Files:
|
||||||
|
logging.getLogger(LOGGER).debug("__Tok_Files")
|
||||||
|
_CBNPCategory._Files.append(self.popString(nextToken))
|
||||||
|
logging.getLogger(LOGGER).debug("_Files: %s" % str(_CBNPCategory._Files))
|
||||||
|
continue
|
||||||
|
# Vidage des autres clefs (inconnues)
|
||||||
|
stack = []
|
||||||
|
while True:
|
||||||
|
if self.isStartOfStruct():
|
||||||
|
stack.append(self.peekNextToken())
|
||||||
|
self.popStructBegin(stack)
|
||||||
|
elif self.isEndOfStruct():
|
||||||
|
self.popStructEnd(stack[-1])
|
||||||
|
if len(stack) > 0:
|
||||||
|
del stack[-1]
|
||||||
|
else:
|
||||||
|
self.popNextArg(self.peekNextToken())
|
||||||
|
if self.isEndOfData() and len(stack) == 0:
|
||||||
|
break
|
28
tools/CSessionId.py
Normal file
28
tools/CSessionId.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CSessionId
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
class CSessionId():
|
||||||
|
def __init__(self, id = 0):
|
||||||
|
self.id = id
|
||||||
|
def read(self, msgin):
|
||||||
|
self.id = msgin.readUint32('id')
|
||||||
|
def push(self, msgout):
|
||||||
|
msgout.pushUint32(self.id)
|
25
tools/CShardName.py
Normal file
25
tools/CShardName.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CShardName
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
class CShardName():
|
||||||
|
def __init__(self, SessionId, DisplayName, ShortName):
|
||||||
|
self.SessionId = SessionId
|
||||||
|
self.DisplayName = DisplayName
|
||||||
|
self.ShortName = ShortName
|
153
tools/CStringManager.py
Normal file
153
tools/CStringManager.py
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CStringManager
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
#from tools import BitStream
|
||||||
|
import copy
|
||||||
|
from tools import CI18N
|
||||||
|
|
||||||
|
LOGGER='CStringManager'
|
||||||
|
|
||||||
|
class CStringManager:
|
||||||
|
def __init__(self):
|
||||||
|
# Message not decoded
|
||||||
|
self.unknown = []
|
||||||
|
# Parameter
|
||||||
|
self.unknownParameterString = []
|
||||||
|
# Message decoded
|
||||||
|
self.decoded = []
|
||||||
|
# Template (id, string)
|
||||||
|
self.templates = {}
|
||||||
|
self.ci18n = CI18N.CI18N()
|
||||||
|
|
||||||
|
def receiveMessage(self, StringId, msgin):
|
||||||
|
try:
|
||||||
|
template = self.templates[StringId]
|
||||||
|
logging.getLogger(LOGGER).debug("template:%s" % template)
|
||||||
|
except KeyError:
|
||||||
|
logging.getLogger(LOGGER).debug("Impossible to decode :%d" % StringId)
|
||||||
|
self.unknown.append((StringId, msgin))
|
||||||
|
|
||||||
|
def receiveTemplate(self, StringId, strUtf8):
|
||||||
|
self.templates.setdefault(StringId, "")
|
||||||
|
self.templates[StringId] = strUtf8
|
||||||
|
self.decodeMessage()
|
||||||
|
|
||||||
|
def cleanDecodedMessage(self):
|
||||||
|
self.decoded = []
|
||||||
|
|
||||||
|
def decodeMessage(self):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/string_manager_client.cpp:608 bool CStringManagerClient::buildDynString(TDynStringInfo &dynInfo)
|
||||||
|
'''
|
||||||
|
newUnknown = []
|
||||||
|
for key, dataRead in self.unknown:
|
||||||
|
if key in self.templates:
|
||||||
|
logging.getLogger(LOGGER).debug('key : %d, data:%s, template:%s' %(key, dataRead.showAllData(), self.templates[key] ))
|
||||||
|
"""
|
||||||
|
Method to decode message
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/string_manager_client.cpp:608 bool CStringManagerClient::buildDynString(TDynStringInfo &dynInfo)
|
||||||
|
"""
|
||||||
|
errorDetected = False
|
||||||
|
i = 0
|
||||||
|
template = self.templates[key]
|
||||||
|
data = copy.deepcopy(dataRead)
|
||||||
|
ret = ""
|
||||||
|
while i < len(template):
|
||||||
|
if template[i] == '%' and i < len(template) -1:
|
||||||
|
i += 1
|
||||||
|
if template[i] == 's':
|
||||||
|
# string
|
||||||
|
StringId = data.readUint32('StringId')
|
||||||
|
logging.getLogger(LOGGER).debug("replacement tag string[pos:%d, template:%s, char:%%%s, stringID:%d]" % (i, template, template[i], StringId))
|
||||||
|
if StringId in self.templates:
|
||||||
|
ParameterString = self.templates[StringId]
|
||||||
|
logging.getLogger(LOGGER).debug("StringId:%d, value:%s" % (StringId, ParameterString))
|
||||||
|
ret += ParameterString
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug("Impossible to decode :%d" % StringId)
|
||||||
|
if StringId not in self.unknown:
|
||||||
|
if StringId not in self.unknownParameterString:
|
||||||
|
logging.getLogger(LOGGER).debug("Impossible to decode :%d (send query)" % StringId)
|
||||||
|
self.unknownParameterString.append(StringId)
|
||||||
|
errorDetected = True
|
||||||
|
elif template[i] == 'i':
|
||||||
|
# integer
|
||||||
|
Integer = data.readSint32('Integer')
|
||||||
|
logging.getLogger(LOGGER).debug("replacement tag integer [pos:%d, template:%s, char:%%%s, integer:%d]" % (i, template, template[i], Integer))
|
||||||
|
ret += str(Integer)
|
||||||
|
elif template[i] == 't':
|
||||||
|
# time
|
||||||
|
Time = data.readUint32('Time')
|
||||||
|
valTime = ""
|
||||||
|
if Time > (10*60*60):
|
||||||
|
nbHours = Time / (10*60*60)
|
||||||
|
Time -= nbHours * 10 * 60 * 60
|
||||||
|
valTime += str(nbHours) + ' ' + self.ci18n.get('uiMissionTimerHour') + ' '
|
||||||
|
nbMinutes = Time / (10*60)
|
||||||
|
Time -= nbMinutes * 10 * 60
|
||||||
|
valTime += str(nbMinutes) + ' ' + self.ci18n.get('uiMissionTimerMinute') + ' '
|
||||||
|
elif Time >= (10*60):
|
||||||
|
nbMinutes = Time / (10*60)
|
||||||
|
Time -= nbMinutes * 10 * 60
|
||||||
|
valTime += str(nbMinutes) + ' ' + self.ci18n.get('uiMissionTimerMinute') + ' '
|
||||||
|
nbSeconds = Time / 10
|
||||||
|
valTime += str(nbSeconds) + ' ' + self.ci18n.get('uiMissionTimerSecond') + ' '
|
||||||
|
|
||||||
|
logging.getLogger(LOGGER).debug("replacement tag time [pos:%d, template:%s, char:%%%s, Time:%d, valTime:%s]" % (i, template, template[i], Time, valTime))
|
||||||
|
ret += valTime
|
||||||
|
elif template[i] == '$':
|
||||||
|
# money
|
||||||
|
Money = data.readUint64('Money')
|
||||||
|
logging.getLogger(LOGGER).debug("replacement tag money [pos:%d, template:%s, char:%%%s, Money:%u]" % (i, template, template[i], Money))
|
||||||
|
ret += str(Integer)
|
||||||
|
elif template[i] == 'm':
|
||||||
|
# dyn_string_id
|
||||||
|
DynStringId = data.readUint32('StringId')
|
||||||
|
logging.getLogger(LOGGER).debug("replacement tag dyn_string_id [pos:%d, template:%s, char:%%%s, DynStringId:%d]" % (i, template, template[i], DynStringId))
|
||||||
|
if DynStringId in self.templates:
|
||||||
|
ParameterString = self.templates[DynStringId]
|
||||||
|
logging.getLogger(LOGGER).debug("DynStringId:%d, value:%s" % (StringId, ParameterString))
|
||||||
|
ret += ParameterString
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug("Impossible to decode :%d - TODO [check if same method to get string value]" % DynStringId)
|
||||||
|
self.unknownParameterString.append((DynStringId))
|
||||||
|
errorDetected = True
|
||||||
|
elif template[i] == '%':
|
||||||
|
# %% => %
|
||||||
|
ret += template[i]
|
||||||
|
logging.getLogger(LOGGER).debug("replacement tag %% [pos:%d, template:%s, char:%%%s]" % (i, template, template[i]))
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning("Error: unknown replacement tag [pos:%d, template:%s, char:%%%s]" % (i, template, template[i]))
|
||||||
|
ret += template[i]
|
||||||
|
else:
|
||||||
|
ret += template[i]
|
||||||
|
i += 1
|
||||||
|
if errorDetected:
|
||||||
|
logging.getLogger(LOGGER).debug('Impossible to decode id:%d' % key)
|
||||||
|
newUnknown.append((key, dataRead))
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug('Message:%s' % ret)
|
||||||
|
self.decoded.append(ret)
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug('Impossible to decode id:%d' % key)
|
||||||
|
newUnknown.append((key, data))
|
||||||
|
self.unknown = newUnknown
|
853
tools/ClientNetworkConnection.py
Normal file
853
tools/ClientNetworkConnection.py
Normal file
|
@ -0,0 +1,853 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module ClientNetworkConnection
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import signal
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
import hashlib
|
||||||
|
from tools import CGenericMultiPartTemp
|
||||||
|
from tools import Enum
|
||||||
|
from tools import CBitSet
|
||||||
|
from tools import World
|
||||||
|
from tools import CImpulseDecoder
|
||||||
|
from tools import DecodeImpulse
|
||||||
|
from tools import TStampQueue
|
||||||
|
from tools import BitStream
|
||||||
|
from tools import CodeMsgXml
|
||||||
|
from tools import CAction
|
||||||
|
from tools import CActionFactory
|
||||||
|
|
||||||
|
LOGGER='ClientNetworkConnection'
|
||||||
|
|
||||||
|
|
||||||
|
def getTextMD5(dataRawXml):
|
||||||
|
dataNew = ''
|
||||||
|
for data in dataRawXml:
|
||||||
|
if data != '\r': # '\015' ignore caractère \r\n =>
|
||||||
|
dataNew += data
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug("***** data:%d" % (ord(data)))
|
||||||
|
m = hashlib.md5()
|
||||||
|
m.update(dataNew.encode('utf-8'))
|
||||||
|
#print(m.hexdigest())
|
||||||
|
#print(m.digest())
|
||||||
|
return m.digest()
|
||||||
|
|
||||||
|
|
||||||
|
class ClientNetworkConnection:
|
||||||
|
'''
|
||||||
|
Partie client de la gestion de la communication reseau avec le serveur:
|
||||||
|
|
||||||
|
client :
|
||||||
|
code/ryzom/client/src/network_connection.cpp
|
||||||
|
server :
|
||||||
|
khanat-opennel-code/code/ryzom/server/src/frontend_service/fe_receive_sub.cpp # void CFeReceiveSub::handleReceivedMsg( CClientHost *clienthost )
|
||||||
|
'''
|
||||||
|
def __init__(self,
|
||||||
|
khanat_host,
|
||||||
|
khanat_port_frontend,
|
||||||
|
headAccount,
|
||||||
|
LanguageCode="fr",
|
||||||
|
checkMessageNumber = True):
|
||||||
|
self._CurrentSendNumber = 0
|
||||||
|
self.GenericMsgHeaderMngr = {}
|
||||||
|
self.GenericMultiPartTemp = CGenericMultiPartTemp.GenericMultiPartTemp()
|
||||||
|
self.LanguageCode = LanguageCode
|
||||||
|
self._QuitId = 0
|
||||||
|
self._ConnectionState = Enum.TConnectionState.NotInitialised
|
||||||
|
self.UserAddr, self.UserKey, self.UserId = None, None, None
|
||||||
|
self.frontend = (khanat_host, khanat_port_frontend)
|
||||||
|
self._sock = None
|
||||||
|
self._CurrentReceivedNumber = 0
|
||||||
|
self._SystemMode = 0
|
||||||
|
self._LastReceivedAck = 0
|
||||||
|
self._LastReceivedNumber = 0
|
||||||
|
self._LastAckInLongAck = 0
|
||||||
|
self._MsgXmlMD5 = None
|
||||||
|
self._DatabaseXmlMD5 = None
|
||||||
|
self.msgXml = None
|
||||||
|
self.databaseXml = None
|
||||||
|
self._Synchronize = 0
|
||||||
|
self._LatestSync = 0
|
||||||
|
self._CurrentServerTick = 0
|
||||||
|
self._MsPerTick = 0
|
||||||
|
self._LCT = 100
|
||||||
|
self._UpdateTime = 0
|
||||||
|
#self._UpdateTicks = 0
|
||||||
|
self._ReceivedSync = False
|
||||||
|
self._LastReceivedTime = 0
|
||||||
|
self._LastReceivedPacketInBothModes = 0
|
||||||
|
self._TotalMessages = 0
|
||||||
|
self._TotalLostPackets = 0
|
||||||
|
self.checkMessageNumber = checkMessageNumber
|
||||||
|
self._LastAckBit = 0
|
||||||
|
self._AckBitMask = 0
|
||||||
|
self._LongAckBitField = CBitSet.CBitSet()
|
||||||
|
self._LatestSyncTime = 0
|
||||||
|
self.headAccount = headAccount
|
||||||
|
self.world = World.World()
|
||||||
|
self._ImpulseDecoder = CImpulseDecoder.CImpulseDecoder(self.world)
|
||||||
|
self._LongAckBitField.resize(1024)
|
||||||
|
self._LatestProbeTime = 0
|
||||||
|
self._LatestProbe = 0
|
||||||
|
self._LatestProbes = []
|
||||||
|
self._LatestQuitTime = 0
|
||||||
|
self._ReceivedAckQuit = False
|
||||||
|
self._Actions = []
|
||||||
|
self._PacketStamps = []
|
||||||
|
self.decodeImpulse = DecodeImpulse.DecodeImpulse()
|
||||||
|
self._InstantPing = 0
|
||||||
|
self._BestPing = 10000
|
||||||
|
self._MsPerTick = 100
|
||||||
|
self._LastSendTime = 0
|
||||||
|
self._ImpulseMultiPartNumber = 0
|
||||||
|
self.clientTick = 0
|
||||||
|
self.stepAction = 0
|
||||||
|
|
||||||
|
def signal_exit(self, sig, frame):
|
||||||
|
logging.getLogger(LOGGER).warning("Receive signal to quit program")
|
||||||
|
self.sendSystemQuit()
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
signal.signal(signal.SIGINT, self.signal_exit)
|
||||||
|
signal.signal(signal.SIGTERM, self.signal_exit)
|
||||||
|
try:
|
||||||
|
self._sock = socket.socket(socket.AF_INET, # Internet
|
||||||
|
socket.SOCK_DGRAM) # UDP
|
||||||
|
except:
|
||||||
|
logging.getLogger(LOGGER).error("Impossible to connect on khanat")
|
||||||
|
return False
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Login
|
||||||
|
self._LatestSyncTime = int(time.clock_gettime(1)*1000)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def cookiesInit(self, UserAddr, UserKey, UserId):
|
||||||
|
self.UserAddr = UserAddr
|
||||||
|
self.UserKey = UserKey
|
||||||
|
self.UserId = UserId
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self._CurrentSendNumber += 0
|
||||||
|
|
||||||
|
def buildSystemHeader(self, msgout): # code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::buildSystemHeader(NLMISC::CBitMemStream &msgout)
|
||||||
|
msgout.pushSint32(self._CurrentSendNumber)
|
||||||
|
systemMode = True
|
||||||
|
msgout.pushBool(systemMode)
|
||||||
|
self._PacketStamps.append( TStampQueue.TStampQueue(self._CurrentSendNumber, self._UpdateTime) )
|
||||||
|
self._CurrentSendNumber += 1
|
||||||
|
|
||||||
|
def sendSystemLogin(self): # code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::sendSystemLogin()
|
||||||
|
logging.getLogger(LOGGER).debug("sendSystemLogin")
|
||||||
|
if self._sock is None:
|
||||||
|
raise ValueError
|
||||||
|
msgout = BitStream.BitStream()
|
||||||
|
self.buildSystemHeader(msgout)
|
||||||
|
msgout.pushUint8(Enum.CLFECOMMON.SYSTEM_LOGIN_CODE)
|
||||||
|
msgout.pushUint32(self.UserAddr)
|
||||||
|
msgout.pushUint32(self.UserKey)
|
||||||
|
msgout.pushUint32(self.UserId)
|
||||||
|
msgout.pushString(self.LanguageCode)
|
||||||
|
|
||||||
|
logging.getLogger(LOGGER).debug("sendSystemLogin:%s" % msgout.showAllDataWrite())
|
||||||
|
self._sock.sendto(msgout.toBytes(), self.frontend)
|
||||||
|
self._CurrentSendNumber += 1
|
||||||
|
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Login
|
||||||
|
|
||||||
|
def sendSystemQuit(self): # code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::sendSystemQuit()
|
||||||
|
logging.getLogger(LOGGER).debug("sendSystemQuit")
|
||||||
|
# Disconnect
|
||||||
|
if self._sock is None:
|
||||||
|
raise ValueError
|
||||||
|
self._QuitId += 1
|
||||||
|
msgout = BitStream.BitStream()
|
||||||
|
self.buildSystemHeader(msgout)
|
||||||
|
msgout.pushUint8(Enum.CLFECOMMON.SYSTEM_QUIT_CODE)
|
||||||
|
msgout.pushSint32(self._QuitId)
|
||||||
|
logging.getLogger(LOGGER).debug("sendSystemQuit:%s" % msgout.showAllDataWrite())
|
||||||
|
self._sock.sendto(msgout.toBytes(), self.frontend)
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Quit
|
||||||
|
|
||||||
|
def sendSystemAckSync(self):
|
||||||
|
'''
|
||||||
|
code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::sendSystemAckSync()
|
||||||
|
'''
|
||||||
|
logging.getLogger(LOGGER).debug("sendSystemAckSync _LastReceivedNumber:%d _LastAckInLongAck:%d _LatestSync:%d" % (self._LastReceivedNumber, self._LastAckInLongAck, self._LatestSync))
|
||||||
|
msgout = BitStream.BitStream()
|
||||||
|
self.buildSystemHeader(msgout)
|
||||||
|
msgout.pushUint8(Enum.CLFECOMMON.SYSTEM_ACK_SYNC_CODE)
|
||||||
|
msgout.pushSint32(self._LastReceivedNumber)
|
||||||
|
msgout.pushSint32(self._LastAckInLongAck)
|
||||||
|
self._LongAckBitField.writeSerial(msgout)
|
||||||
|
msgout.pushSint32(self._LatestSync)
|
||||||
|
|
||||||
|
logging.getLogger(LOGGER).debug("sendSystemAckSync:%s" % msgout.showAllDataWrite())
|
||||||
|
self._sock.sendto(msgout.toBytes(), self.frontend)
|
||||||
|
|
||||||
|
self._LatestSyncTime = self._UpdateTime
|
||||||
|
|
||||||
|
def sendSystemAckProbe(self):
|
||||||
|
logging.getLogger(LOGGER).debug("sendSystemAckProbe")
|
||||||
|
msgout = BitStream.BitStream()
|
||||||
|
self.buildSystemHeader(msgout)
|
||||||
|
msgout.pushUint8(Enum.CLFECOMMON.SYSTEM_ACK_PROBE_CODE)
|
||||||
|
msgout.pushSint32(len(self._LatestProbes))
|
||||||
|
for data in self._LatestProbes:
|
||||||
|
msgout.pushSint32(data)
|
||||||
|
self._LatestProbes = []
|
||||||
|
logging.getLogger(LOGGER).debug("sendSystemAckProbe:%s" % msgout.showAllDataWrite())
|
||||||
|
self._sock.sendto(msgout.toBytes(), self.frontend)
|
||||||
|
|
||||||
|
|
||||||
|
def sendSystemDisconnection(self):
|
||||||
|
logging.getLogger(LOGGER).debug("sendSystemDisconnection")
|
||||||
|
if self._sock is None:
|
||||||
|
raise ValueError
|
||||||
|
msgout = BitStream.BitStream()
|
||||||
|
self.buildSystemHeader(msgout)
|
||||||
|
msgout.pushUint8(Enum.CLFECOMMON.SYSTEM_DISCONNECTION_CODE)
|
||||||
|
self._sock.sendto(msgout.toBytes(), self.frontend)
|
||||||
|
|
||||||
|
def sendStringRequest(self, stringId):
|
||||||
|
# Launch query for StringID (we will rfeceived the full text
|
||||||
|
# khanat-opennel-code/code/ryzom/client/src/string_manager_client.cpp:333 bool CStringManagerClient::getString(uint32 stringId, ucstring &result)
|
||||||
|
# Send STRING_MANAGER:STRING_RQ
|
||||||
|
logging.getLogger(LOGGER).debug("sendStringRequest")
|
||||||
|
if self._sock is None:
|
||||||
|
raise ValueError
|
||||||
|
msgout = BitStream.BitStream()
|
||||||
|
ref = CodeMsgXml.CodeMsgXml(self.msgXml, 'STRING_MANAGER:STRING_RQ')
|
||||||
|
for size, value, id in ref:
|
||||||
|
msgout.internalSerial(value, size, typeName=id)
|
||||||
|
msgout.pushUint32(stringId)
|
||||||
|
self.push(msgout)
|
||||||
|
|
||||||
|
def sendNormalMessage(self):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::sendNormalMessage()
|
||||||
|
'''
|
||||||
|
logging.getLogger(LOGGER).debug("sendNormalMessage")
|
||||||
|
if self._sock is None:
|
||||||
|
raise ValueError
|
||||||
|
msgout = BitStream.BitStream()
|
||||||
|
msgout.pushSint32(self._CurrentSendNumber)
|
||||||
|
systemMode = False # Normal
|
||||||
|
msgout.pushBool(systemMode)
|
||||||
|
msgout.pushSint32(self._LastReceivedNumber)
|
||||||
|
msgout.pushSint32(self._AckBitMask)
|
||||||
|
|
||||||
|
numPacked = 0
|
||||||
|
|
||||||
|
for block in self._Actions:
|
||||||
|
if block.Cycle == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
if block.FirstPacket == 0:
|
||||||
|
block.FirstPacket = self._CurrentSendNumber;
|
||||||
|
|
||||||
|
block.writeSerial(msgout)
|
||||||
|
numPacked += 1
|
||||||
|
if msgout.getPosInBit() > 480*8: # easy version
|
||||||
|
break
|
||||||
|
|
||||||
|
logging.getLogger(LOGGER).debug("Send:%s" % msgout.showAllDataWrite())
|
||||||
|
self._sock.sendto(msgout.toBytes(), self.frontend)
|
||||||
|
|
||||||
|
self._LastSendTime = int(time.clock_gettime(1)*1000)
|
||||||
|
self._PacketStamps.append( TStampQueue.TStampQueue(self._CurrentSendNumber, self._UpdateTime) )
|
||||||
|
self._CurrentSendNumber += 1
|
||||||
|
|
||||||
|
def readDelta(self, msg):
|
||||||
|
propertyCount = msg.readUint16('propertyCount')
|
||||||
|
logging.getLogger(LOGGER).debug("propertyCount:%d" % propertyCount)
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
for _ in range(0, propertyCount):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def buildStream(self, buffersize=65536):
|
||||||
|
# khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # bool CNetworkConnection::buildStream( CBitMemStream &msgin )
|
||||||
|
data, addr = self._sock.recvfrom(buffersize)
|
||||||
|
return data, addr
|
||||||
|
|
||||||
|
def decodeHeader(self, msg):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # bool CNetworkConnection::decodeHeader(CBitMemStream &msgin, bool checkMessageNumber)
|
||||||
|
'''
|
||||||
|
self._TotalMessages += 1
|
||||||
|
self._LastReceivedTime = self._UpdateTime
|
||||||
|
self._CurrentReceivedNumber = msg.readSint32('CurrentReceivedNumber')
|
||||||
|
self._SystemMode = msg.readBool('SystemMode')
|
||||||
|
|
||||||
|
if self.checkMessageNumber and self._CurrentReceivedNumber > self._LastReceivedPacketInBothModes:
|
||||||
|
self._TotalLostPackets += self._CurrentReceivedNumber - self._LastReceivedPacketInBothModes - 1
|
||||||
|
self._LastReceivedPacketInBothModes = self._CurrentReceivedNumber
|
||||||
|
# else:
|
||||||
|
# self._LastReceivedPacketInBothModes = self._CurrentReceivedNumber - 1
|
||||||
|
|
||||||
|
if not self._SystemMode:
|
||||||
|
self._LastReceivedAck = msg.readSint32('LastReceivedAck');
|
||||||
|
logging.getLogger(LOGGER).debug("Normal Mode _LastReceivedAck:%d" % self._LastReceivedAck)
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug("System Mode")
|
||||||
|
|
||||||
|
if self._CurrentReceivedNumber > self._LastReceivedNumber+1:
|
||||||
|
logging.getLogger(LOGGER).debug("lost messages server->client [%d; %d]" %(self._LastReceivedPacketInBothModes + 1, self._CurrentReceivedNumber - 1))
|
||||||
|
elif self._CurrentReceivedNumber == self._LastReceivedNumber:
|
||||||
|
logging.getLogger(LOGGER).debug("awaiting packet %d, received packet %d" %(self._LastReceivedPacketInBothModes + 1, self._CurrentReceivedNumber))
|
||||||
|
return False
|
||||||
|
elif self._CurrentReceivedNumber < self._LastReceivedNumber:
|
||||||
|
logging.getLogger(LOGGER).debug("received an old message, awaiting packet %d, received packet %d" %(self._LastReceivedPacketInBothModes + 1, self._CurrentReceivedNumber))
|
||||||
|
return False
|
||||||
|
ackBool = ( not self._SystemMode ) and (self._ConnectionState == Enum.TConnectionState.Connected or self._ConnectionState == Enum.TConnectionState.Synchronize)
|
||||||
|
if ackBool:
|
||||||
|
ackBit = 1
|
||||||
|
else:
|
||||||
|
ackBit = 0
|
||||||
|
if self._CurrentReceivedNumber - self._LastReceivedNumber < 32:
|
||||||
|
self._AckBitMask <<= self._CurrentReceivedNumber - self._LastReceivedNumber
|
||||||
|
self._AckBitMask |= self._LastAckBit << (self._CurrentReceivedNumber - self._LastReceivedNumber - 1)
|
||||||
|
elif (self._CurrentReceivedNumber - self._LastReceivedNumber) == 32 and self._LastAckBit != 0:
|
||||||
|
self._AckBitMask = 0x80000000
|
||||||
|
else:
|
||||||
|
self._AckBitMask = 0x00000000
|
||||||
|
self._LastAckBit = ackBit;
|
||||||
|
for i in range(self._LastReceivedNumber+1, self._CurrentReceivedNumber):
|
||||||
|
self._LongAckBitField.clearBit(i & 511) # (512 - 1) mask 9bit
|
||||||
|
self._LongAckBitField.set(self._CurrentReceivedNumber & 511, ackBool) # (512 - 1) mask 9bit
|
||||||
|
|
||||||
|
logging.getLogger(LOGGER).debug("_LastAckInLongAck:%d _CurrentReceivedNumber:%d" % (self._LastAckInLongAck, self._CurrentReceivedNumber))
|
||||||
|
if self._LastAckInLongAck <= (self._CurrentReceivedNumber-512):
|
||||||
|
self._LastAckInLongAck = self._CurrentReceivedNumber-511; # (512 - 1) mask 9bit
|
||||||
|
|
||||||
|
self._LastReceivedNumber = self._CurrentReceivedNumber
|
||||||
|
logging.getLogger(LOGGER).debug("_CurrentReceivedNumber:%d, _LastReceivedNumber:%d, ackBit:%d, _AckBitMask:%d _LongAckBitField:%s" % (self._CurrentReceivedNumber, self._LastReceivedNumber, ackBit, self._AckBitMask, self._LongAckBitField))
|
||||||
|
return True
|
||||||
|
|
||||||
|
def receiveSystemProbe(self, msg):
|
||||||
|
logging.getLogger(LOGGER).debug("receiveSystemProbe")
|
||||||
|
self._LatestProbeTime = self._UpdateTime
|
||||||
|
self._LatestProbe = msg.readSint32('LatestProbe')
|
||||||
|
logging.getLogger(LOGGER).debug("LatestProbe: %d" % self._LatestProbe)
|
||||||
|
self._LatestProbes.append(self._LatestProbe)
|
||||||
|
logging.getLogger(LOGGER).debug("Msg Received:" + msg.showAllData())
|
||||||
|
|
||||||
|
def receiveSystemStalled(self, msg):
|
||||||
|
logging.getLogger(LOGGER).debug("received STALLED")
|
||||||
|
logging.getLogger(LOGGER).debug("Msg Received:" + msg.showAllData())
|
||||||
|
|
||||||
|
def receiveSystemSync(self, msg):
|
||||||
|
logging.getLogger(LOGGER).debug("receiveSystemSync")
|
||||||
|
self._LatestSyncTime = self._UpdateTime
|
||||||
|
self._Synchronize = msg.readUint32('Synchronize')
|
||||||
|
stime = msg.readSint64('stime')
|
||||||
|
self._LatestSync = msg.readUint32('LatestSync')
|
||||||
|
logging.getLogger(LOGGER).debug("%d %d %d" %(self._Synchronize, stime, self._LatestSync))
|
||||||
|
# khanat-opennel-code/code/ryzom/client/src/network_connection.cpp : void CNetworkConnection::receiveSystemSync(CBitMemStream &msgin)
|
||||||
|
MsgData = msg.readArrayUint8(16, 'MsgData')
|
||||||
|
DatabaseData = msg.readArrayUint8(16, 'DatabaseData')
|
||||||
|
logging.getLogger(LOGGER).debug("MsgData:" + str(MsgData))
|
||||||
|
logging.getLogger(LOGGER).debug("DatabaseData:" + str(DatabaseData))
|
||||||
|
md5Msg = bytes(MsgData)
|
||||||
|
md5Database = bytes(DatabaseData)
|
||||||
|
if md5Msg == self._MsgXmlMD5:
|
||||||
|
logging.getLogger(LOGGER).info("Check MD5 msg.xml : OK")
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).error("Check MD5 msg.xml : KO")
|
||||||
|
if md5Database == self._DatabaseXmlMD5:
|
||||||
|
logging.getLogger(LOGGER).info("Check MD5 database.xml : OK")
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).error("Check MD5 database.xml : KO")
|
||||||
|
logging.getLogger(LOGGER).debug("Msg Received:" + msg.showAllData())
|
||||||
|
self._MsPerTick = 100
|
||||||
|
self._CurrentServerTick = self._Synchronize + self._CurrentReceivedNumber + 2
|
||||||
|
self._CurrentClientTick = self._CurrentServerTick - ( self._LCT + self._MsPerTick ) / self._MsPerTick
|
||||||
|
self._CurrentClientTime = self._UpdateTime - (self._LCT + self._MsPerTick)
|
||||||
|
self.sendSystemAckSync()
|
||||||
|
|
||||||
|
def decodeVisualProperties(self, msgin):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::decodeVisualProperties( CBitMemStream& msgin )
|
||||||
|
'''
|
||||||
|
while True:
|
||||||
|
if msgin.getPosInBit() + 8*8 > len(msgin)*8:
|
||||||
|
return
|
||||||
|
slot = msgin.readUint8('slot')
|
||||||
|
associationBits = msgin.readUint32('associationBits')
|
||||||
|
logging.getLogger(LOGGER).debug("slot:%d associationBits:%d" %(slot, associationBits))
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
return
|
||||||
|
|
||||||
|
def receiveNormalMessage(self, msgin):
|
||||||
|
logging.getLogger(LOGGER).debug("receiveNormalMessage : received normal message Packet (%d) %s" % (msgin.needRead(), msgin.showLastData() ))
|
||||||
|
actions = self._ImpulseDecoder.decode(msgin, self._CurrentReceivedNumber, self._LastReceivedAck, self._CurrentSendNumber )
|
||||||
|
if actions:
|
||||||
|
logging.getLogger(LOGGER).debug('actions: ' +','.join( [ str(x) for x in actions] ) )
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug('actions: None')
|
||||||
|
logging.getLogger(LOGGER).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._LastReceivedAck:
|
||||||
|
logging.getLogger(LOGGER).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
|
||||||
|
|
||||||
|
# remove useless stamps in queue
|
||||||
|
while len(self._PacketStamps) != 0 and self._LastReceivedAck > self._PacketStamps[0].first:
|
||||||
|
self._PacketStamps.pop(0)
|
||||||
|
|
||||||
|
# Statistique !
|
||||||
|
if len(self._PacketStamps) == 0 or self._PacketStamps[0].first > self._LastReceivedAck:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
ackedPacketTime = self._PacketStamps[0].second
|
||||||
|
ping = self._UpdateTime - ackedPacketTime
|
||||||
|
self._InstantPing = ping
|
||||||
|
if ping < self._BestPing:
|
||||||
|
self._BestPing = ping
|
||||||
|
earliest = ackedPacketTime + self._BestPing//2
|
||||||
|
latest = self._UpdateTime - self._BestPing//2
|
||||||
|
|
||||||
|
numStepTick = self._CurrentServerTick - self._CurrentClientTick
|
||||||
|
if numStepTick > 0 and earliest > self._CurrentClientTime and latest > self._CurrentClientTime:
|
||||||
|
if self._CurrentClientTime + self._MsPerTick * numStepTick < earliest:
|
||||||
|
self._MsPerTick = (earliest - self._CurrentClientTime)//numStepTick
|
||||||
|
if (self._CurrentClientTime + self._MsPerTick * numStepTick) > latest:
|
||||||
|
self._MsPerTick = (latest - self._CurrentClientTime)//numStepTick
|
||||||
|
if self._MsPerTick == 0:
|
||||||
|
logging.getLogger(LOGGER).warning("_MsPerTick is 0 because server tick is too big %d compare to the client tick is %d" %(self._CurrentServerTick, self._CurrentClientTick))
|
||||||
|
self._MsPerTick = 1
|
||||||
|
elif numStepTick <= 0:
|
||||||
|
self._MsPerTick = self._LCT
|
||||||
|
|
||||||
|
|
||||||
|
## remove useless stamps in queue
|
||||||
|
#while self._PacketStamps and self._LastReceivedAck > self._PacketStamps[0].first:
|
||||||
|
# self._PacketStamps.pop(0)
|
||||||
|
if actions:
|
||||||
|
logging.getLogger(LOGGER).debug('list actions: [' + str(len(actions)) + '] ' +','.join( [ str(x) for x in actions] ) )
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug('list actions: None')
|
||||||
|
|
||||||
|
# Decode the actions received in the impulsions
|
||||||
|
logging.getLogger(LOGGER).debug('=' * 80)
|
||||||
|
for action in actions:
|
||||||
|
logging.getLogger(LOGGER).debug('-' * 80)
|
||||||
|
if action.Code == Enum.TActionCode.ACTION_DISCONNECTION_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Action : ACTION_DISCONNECTION_CODE")
|
||||||
|
self.disconnect()
|
||||||
|
elif action.Code == Enum.TActionCode.ACTION_GENERIC_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Action : ACTION_GENERIC_CODE")
|
||||||
|
action.genericAction(self.decodeImpulse, self.world, self.GenericMultiPartTemp)
|
||||||
|
logging.getLogger(LOGGER).info("Action: ACTION_GENERIC_CODE : %s" % action)
|
||||||
|
elif action.Code == Enum.TActionCode.ACTION_GENERIC_MULTI_PART_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Action : ACTION_GENERIC_MULTI_PART_CODE")
|
||||||
|
action.genericAction(self.decodeImpulse, self.world, self.GenericMultiPartTemp)
|
||||||
|
elif action.Code == Enum.TActionCode.ACTION_DUMMY_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Action : ACTION_DUMMY_CODE")
|
||||||
|
self._ImpulseDecoder.removeCAction(action)
|
||||||
|
|
||||||
|
# Decode the visual properties
|
||||||
|
self.decodeVisualProperties( msgin );
|
||||||
|
|
||||||
|
self._LastReceivedNormalTime = int(time.clock_gettime(1)*1000)
|
||||||
|
logging.getLogger(LOGGER).debug("Msg Received:" + msgin.showAllData())
|
||||||
|
|
||||||
|
def receiveSystemAckQuit(self, msgin):
|
||||||
|
logging.getLogger(LOGGER).debug("received ACK_QUIT")
|
||||||
|
self._ReceivedAckQuit = True
|
||||||
|
logging.getLogger(LOGGER).debug("Msg Received:" + msgin.showAllData())
|
||||||
|
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
logging.getLogger(LOGGER).info("Disconnect")
|
||||||
|
self.sendSystemDisconnection()
|
||||||
|
self._sock.close()
|
||||||
|
self._sock = None
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Disconnect
|
||||||
|
|
||||||
|
def stateLogin(self, msgin):
|
||||||
|
self.decodeHeader(msgin)
|
||||||
|
if self._SystemMode:
|
||||||
|
message = msgin.readUint8('message')
|
||||||
|
logging.getLogger(LOGGER).debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead()))
|
||||||
|
if message == Enum.CLFECOMMON.SYSTEM_SYNC_CODE:
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Synchronize
|
||||||
|
logging.getLogger(LOGGER).debug("Login->synchronize")
|
||||||
|
self.receiveSystemSync(msgin)
|
||||||
|
return True
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_STALLED_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("received STALLED")
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Stalled
|
||||||
|
self.receiveSystemStalled(msgin)
|
||||||
|
return True
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_PROBE_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Login->probe")
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Probe
|
||||||
|
self.receiveSystemProbe(msgin)
|
||||||
|
return True
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
|
||||||
|
self.disconnect()
|
||||||
|
logging.getLogger(LOGGER).warning("BACK-END DOWN")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning("CNET: received system %d in state Login" % message)
|
||||||
|
logging.getLogger(LOGGER).debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d] '%s'" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead(), msgin.showLastData()))
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning("CNET: received normal in state Login")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def stateSynchronize(self, msgin):
|
||||||
|
logging.getLogger(LOGGER).debug("stateSynchronize")
|
||||||
|
self.decodeHeader(msgin)
|
||||||
|
if self._SystemMode:
|
||||||
|
message = msgin.readUint8('message')
|
||||||
|
logging.getLogger(LOGGER).debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead()))
|
||||||
|
if message == Enum.CLFECOMMON.SYSTEM_PROBE_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("synchronize->probe")
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Probe
|
||||||
|
self.receiveSystemProbe(msgin)
|
||||||
|
return True
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_STALLED_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("received STALLED")
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Stalled
|
||||||
|
self.receiveSystemStalled(msgin)
|
||||||
|
return True
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_SYNC_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("synchronize->synchronize")
|
||||||
|
self.receiveSystemSync(msgin)
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
|
||||||
|
self.disconnect()
|
||||||
|
logging.getLogger(LOGGER).warning("BACK-END DOWN")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning("CNET: received system %d in state Synchronize" % message)
|
||||||
|
logging.getLogger(LOGGER).debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d] '%s'" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead(), msgin.showLastData()))
|
||||||
|
else:
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Connected
|
||||||
|
logging.getLogger(LOGGER).warning("CNET: synchronize->connected")
|
||||||
|
# _Changes.push_back(CChange(0, ConnectionReady));
|
||||||
|
self._ImpulseDecoder.reset();
|
||||||
|
self.receiveNormalMessage(msgin);
|
||||||
|
return True
|
||||||
|
logging.getLogger(LOGGER).debug("sendSystemAckSync ? (%d , %d , %d)" %(self._UpdateTime, self._LatestSyncTime, self._UpdateTime - self._LatestSyncTime))
|
||||||
|
if self._UpdateTime - self._LatestSyncTime > 300:
|
||||||
|
self.sendSystemAckSync();
|
||||||
|
return False
|
||||||
|
|
||||||
|
def stateConnected(self, msgin):
|
||||||
|
self.decodeHeader(msgin)
|
||||||
|
if self._SystemMode:
|
||||||
|
message = msgin.readUint8('message')
|
||||||
|
logging.getLogger(LOGGER).debug("SystemMode _CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead()))
|
||||||
|
if message == Enum.CLFECOMMON.SYSTEM_PROBE_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Connected->probe")
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Probe
|
||||||
|
self.receiveSystemProbe(msgin)
|
||||||
|
return True
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_SYNC_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("Connected->synchronize")
|
||||||
|
self.receiveSystemSync(msgin)
|
||||||
|
return True
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_STALLED_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("received STALLED")
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Stalled
|
||||||
|
self.receiveSystemStalled(msgin)
|
||||||
|
return True
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
|
||||||
|
self.disconnect()
|
||||||
|
logging.getLogger(LOGGER).warning("BACK-END DOWN")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning("CNET: received system %d in state Connected" % message)
|
||||||
|
logging.getLogger(LOGGER).debug("NormalMode _CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d] '%s'" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead(), msgin.showLastData()))
|
||||||
|
else:
|
||||||
|
self.receiveNormalMessage(msgin);
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def stateProbe(self, msgin):
|
||||||
|
self.decodeHeader(msgin)
|
||||||
|
if self._SystemMode:
|
||||||
|
message = msgin.readUint8('message')
|
||||||
|
logging.getLogger(LOGGER).debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead()))
|
||||||
|
if message == Enum.CLFECOMMON.SYSTEM_SYNC_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("probe->synchronize")
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Synchronize
|
||||||
|
self.receiveSystemSync(msgin)
|
||||||
|
return True
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_STALLED_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("probe->stalled")
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Stalled
|
||||||
|
self.receiveSystemStalled(msgin)
|
||||||
|
return True
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_PROBE_CODE:
|
||||||
|
self.receiveSystemProbe(msgin)
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
|
||||||
|
self.disconnect()
|
||||||
|
logging.getLogger(LOGGER).warning("BACK-END DOWN")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning("CNET: received system %d in state Probe" % message)
|
||||||
|
logging.getLogger(LOGGER).debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d] '%s'" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead(), msgin.showLastData()))
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning("received normal in state Probe")
|
||||||
|
|
||||||
|
if (len(self._LatestProbes) > 0) or (self._UpdateTime - self._LatestProbeTime > 300):
|
||||||
|
self.sendSystemAckProbe()
|
||||||
|
self._LatestProbeTime = self._UpdateTime
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def stateStalled(self, msgin):
|
||||||
|
self.decodeHeader(msgin)
|
||||||
|
if self._SystemMode:
|
||||||
|
message = msgin.readUint8('message')
|
||||||
|
logging.getLogger(LOGGER).debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead()))
|
||||||
|
if message == Enum.CLFECOMMON.SYSTEM_SYNC_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("stalled->synchronize")
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Synchronize
|
||||||
|
self.receiveSystemSync(msgin)
|
||||||
|
return True
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_PROBE_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("stalled->probe")
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Probe
|
||||||
|
self.receiveSystemProbe(msgin)
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_STALLED_CODE:
|
||||||
|
self.receiveSystemStalled(msgin)
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
|
||||||
|
self.disconnect()
|
||||||
|
logging.getLogger(LOGGER).warning("BACK-END DOWN")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning("CNET: received system %d in state Stalled" % message)
|
||||||
|
logging.getLogger(LOGGER).debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d] '%s'" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead(), msgin.showLastData()))
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning("received normal in state Stalled")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def stateQuit(self, msgin):
|
||||||
|
self.decodeHeader(msgin)
|
||||||
|
if self._SystemMode:
|
||||||
|
message = msgin.readUint8('message')
|
||||||
|
logging.getLogger(LOGGER).debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead()))
|
||||||
|
if message == Enum.CLFECOMMON.SYSTEM_SYNC_CODE:
|
||||||
|
logging.getLogger(LOGGER).debug("quit->synchronize")
|
||||||
|
self._ConnectionState = Enum.TConnectionState.Synchronize
|
||||||
|
self.receiveSystemSync(msgin)
|
||||||
|
return True
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
|
||||||
|
self.disconnect()
|
||||||
|
logging.getLogger(LOGGER).warning("BACK-END DOWN")
|
||||||
|
return False
|
||||||
|
elif message == Enum.CLFECOMMON.SYSTEM_ACK_QUIT_CODE:
|
||||||
|
self.receiveSystemAckQuit(msgin)
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning("CNET: received system %d in state Quit" % message)
|
||||||
|
logging.getLogger(LOGGER).debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d] '%s'" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead(), msgin.showLastData()))
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).warning("received normal in state Quit")
|
||||||
|
if not self._ReceivedAckQuit and (self._UpdateTime - self._LatestQuitTime > 100):
|
||||||
|
self.sendSystemQuit()
|
||||||
|
self._LatestQuitTime = self._UpdateTime
|
||||||
|
return False
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
# khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # bool CNetworkConnection::update()
|
||||||
|
self._UpdateTime = int(time.clock_gettime(1)*1000)
|
||||||
|
self._ReceivedSync = False
|
||||||
|
|
||||||
|
if not self._sock:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# TODO - REMOVE this counter (just to stop loop)
|
||||||
|
counterLoop = 0
|
||||||
|
|
||||||
|
stateBroke = True
|
||||||
|
while stateBroke:
|
||||||
|
buffer, addr = self.buildStream()
|
||||||
|
msgin = BitStream.BitStream()
|
||||||
|
msgin.fromBytes(buffer)
|
||||||
|
logging.getLogger(LOGGER).debug("received message: %s" % msgin.showAllData())
|
||||||
|
if self._ConnectionState == Enum.TConnectionState.Login:
|
||||||
|
logging.getLogger(LOGGER).debug("state:Login")
|
||||||
|
stateBroke = self.stateLogin(msgin)
|
||||||
|
elif self._ConnectionState == Enum.TConnectionState.Synchronize:
|
||||||
|
logging.getLogger(LOGGER).debug("state:Synchronize")
|
||||||
|
stateBroke = self.stateSynchronize(msgin)
|
||||||
|
elif self._ConnectionState == Enum.TConnectionState.Connected:
|
||||||
|
logging.getLogger(LOGGER).debug("state:Connected")
|
||||||
|
stateBroke = self.stateConnected(msgin)
|
||||||
|
elif self._ConnectionState == Enum.TConnectionState.Probe:
|
||||||
|
logging.getLogger(LOGGER).debug("state:Probe")
|
||||||
|
stateBroke = self.stateProbe(msgin)
|
||||||
|
elif self._ConnectionState == Enum.TConnectionState.Stalled:
|
||||||
|
logging.getLogger(LOGGER).debug("state:Stalled")
|
||||||
|
stateBroke = self.stateStalled(msgin)
|
||||||
|
elif self._ConnectionState == Enum.TConnectionState.Quit:
|
||||||
|
logging.getLogger(LOGGER).debug("state:Quit")
|
||||||
|
stateBroke = self.stateQuit(msgin)
|
||||||
|
else:
|
||||||
|
stateBroke = False
|
||||||
|
logging.getLogger(LOGGER).debug("message decoded: %s" % msgin.showAllData())
|
||||||
|
counterLoop += 1
|
||||||
|
if counterLoop > 10:
|
||||||
|
break
|
||||||
|
|
||||||
|
def push_back(self, action):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::push(CAction *action)
|
||||||
|
'''
|
||||||
|
# search to aggregate Action (send by block)
|
||||||
|
if len(self._Actions) == 0 or self._Actions[-1].Cycle != 0:
|
||||||
|
self._Actions.append(CAction.CActionBlock())
|
||||||
|
self._Actions[-1].push_back(action)
|
||||||
|
|
||||||
|
def push(self, msgout):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::push(CBitMemStream &msg)
|
||||||
|
'''
|
||||||
|
logging.getLogger(LOGGER).debug("Push :%s" % msgout.showAllDataWrite())
|
||||||
|
maxImpulseBitSize = 1840 # = 230*8
|
||||||
|
cp = CActionFactory.CActionFactory(self.world)
|
||||||
|
ag = cp.createFactory(CAction.INVALID_SLOT, Enum.TActionCode.ACTION_GENERIC_CODE)
|
||||||
|
bytelen = (msgout.sizeData() + 7) // 8
|
||||||
|
impulseMinBitSize = ag.size()
|
||||||
|
impulseBitSize = impulseMinBitSize + (4 + bytelen)*8
|
||||||
|
logging.getLogger(LOGGER).debug("maxImpulseBitSize:%d bytelen:%d impulseMinBitSize:%d impulseBitSize:%d" %(maxImpulseBitSize, bytelen, impulseMinBitSize, impulseBitSize))
|
||||||
|
if impulseBitSize < maxImpulseBitSize:
|
||||||
|
ag.set(msgout);
|
||||||
|
self.push_back(ag)
|
||||||
|
else:
|
||||||
|
agmp = cp.createFactory(CAction.INVALID_SLOT, Enum.TActionCode.ACTION_GENERIC_MULTI_PART_CODE)
|
||||||
|
minimumBitSizeForMP = agmp.size()
|
||||||
|
availableSize = (maxImpulseBitSize - minimumBitSizeForMP) // 8
|
||||||
|
nbBlock = (bytelen + availableSize - 1) // availableSize
|
||||||
|
num = self._ImpulseMultiPartNumber
|
||||||
|
self._ImpulseMultiPartNumber += 1
|
||||||
|
logging.getLogger(LOGGER).debug("minimumBitSizeForMP:%d availableSize:%d nbBlock:%d num:%d _ImpulseMultiPartNumber:%d" % (minimumBitSizeForMP, availableSize, nbBlock, num, self._ImpulseMultiPartNumber))
|
||||||
|
for i in range(0, nbBlock):
|
||||||
|
logging.getLogger(LOGGER).debug("i:%d nbBlock:%d" % (i, nbBlock))
|
||||||
|
if i != 0:
|
||||||
|
# Create a new CActionFactory
|
||||||
|
agmp = cp.createFactory(CAction.INVALID_SLOT, Enum.TActionCode.ACTION_GENERIC_MULTI_PART_CODE)
|
||||||
|
agmp.set(num, i, msgout.buffer(), bytelen, availableSize, nbBlock)
|
||||||
|
self.push_back(agmp)
|
||||||
|
|
||||||
|
def sendFastMode(self):
|
||||||
|
if self._ConnectionState == Enum.TConnectionState.Connected and self._LastSendTime > 100:
|
||||||
|
self.sendNormalMessage()
|
||||||
|
|
||||||
|
def send(self):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::send(TGameCycle cycle)
|
||||||
|
'''
|
||||||
|
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:
|
||||||
|
logging.getLogger(LOGGER).debug("No Action")
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug("Prepare Action")
|
||||||
|
block = self._Actions[-1]
|
||||||
|
block.Cycle = cycle
|
||||||
|
# check last block isn't bigger than maximum allowed
|
||||||
|
i = 0
|
||||||
|
for action in block.Actions:
|
||||||
|
bitSize += action.size()
|
||||||
|
if bitSize >= 480*8:
|
||||||
|
break
|
||||||
|
i += 1
|
||||||
|
if i < len(self._Actions):
|
||||||
|
# Too big block -> split block
|
||||||
|
newBlock = CAction.CActionBlock()
|
||||||
|
newBlock.Cylce = 0
|
||||||
|
newBlock.insert(self._Actions, i, len(block.Actions))
|
||||||
|
block.eraseToEnd(i)
|
||||||
|
|
||||||
|
if self._ConnectionState == Enum.TConnectionState.Connected:
|
||||||
|
self.sendNormalMessage()
|
||||||
|
|
||||||
|
#if len(self.world.Commands) > 0:
|
||||||
|
# cmd = self.world.Commands.pop(0)
|
||||||
|
|
||||||
|
def analyze(self):
|
||||||
|
for id, data in self.world.StringManager.unknown:
|
||||||
|
logging.getLogger(LOGGER).debug("id:%d, data:%s" % (id, data.showAllData()))
|
||||||
|
self.sendStringRequest(id)
|
||||||
|
for id in self.world.StringManager.unknownParameterString:
|
||||||
|
logging.getLogger(LOGGER).debug("id:%d" % (id))
|
||||||
|
self.sendStringRequest(id)
|
||||||
|
for msg in self.world.StringManager.decoded:
|
||||||
|
logging.getLogger(LOGGER).info("message:%s" % (msg))
|
||||||
|
self.world.StringManager.cleanDecodedMessage()
|
||||||
|
if self.world.CurrentState == Enum.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 == Enum.TPeople.Unknown:
|
||||||
|
bms = self.world.CreaterCharacter(self.msgXml, self.headAccount)
|
||||||
|
self.push(bms)
|
||||||
|
self.stepAction = 1
|
||||||
|
else:
|
||||||
|
self.stepAction = 1
|
||||||
|
elif self.stepAction == 1 and self.world.CharacterSummaries != []:
|
||||||
|
if self.world.CharacterSummaries[0].People != Enum.TPeople.Unknown:
|
||||||
|
logging.getLogger(LOGGER).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 = Enum.TState.st_start
|
||||||
|
self.msgXml = ET.fromstring(msgRawXml)
|
||||||
|
#ET.dump(msgXml)
|
||||||
|
self.databaseXml = ET.fromstring(databaseRawXml)
|
||||||
|
#ET.dump(databaseXml)
|
||||||
|
|
||||||
|
self._MsgXmlMD5 = getTextMD5(msgRawXml)
|
||||||
|
self._DatabaseXmlMD5 = getTextMD5(databaseRawXml)
|
||||||
|
|
||||||
|
self.decodeImpulse.loadMsg(self.msgXml)
|
||||||
|
self.decodeImpulse.loadDatabase(self.databaseXml)
|
||||||
|
|
||||||
|
self.connect()
|
||||||
|
logging.getLogger(LOGGER).info("Client Login")
|
||||||
|
self.sendSystemLogin()
|
||||||
|
self.world.CurrentState = Enum.TState.st_connect
|
||||||
|
|
||||||
|
logging.getLogger(LOGGER).info("Receive Message")
|
||||||
|
self.clientTick = 0
|
||||||
|
for _ in range(0, 50):
|
||||||
|
#while True:
|
||||||
|
logging.getLogger(LOGGER).debug("%s [%s: %d / %d] %s" % ("*" * 40, "Loop", self.clientTick, self.stepAction, "*" * 40))
|
||||||
|
self.update()
|
||||||
|
self.analyze()
|
||||||
|
self.send()
|
||||||
|
self.clientTick += 1
|
||||||
|
|
||||||
|
logging.getLogger(LOGGER).info("Client Quit")
|
||||||
|
self.sendSystemQuit()
|
||||||
|
|
||||||
|
|
44
tools/CodeMsgXml.py
Normal file
44
tools/CodeMsgXml.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CodeMsgXml
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from tools import getPowerOf2
|
||||||
|
|
||||||
|
LOGGER='CodeMsgXml'
|
||||||
|
|
||||||
|
def CodeMsgXml(msgXml, key):
|
||||||
|
head = msgXml
|
||||||
|
listpath = key.split(':')
|
||||||
|
ret = []
|
||||||
|
for id in listpath:
|
||||||
|
nbBit = getPowerOf2.getPowerOf2(len(head))
|
||||||
|
found = False
|
||||||
|
i = 0
|
||||||
|
for ele in head:
|
||||||
|
if ele.attrib['name'] == id:
|
||||||
|
found = True
|
||||||
|
ret.append([nbBit, i, id])
|
||||||
|
break
|
||||||
|
i +=1
|
||||||
|
if not found:
|
||||||
|
logging.getLogger(LOGGER).error("Impossible to found value (all key:%s, value:%s)" % (key, id))
|
||||||
|
raise ValueError
|
||||||
|
head = ele
|
||||||
|
return ret
|
573
tools/DecodeImpulse.py
Normal file
573
tools/DecodeImpulse.py
Normal file
|
@ -0,0 +1,573 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module DecodeImpulse
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
#from tools import BitStream
|
||||||
|
from tools import getPowerOf2
|
||||||
|
from tools import CShardName
|
||||||
|
from tools import CCharacterSummary
|
||||||
|
from tools import CMainlandSummary
|
||||||
|
|
||||||
|
|
||||||
|
LOGGER='DecodeImpulse'
|
||||||
|
|
||||||
|
class DecodeImpulse():
|
||||||
|
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 updatePatcherPriorityBasedOnCharacters(self, world):
|
||||||
|
logging.getLogger(LOGGER).debug('Load character')
|
||||||
|
hasMainlandChar = False
|
||||||
|
for ele in world.CharacterSummaries:
|
||||||
|
if ele.Name == "":
|
||||||
|
continue
|
||||||
|
if not ele.InNewbieland:
|
||||||
|
hasMainlandChar = True
|
||||||
|
break
|
||||||
|
if hasMainlandChar:
|
||||||
|
logging.getLogger(LOGGER).debug('hasMainlandChar : True')
|
||||||
|
else:
|
||||||
|
logging.getLogger(LOGGER).debug('hasMainlandChar : False')
|
||||||
|
# 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.BitStream()
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseDatabaseUpdatePlayer(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO:%s" % msgin)
|
||||||
|
def impulseUpdateInventory(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseInitInventory(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseDatabaseUpdateBank(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseDatabaseInitBank(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseDatabaseResetBank(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseNoUserChar(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseUserChars(self, msgin, world):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/net_manager.cpp # void impulseUserChars(NLMISC::CBitMemStream &impulse)
|
||||||
|
'''
|
||||||
|
world.ServerPeopleActive = msgin.readUint8('ServerPeopleActive')
|
||||||
|
world.ServerCareerActive = msgin.readUint8('ServerCareerActive')
|
||||||
|
# impulse.serialCont (CharacterSummaries);
|
||||||
|
world.CharacterSummaries = []
|
||||||
|
size = msgin.readUint32('CharacterSummaries:len')
|
||||||
|
logging.getLogger(LOGGER).debug(msgin.showAllData())
|
||||||
|
logging.getLogger(LOGGER).debug("size:%d" % size)
|
||||||
|
for _ in range(0, size):
|
||||||
|
tmp = CCharacterSummary.CCharacterSummary()
|
||||||
|
tmp.read(msgin)
|
||||||
|
world.CharacterSummaries.append(tmp)
|
||||||
|
# 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.CShardName(int(shardNames[i*3+0]), shardNames[i*3+1], shardNames[i*3+2])
|
||||||
|
world.CShardNames.append(tmp)
|
||||||
|
|
||||||
|
#_, shardNames = msgin.readCont('shardNames')
|
||||||
|
# readPrivileges(impulse);
|
||||||
|
world.UserPrivileges = msgin.readString('UserPrivileges')
|
||||||
|
world.FreeTrial = msgin.readBool('FreeTrial')
|
||||||
|
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.CMainlandSummary()
|
||||||
|
tmp.read(msgin)
|
||||||
|
world.Mainlands.append(tmp)
|
||||||
|
self.updatePatcherPriorityBasedOnCharacters(world); # Load player config from server to client
|
||||||
|
|
||||||
|
def impulseUserChar(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseFarTP(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseServerReady(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseCharNameValid(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseShardId(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseServerQuitOk(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseServerQuitAbort(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseMailNotification(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseForumNotification(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulsePermanentBan(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulsePermanentUnban(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseChat(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseTell(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseFarTell(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseChat2(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseDynString(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def inpulseDynStringInChatGroup(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseTell2(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseTP(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseTPWithSeason(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseCorrectPos(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseCombatEngageFailed(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseDynChatOpen(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseDynChatClose(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseBeginCast(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseTeamInvitation(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseTeamShareOpen(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseTeamShareInvalid(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseTeamShareClose(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseTeamContactInit(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseTeamContactCreate(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseTeamContactStatus(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseTeamContactRemove(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseExchangeInvitation(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseExchangeCloseInvitation(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseMountAbort(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseWhere(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseCounter(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
|
||||||
|
def impulsePhraseSend(self, msgin, world):
|
||||||
|
# khanat-opennel-code/code/ryzom/client/src/net_manager.cpp:2283 void impulsePhraseSend(NLMISC::CBitMemStream &impulse)
|
||||||
|
dynId = msgin.readUint32('dynId')
|
||||||
|
logging.getLogger(LOGGER).debug("dynId:%d" % dynId)
|
||||||
|
StringId = msgin.readUint32('StringId')
|
||||||
|
logging.getLogger(LOGGER).debug("dynId:%d StringId:%s" % (dynId, StringId))
|
||||||
|
world.StringManager.receiveMessage(StringId, msgin.getNotRead())
|
||||||
|
|
||||||
|
def impulseStringResp(self, msgin, world):
|
||||||
|
# khanat-opennel-code/code/ryzom/client/src/net_manager.cpp:2295 void impulseStringResp(NLMISC::CBitMemStream &impulse)
|
||||||
|
StringId = msgin.readUint32('StringId')
|
||||||
|
strUtf8 = msgin.toBytes()
|
||||||
|
strUtf8 = msgin.readUtf8String('strUtf8')
|
||||||
|
logging.getLogger(LOGGER).debug("StringId:%d strUtf8:%s" % (StringId, strUtf8))
|
||||||
|
world.StringManager.receiveTemplate(StringId, strUtf8)
|
||||||
|
|
||||||
|
def impulseReloadCache(self, msgin, world):
|
||||||
|
world.timestamp = msgin.readUint32('timestamp')
|
||||||
|
logging.getLogger(LOGGER).debug("Reload Cache timestamp:%d" % world.timestamp)
|
||||||
|
logging.getLogger(LOGGER).debug("Message not read (%d) %s" % (msgin.needRead(), msgin.showLastData() ))
|
||||||
|
|
||||||
|
def impulseBotChatForceEnd(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseJournalInitCompletedMissions(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseJournalUpdateCompletedMissions(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
|
||||||
|
def impulseJournalAddCompass(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseJournalRemoveCompass(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseGuildJoinProposal(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseGuildAscensor(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseGuildLeaveAscensor(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseGuildAbortCreation(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseGuildOpenGuildWindow(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseGuildOpenInventory(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseGuildCloseInventory(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseGuildUpdatePlayerTitle(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseGuildUseFemaleTitles(self, msgin, world):
|
||||||
|
world.UseFemaleTitles = msgin.readBool('UseFemaleTitles')
|
||||||
|
logging.getLogger(LOGGER).debug("UseFemaleTitles")
|
||||||
|
|
||||||
|
def impulseCloseTempInv(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseRemoteAdmin(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulsePhraseDownLoad(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulsePhraseConfirmBuy(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulsePhraseAckExecuteCyclic(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulsePhraseAckExecuteNext(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseItemInfoSet(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseItemInfoRefreshVersion(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulsePrereqInfoSet(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseItemOpenRoomInventory(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseItemCloseRoomInventory(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseDeathRespawnPoint(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseDeathRespawn(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseDuelInvitation(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseDuelCancelInvitation(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulsePVPChallengeInvitation(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulsePVPChallengeCancelInvitation(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulsePVPFactionPushFactionWar(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulsePVPFactionPopFactionWar(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulsePVPFactionFactionWars(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseEncyclopediaUpdate(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseEncyclopediaInit(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseUserBars(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseUserPopup(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
|
||||||
|
def impulseEnterCrZoneProposal(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseCloseEnterCrZoneProposal(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
|
||||||
|
def cbImpulsionGatewayOpen(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def cbImpulsionGatewayMessage (self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def cbImpulsionGatewayClose (self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseOutpostChooseSide (self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseOutpostDeclareWarAck (self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseCombatFlyingChaScore1Delta (self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseCombatFlyingTextItemSpecialEffectProc (self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseCombatFlyingText (self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseSetSeason (self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseDssDown (self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseSetNpcIconDesc (self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseServerEventForMissionAvailability (self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
def impulseSetNpcIconTimer (self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def impulseDatabaseInitPlayer(self, msgin, world):
|
||||||
|
logging.getLogger(LOGGER).debug("TODO")
|
||||||
|
|
||||||
|
def initializeNetwork(self):
|
||||||
|
self.GenericMsgHeaderMngr.setdefault('DB_UPD_PLR', self.impulseDatabaseUpdatePlayer)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault('DB_INIT:PLR', self.impulseDatabaseInitPlayer)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("DB_UPD_INV", self.impulseUpdateInventory)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("DB_INIT:INV", self.impulseInitInventory)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("DB_GROUP:UPDATE_BANK", self.impulseDatabaseUpdateBank)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("DB_GROUP:INIT_BANK", self.impulseDatabaseInitBank)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("DB_GROUP:RESET_BANK", self.impulseDatabaseResetBank)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:NO_USER_CHAR", self.impulseNoUserChar)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:USER_CHARS", self.impulseUserChars)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:USER_CHAR", self.impulseUserChar)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:FAR_TP", self.impulseFarTP)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:READY", self.impulseServerReady)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:VALID_NAME", self.impulseCharNameValid)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:SHARD_ID", self.impulseShardId)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:SERVER_QUIT_OK", self.impulseServerQuitOk)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:SERVER_QUIT_ABORT", self.impulseServerQuitAbort)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:MAIL_AVAILABLE", self.impulseMailNotification)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:GUILD_MESSAGE_AVAILABLE", self.impulseForumNotification)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:PERMANENT_BAN", self.impulsePermanentBan)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CONNECTION:UNBAN", self.impulsePermanentUnban)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("STRING:CHAT", self.impulseChat)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("STRING:TELL", self.impulseTell)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("STRING:FAR_TELL", self.impulseFarTell)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("STRING:CHAT2", self.impulseChat2)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("STRING:DYN_STRING", self.impulseDynString)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("STRING:DYN_STRING_GROUP", self.inpulseDynStringInChatGroup)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("STRING:TELL2", self.impulseTell2)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("TP:DEST", self.impulseTP)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("TP:DEST_WITH_SEASON", self.impulseTPWithSeason)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("TP:CORRECT", self.impulseCorrectPos)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("COMBAT:ENGAGE_FAILED", self.impulseCombatEngageFailed)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("BOTCHAT:DYNCHAT_OPEN", self.impulseDynChatOpen)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("BOTCHAT:DYNCHAT_CLOSE", self.impulseDynChatClose)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("CASTING:BEGIN", self.impulseBeginCast)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("TEAM:INVITATION", self.impulseTeamInvitation)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("TEAM:SHARE_OPEN", self.impulseTeamShareOpen)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("TEAM:SHARE_INVALID", self.impulseTeamShareInvalid)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("TEAM:SHARE_CLOSE", self.impulseTeamShareClose)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("TEAM:CONTACT_INIT", self.impulseTeamContactInit)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("TEAM:CONTACT_CREATE", self.impulseTeamContactCreate)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("TEAM:CONTACT_STATUS", self.impulseTeamContactStatus)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("TEAM:CONTACT_REMOVE", self.impulseTeamContactRemove)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("EXCHANGE:INVITATION", self.impulseExchangeInvitation)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("EXCHANGE:CLOSE_INVITATION", self.impulseExchangeCloseInvitation)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("ANIMALS:MOUNT_ABORT", self.impulseMountAbort)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("DEBUG:REPLY_WHERE", self.impulseWhere)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("DEBUG:COUNTER", self.impulseCounter)
|
||||||
|
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("STRING_MANAGER:PHRASE_SEND", self.impulsePhraseSend)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("STRING_MANAGER:STRING_RESP", self.impulseStringResp)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("STRING_MANAGER:RELOAD_CACHE", self.impulseReloadCache)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("BOTCHAT:FORCE_END", self.impulseBotChatForceEnd)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("JOURNAL:INIT_COMPLETED_MISSIONS", self.impulseJournalInitCompletedMissions)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("JOURNAL:UPDATE_COMPLETED_MISSIONS", self.impulseJournalUpdateCompletedMissions)
|
||||||
|
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("JOURNAL:ADD_COMPASS", self.impulseJournalAddCompass)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("JOURNAL:REMOVE_COMPASS", self.impulseJournalRemoveCompass)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("GUILD:JOIN_PROPOSAL", self.impulseGuildJoinProposal)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("GUILD:ASCENSOR", self.impulseGuildAscensor)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("GUILD:LEAVE_ASCENSOR", self.impulseGuildLeaveAscensor)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("GUILD:ABORT_CREATION", self.impulseGuildAbortCreation)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("GUILD:OPEN_GUILD_WINDOW", self.impulseGuildOpenGuildWindow)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("GUILD:OPEN_INVENTORY", self.impulseGuildOpenInventory)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("GUILD:CLOSE_INVENTORY", self.impulseGuildCloseInventory)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("GUILD:UPDATE_PLAYER_TITLE", self.impulseGuildUpdatePlayerTitle)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("GUILD:USE_FEMALE_TITLES", self.impulseGuildUseFemaleTitles)
|
||||||
|
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("HARVEST:CLOSE_TEMP_INVENTORY", self.impulseCloseTempInv)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("COMMAND:REMOTE_ADMIN", self.impulseRemoteAdmin)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("PHRASE:DOWNLOAD", self.impulsePhraseDownLoad)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("PHRASE:CONFIRM_BUY", self.impulsePhraseConfirmBuy)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("PHRASE:EXEC_CYCLIC_ACK", self.impulsePhraseAckExecuteCyclic)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("PHRASE:EXEC_NEXT_ACK", self.impulsePhraseAckExecuteNext)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("ITEM_INFO:SET", self.impulseItemInfoSet)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("ITEM_INFO:REFRESH_VERSION", self.impulseItemInfoRefreshVersion)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("MISSION_PREREQ:SET", self.impulsePrereqInfoSet)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("ITEM:OPEN_ROOM_INVENTORY", self.impulseItemOpenRoomInventory)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("ITEM:CLOSE_ROOM_INVENTORY", self.impulseItemCloseRoomInventory)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("DEATH:RESPAWN_POINT", self.impulseDeathRespawnPoint)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("DEATH:RESPAWN", self.impulseDeathRespawn)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("DUEL:INVITATION", self.impulseDuelInvitation)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("DUEL:CANCEL_INVITATION", self.impulseDuelCancelInvitation)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("PVP_CHALLENGE:INVITATION", self.impulsePVPChallengeInvitation)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("PVP_CHALLENGE:CANCEL_INVITATION", self.impulsePVPChallengeCancelInvitation)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("PVP_FACTION:PUSH_FACTION_WAR", self.impulsePVPFactionPushFactionWar)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("PVP_FACTION:POP_FACTION_WAR", self.impulsePVPFactionPopFactionWar)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("PVP_FACTION:FACTION_WARS", self.impulsePVPFactionFactionWars)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("ENCYCLOPEDIA:UPDATE", self.impulseEncyclopediaUpdate)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("ENCYCLOPEDIA:INIT", self.impulseEncyclopediaInit)
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("USER:BARS", self.impulseUserBars)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("USER:POPUP", self.impulseUserPopup)
|
||||||
|
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("MISSION:ASK_ENTER_CRITICAL", self.impulseEnterCrZoneProposal)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault("MISSION:CLOSE_ENTER_CRITICAL", self.impulseCloseEnterCrZoneProposal)
|
||||||
|
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "MODULE_GATEWAY:FEOPEN", self.cbImpulsionGatewayOpen)
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "MODULE_GATEWAY:GATEWAY_MSG", self.cbImpulsionGatewayMessage )
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "MODULE_GATEWAY:FECLOSE", self.cbImpulsionGatewayClose )
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "OUTPOST:CHOOSE_SIDE", self.impulseOutpostChooseSide )
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "OUTPOST:DECLARE_WAR_ACK", self.impulseOutpostDeclareWarAck )
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "COMBAT:FLYING_ChaScore1_DELTA", self.impulseCombatFlyingChaScore1Delta )
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "COMBAT:FLYING_TEXT_ISE", self.impulseCombatFlyingTextItemSpecialEffectProc )
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "COMBAT:FLYING_TEXT", self.impulseCombatFlyingText )
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "SEASON:SET", self.impulseSetSeason )
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "RING_MISSION:DSS_DOWN", self.impulseDssDown )
|
||||||
|
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "NPC_ICON:SET_DESC", self.impulseSetNpcIconDesc )
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "NPC_ICON:SVR_EVENT_MIS_AVL", self.impulseServerEventForMissionAvailability )
|
||||||
|
self.GenericMsgHeaderMngr.setdefault( "NPC_ICON:SET_TIMER", self.impulseSetNpcIconTimer )
|
||||||
|
|
||||||
|
def sizeElement(self, keys = None):
|
||||||
|
head = self.msgXml
|
||||||
|
if not keys:
|
||||||
|
return len(head)
|
||||||
|
ret = len(head)
|
||||||
|
for key in keys.split(':'):
|
||||||
|
for ele in head:
|
||||||
|
if ele.attrib['name'] == key:
|
||||||
|
head = ele
|
||||||
|
ret = len(head)
|
||||||
|
break
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def searchElement(self, keys):
|
||||||
|
ret = []
|
||||||
|
head = self.msgXml
|
||||||
|
logging.getLogger(LOGGER).debug(len(head))
|
||||||
|
for key in keys.split(':'):
|
||||||
|
#print(key)
|
||||||
|
id = 0
|
||||||
|
for ele in head:
|
||||||
|
if ele.attrib['name'] == key:
|
||||||
|
logging.getLogger(LOGGER).debug('%s => %d' % (key, id))
|
||||||
|
ret.append(id)
|
||||||
|
head = ele
|
||||||
|
break
|
||||||
|
id += 1
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def execute(self, msgin, world):
|
||||||
|
'''
|
||||||
|
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))
|
||||||
|
id = msgin.readSerial(nbBit, name='MsgXML', typeName='Number', emulate=True)
|
||||||
|
|
||||||
|
ele = head[id]
|
||||||
|
name = ele.attrib['name']
|
||||||
|
listpath.append(name)
|
||||||
|
fullname = ':'.join(listpath)
|
||||||
|
|
||||||
|
id = msgin.readSerial(nbBit, name='MsgXML', typeName='XML <' + name + '>')
|
||||||
|
logging.getLogger(LOGGER).debug(fullname)
|
||||||
|
if fullname in self.GenericMsgHeaderMngr:
|
||||||
|
logging.getLogger(LOGGER).debug("Found : %s" % fullname)
|
||||||
|
self.GenericMsgHeaderMngr[fullname](msgin, world)
|
||||||
|
logging.getLogger(LOGGER).debug("MessageXML decoded: %s" % msgin.showAllData() )
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
#logging.getLogger(LOGGER).debug("Non trouve")
|
||||||
|
for ele in head:
|
||||||
|
if ele.attrib['name'] == name:
|
||||||
|
head = ele
|
||||||
|
break
|
||||||
|
if head != ele:
|
||||||
|
logging.getLogger(LOGGER).error("Impossible to found %s" % fullname )
|
||||||
|
logging.getLogger(LOGGER).debug("MessageXML decoded: %s" % msgin.showAllData() )
|
||||||
|
return False
|
||||||
|
# End While
|
||||||
|
logging.getLogger(LOGGER).debug("MessageXML decoded: %s" % msgin.showAllData() )
|
||||||
|
return False
|
||||||
|
|
||||||
|
def loadMsg(self, msgXml):
|
||||||
|
self.msgXml = msgXml
|
||||||
|
|
||||||
|
def loadDatabase(self, databaseXml):
|
||||||
|
self.databaseXml = databaseXml
|
565
tools/Enum.py
Normal file
565
tools/Enum.py
Normal file
|
@ -0,0 +1,565 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module CLFECOMMON
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
class TConnectionState(IntEnum):
|
||||||
|
NotInitialised = 0 # nothing happened yet
|
||||||
|
NotConnected = 1 # init() called
|
||||||
|
Authenticate = 2 # connect() called, identified by the login server
|
||||||
|
Login = 3 # connecting to the frontend, sending identification
|
||||||
|
Synchronize = 4 # connection accepted by the frontend, synchronizing
|
||||||
|
Connected = 5 # synchronized, connected, ready to work
|
||||||
|
Probe = 6 # connection lost by frontend, probing for response
|
||||||
|
Stalled = 7 # server is stalled
|
||||||
|
Disconnect = 8 # disconnect() called, or timeout, or connection closed by frontend
|
||||||
|
Quit = 9 # quit() called
|
||||||
|
|
||||||
|
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
|
||||||
|
neutral = 2
|
||||||
|
unknown = 4
|
||||||
|
|
||||||
|
|
||||||
|
class TPeople(IntEnum):
|
||||||
|
Undefined = -1
|
||||||
|
Humanoid = 0
|
||||||
|
Playable = 0
|
||||||
|
Fyros = 0
|
||||||
|
Matis = 1
|
||||||
|
Tryker = 2
|
||||||
|
Zorai = 3
|
||||||
|
EndPlayable = 4
|
||||||
|
Karavan = 4
|
||||||
|
Tribe = 5
|
||||||
|
Common = 6
|
||||||
|
EndHumanoid = 7
|
||||||
|
Creature = 7
|
||||||
|
Fauna = 7
|
||||||
|
Arma = 7
|
||||||
|
Balduse = 8
|
||||||
|
Bul = 9
|
||||||
|
Capryni = 10
|
||||||
|
Chonari = 11
|
||||||
|
Clapclap = 12
|
||||||
|
Cococlaw = 13
|
||||||
|
Cute = 14
|
||||||
|
Dag = 15
|
||||||
|
Diranak = 16
|
||||||
|
Estrasson = 17
|
||||||
|
Filin = 18
|
||||||
|
Frahar = 19
|
||||||
|
Gibbai = 20
|
||||||
|
Hachtaha = 21
|
||||||
|
Jungler = 22
|
||||||
|
Kakty = 23
|
||||||
|
Kalab = 24
|
||||||
|
Kami = 25
|
||||||
|
Kazoar = 26
|
||||||
|
Kitin = 27
|
||||||
|
Kitins = 28
|
||||||
|
Kitifly = 28
|
||||||
|
Kitihank = 29
|
||||||
|
Kitiharak = 30
|
||||||
|
Kitikil = 31
|
||||||
|
Kitimandib = 32
|
||||||
|
Kitinagan = 33
|
||||||
|
Kitinega = 34
|
||||||
|
Kitinokto = 35
|
||||||
|
EndKitins = 36
|
||||||
|
Lightbird = 36
|
||||||
|
Mektoub = 37
|
||||||
|
MektoubPacker = 38
|
||||||
|
MektoubMount = 39
|
||||||
|
Pucetron = 40
|
||||||
|
Regus = 41
|
||||||
|
Ryzerb = 42
|
||||||
|
Ryzoholo = 43
|
||||||
|
Ryzoholok = 44
|
||||||
|
Vampignon = 45
|
||||||
|
Varinx = 46
|
||||||
|
Yber = 47
|
||||||
|
Zerx = 48
|
||||||
|
race_c1 = 49
|
||||||
|
race_c2 = 50
|
||||||
|
race_c3 = 51
|
||||||
|
race_c4 = 52
|
||||||
|
race_c5 = 53
|
||||||
|
race_c6 = 54
|
||||||
|
race_c7 = 55
|
||||||
|
race_h1 = 56
|
||||||
|
race_h2 = 57
|
||||||
|
race_h3 = 58
|
||||||
|
race_h4 = 59
|
||||||
|
race_h5 = 60
|
||||||
|
race_h6 = 61
|
||||||
|
race_h7 = 62
|
||||||
|
race_h8 = 63
|
||||||
|
race_h9 = 64
|
||||||
|
race_h10 = 65
|
||||||
|
race_h11 = 66
|
||||||
|
race_h12 = 67
|
||||||
|
EndFauna = 68
|
||||||
|
Flora = 68
|
||||||
|
Cephaloplant = 68
|
||||||
|
Electroalgs = 69
|
||||||
|
Phytopsy = 70
|
||||||
|
SapEnslaver = 71
|
||||||
|
SpittingWeeds = 72
|
||||||
|
Swarmplants = 73
|
||||||
|
EndFlora = 74
|
||||||
|
Goo = 74
|
||||||
|
GooFauna = 74
|
||||||
|
GooArma = 74
|
||||||
|
GooBalduse = 75
|
||||||
|
GooBul = 76
|
||||||
|
GooCapryni = 77
|
||||||
|
GooChonari = 78
|
||||||
|
GooClapclap = 79
|
||||||
|
GooCococlaw = 80
|
||||||
|
GooCute = 81
|
||||||
|
GooDag = 82
|
||||||
|
GooDiranak = 83
|
||||||
|
GooEstrasson = 84
|
||||||
|
GooFilin = 85
|
||||||
|
GooFrahar = 86
|
||||||
|
GooGibbai = 87
|
||||||
|
GooHachtaha = 88
|
||||||
|
GooJungler = 89
|
||||||
|
GooKakty = 90
|
||||||
|
GooKalab = 91
|
||||||
|
GooKami = 92
|
||||||
|
GooKazoar = 93
|
||||||
|
GooKitifly = 94
|
||||||
|
GooKitihank = 95
|
||||||
|
GooKitiharak = 96
|
||||||
|
GooKitikil = 97
|
||||||
|
GooKitimandib = 98
|
||||||
|
GooKitin = 99
|
||||||
|
GooKitinagan = 100
|
||||||
|
GooKitinega = 101
|
||||||
|
GooKitinokto = 102
|
||||||
|
GooLightbird = 103
|
||||||
|
GooMektoub = 104
|
||||||
|
GooMektoubPacker = 105
|
||||||
|
GooMektoubMount = 106
|
||||||
|
GooPucetron = 107
|
||||||
|
GooRegus = 108
|
||||||
|
GooRyzerb = 109
|
||||||
|
GooRyzoholo = 110
|
||||||
|
GooRyzoholok = 111
|
||||||
|
GooVampignon = 112
|
||||||
|
GooVarinx = 113
|
||||||
|
GooYber = 114
|
||||||
|
GooZerx = 115
|
||||||
|
Goorace_c1 = 116
|
||||||
|
Goorace_c2 = 117
|
||||||
|
Goorace_c3 = 118
|
||||||
|
Goorace_c4 = 119
|
||||||
|
Goorace_c5 = 120
|
||||||
|
Goorace_c6 = 121
|
||||||
|
Goorace_c7 = 122
|
||||||
|
Goorace_h1 = 123
|
||||||
|
Goorace_h2 = 124
|
||||||
|
Goorace_h3 = 125
|
||||||
|
Goorace_h4 = 126
|
||||||
|
Goorace_h5 = 127
|
||||||
|
Goorace_h6 = 128
|
||||||
|
Goorace_h7 = 129
|
||||||
|
Goorace_h8 = 130
|
||||||
|
Goorace_h9 = 131
|
||||||
|
Goorace_h10 = 132
|
||||||
|
Goorace_h11 = 133
|
||||||
|
Goorace_h12 = 134
|
||||||
|
EndGooFauna = 135
|
||||||
|
GooPlant = 135
|
||||||
|
GooCephaloplant = 135
|
||||||
|
GooElectroalgs = 136
|
||||||
|
GooPhytopsy = 137
|
||||||
|
GooSapEnslaver = 138
|
||||||
|
GooSpittingWeeds = 139
|
||||||
|
GooSwarmplants = 140
|
||||||
|
EndGooPlant = 141
|
||||||
|
EndGoo = 141
|
||||||
|
EndCreature = 141
|
||||||
|
___TPeople_useSize = 142
|
||||||
|
Unknown = 142
|
||||||
|
EndPeople = 142
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ECharacterTitle(IntEnum):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/common/src/game_share/character_title.h # enum ECharacterTitle
|
||||||
|
'''
|
||||||
|
Refugee = 0
|
||||||
|
Homin = 1 #
|
||||||
|
Novice_Artisan = 2 #
|
||||||
|
Novice_Warrior = 3 #
|
||||||
|
Novice_Harvester = 4 #
|
||||||
|
Novice_Magician = 5 #
|
||||||
|
Artisan_Apprentice = 6 #
|
||||||
|
Magician_Apprentice = 7 #
|
||||||
|
Defensive_Magician = 8 #
|
||||||
|
Offensive_Magician = 9 #
|
||||||
|
Mentalist = 10 #
|
||||||
|
Summoner = 11 #
|
||||||
|
Master_Of_Illusion = 12 #
|
||||||
|
Mind_Lord = 13 #
|
||||||
|
Healer = 14 #
|
||||||
|
Priest = 15 #
|
||||||
|
Master_Of_Life = 16 #
|
||||||
|
Celestial_Guardian = 17 #
|
||||||
|
Disturber = 18 #
|
||||||
|
Affliction_Bringer = 19 #
|
||||||
|
Master_Of_Torment = 20 #
|
||||||
|
Avatar_Of_Sorrow = 21 #
|
||||||
|
Destroyer = 22 #
|
||||||
|
Archmage = 23 #
|
||||||
|
Master_Of_Pain = 24 #
|
||||||
|
Avatar_Of_Destruction = 25 #
|
||||||
|
Elementalist = 26 #
|
||||||
|
Alchemist = 27 #
|
||||||
|
Biomancer = 28 #
|
||||||
|
Master_Of_Energies = 29 #
|
||||||
|
Chosen_Of_Atys = 30 #
|
||||||
|
Warrior_Apprentice = 31 #
|
||||||
|
Melee_Warrior = 32 #
|
||||||
|
Range_Fighter = 33 #
|
||||||
|
Light_Armsman = 34 #
|
||||||
|
Heavy_Armsman = 35 #
|
||||||
|
Close_Fighter = 36 #
|
||||||
|
Gunman = 37 #
|
||||||
|
Heavy_Gunman = 38 #
|
||||||
|
Advanced_Gunman = 39 #
|
||||||
|
Advanced_Heavy_Gunman = 40 #
|
||||||
|
Bludgeoner = 41 #
|
||||||
|
Skewerer = 42 #
|
||||||
|
Slasher = 43 #
|
||||||
|
Smasher = 44 #
|
||||||
|
Impaler = 45 #
|
||||||
|
Cleaver = 46 #
|
||||||
|
Advanced_Close_Fighter = 47 #
|
||||||
|
Maceman = 48 #
|
||||||
|
Brute = 49 #
|
||||||
|
Spearman = 50 #
|
||||||
|
Axeman = 51 #
|
||||||
|
Swordsman = 52 #
|
||||||
|
Heavy_Maceman = 53 #
|
||||||
|
Pikeman = 54 #
|
||||||
|
Heavy_Axeman = 55 #
|
||||||
|
Heavy_Swordsman = 56 #
|
||||||
|
Knifeman = 57 #
|
||||||
|
Hand_To_Hand_Fighter = 58 #
|
||||||
|
Bowman = 59 #
|
||||||
|
Pistoleer = 60 #
|
||||||
|
Heavy_Bowman = 61 #
|
||||||
|
Artilleryman = 62 #
|
||||||
|
Rifleman = 63 #
|
||||||
|
Master_Maceman = 64 #
|
||||||
|
Master_Brute = 65 #
|
||||||
|
Master_Spearman = 66 #
|
||||||
|
Master_Axeman = 67 #
|
||||||
|
Master_Swordsman = 68 #
|
||||||
|
Master_Heavy_Maceman = 69 #
|
||||||
|
Master_Pikeman = 70 #
|
||||||
|
Master_Heavy_Axeman = 71 #
|
||||||
|
Master_Heavy_Swordsman = 72 #
|
||||||
|
Master_Knifeman = 73 #
|
||||||
|
Master_Hand_To_Hand_Fighter = 74 #
|
||||||
|
Master_Bowman = 75 #
|
||||||
|
Master_Pistoleer = 76 #
|
||||||
|
Master_Heavy_Bowman = 77 #
|
||||||
|
Master_Artilleryman = 78 #
|
||||||
|
Master_Rifleman = 79 #
|
||||||
|
Armorer_Apprentice = 80 #
|
||||||
|
Jeweler_Apprentice = 81 #
|
||||||
|
Melee_Weapon_Smith_Apprentice = 82 #
|
||||||
|
Range_Weapon_Smith_Apprentice = 83 #
|
||||||
|
Heavy_Armorer = 84 #
|
||||||
|
Light_Armorer = 85 #
|
||||||
|
Medium_Armorer = 86 #
|
||||||
|
Shield_Smith = 87 #
|
||||||
|
Jeweler = 88 #
|
||||||
|
Melee_Weapon_Smith = 89 #
|
||||||
|
Melee_Heavy_Weapon_Smith = 90 #
|
||||||
|
Melee_Light_Weapon_Smith = 91 #
|
||||||
|
Range_Weapon_Smith = 92 #
|
||||||
|
Range_Heavy_Weapon_Smith = 93 #
|
||||||
|
Advanced_Heavy_Armorer = 94 #
|
||||||
|
Advanced_Light_Armorer = 95 #
|
||||||
|
Advanced_Medium_Armorer = 96 #
|
||||||
|
Advanced_Shield_Smith = 97 #
|
||||||
|
Advanced_Jeweler = 98 #
|
||||||
|
Advanced_Melee_Weapon_Smith = 99 #
|
||||||
|
Advanced_Melee_Heavy_Weapon_Smith = 100 #
|
||||||
|
Advanced_Melee_Light_Weapon_Smith = 101 #
|
||||||
|
Advanced_Range_Weapon_Smith = 102 #
|
||||||
|
Advanced_Range_Heavy_Weapon_Smith = 103 #
|
||||||
|
Expert_Heavy_Armorer = 104 #
|
||||||
|
Expert_Light_Armorer = 105 #
|
||||||
|
Expert_Medium_Armorer = 106 #
|
||||||
|
Expert_Shield_Smith = 107 #
|
||||||
|
Expert_Jeweler = 108 #
|
||||||
|
Expert_Melee_Weapon_Smith = 109 #
|
||||||
|
Expert_Melee_Heavy_Weapon_Smith = 110 #
|
||||||
|
Expert_Melee_Light_Weapon_Smith = 111 #
|
||||||
|
Expert_Range_Weapon_Smith = 112 #
|
||||||
|
Expert_Range_Heavy_Weapon_Smith = 113 #
|
||||||
|
Heavy_Armorer_Master = 114 #
|
||||||
|
Light_Armorer_Master = 115 #
|
||||||
|
Medium_Armorer_Master = 116 #
|
||||||
|
Shield_Smith_Master = 117 #
|
||||||
|
Jeweler_Master = 118 #
|
||||||
|
Melee_Weapon_Smith_Master = 119 #
|
||||||
|
Melee_Heavy_Weapon_Smith_Master = 120 #
|
||||||
|
Melee_Light_Weapon_Smith_Master = 121 #
|
||||||
|
Range_Weapon_Smith_Master = 122 #
|
||||||
|
Range_Heavy_Weapon_Smith_Master = 123 #
|
||||||
|
Forager_Apprentice = 124 #
|
||||||
|
Forager = 125 #
|
||||||
|
Desert_Forager = 126 #
|
||||||
|
Forest_Forager = 127 #
|
||||||
|
Jungle_Forager = 128 #
|
||||||
|
Lacustre_Forager = 129 #
|
||||||
|
Prime_Roots_Forager = 130 #
|
||||||
|
Advanced_Desert_Forager = 131 #
|
||||||
|
Advanced_Forest_Forager = 132 #
|
||||||
|
Advanced_Jungle_Forager = 133 #
|
||||||
|
Advanced_Lacustre_Forager = 134 #
|
||||||
|
Advanced_Prime_Roots_Forager = 135 #
|
||||||
|
Expert_Desert_Forager = 136 #
|
||||||
|
Expert_Forest_Forager = 137 #
|
||||||
|
Expert_Jungle_Forager = 138 #
|
||||||
|
Expert_Lacustre_Forager = 139 #
|
||||||
|
Expert_Prime_Roots_Forager = 140 #
|
||||||
|
Master_Desert_Forager = 141 #
|
||||||
|
Master_Forest_Forager = 142 #
|
||||||
|
Master_Jungle_Forager = 143 #
|
||||||
|
Master_Lacustre_Forager = 144 #
|
||||||
|
Master_Prime_Roots_Forager = 145 #
|
||||||
|
Kami_Ally = 146 #
|
||||||
|
Karavan_Ally = 147 #
|
||||||
|
Title00000 = 148 #
|
||||||
|
Title00001 = 149 # // Journeyer
|
||||||
|
Title00002 = 150 # // Novice Kitin Hunter
|
||||||
|
Title00003 = 151 # // Kitin Hunter
|
||||||
|
Title00004 = 152 # // Master Kitin Hunter
|
||||||
|
Title00005 = 153 # // Kitin Eradicator
|
||||||
|
Title00006 = 154 # // Kitin Mass Murderer
|
||||||
|
Title00007 = 155 # // Matis Guardian
|
||||||
|
Title00008 = 156 # // Fyros Guardian
|
||||||
|
Title00009 = 157 # // Tryker Guardian
|
||||||
|
Title00010 = 158 # // Zorai Guardian
|
||||||
|
Title00011 = 159 # // Atys Guardian
|
||||||
|
Title00012 = 160 #
|
||||||
|
Title00013 = 161 #
|
||||||
|
Title00014 = 162 # // The fortunate
|
||||||
|
Title00015 = 163 # // Jinxed
|
||||||
|
Title00016 = 164 #
|
||||||
|
Title00017 = 165 #
|
||||||
|
Title00018 = 166 #
|
||||||
|
Title00019 = 167 #
|
||||||
|
Title00020 = 168 # // Fyros Patriot
|
||||||
|
Title00021 = 169 # // Matis Vassal
|
||||||
|
Title00022 = 170 # // Tryker Citizen
|
||||||
|
Title00023 = 171 # // Zorai Initiate
|
||||||
|
Title00024 = 172 # // Kami Disciple
|
||||||
|
Title00025 = 173 # // Karavan Follower
|
||||||
|
Title00026 = 174 # // Fyros Akenak
|
||||||
|
Title00027 = 175 # // Matis Noble
|
||||||
|
Title00028 = 176 # // Tryker Taliar
|
||||||
|
Title00029 = 177 # // Zorai Awakened
|
||||||
|
Title00030 = 178 # // Marauder
|
||||||
|
Title00031 = 179 # // Fyros Ambassador
|
||||||
|
Title00032 = 180 # // Matis Ambassador
|
||||||
|
Title00033 = 181 # // Tryker Ambassador
|
||||||
|
Title00034 = 182 # // Zorai Ambassador
|
||||||
|
Title00035 = 183 #
|
||||||
|
Title00036 = 184 #
|
||||||
|
Title00037 = 185 #
|
||||||
|
Title00038 = 186 #
|
||||||
|
Title00039 = 187 #
|
||||||
|
Title00040 = 188 #
|
||||||
|
Title00041 = 189 #
|
||||||
|
Title00042 = 190 #
|
||||||
|
Title00043 = 191 #
|
||||||
|
Title00044 = 192 #
|
||||||
|
Title00045 = 193 #
|
||||||
|
Title00046 = 194 #
|
||||||
|
Title00047 = 195 # // Machinegunner
|
||||||
|
Title00048 = 196 # // Assault Machinegunner
|
||||||
|
Title00049 = 197 #
|
||||||
|
Title00050 = 198 # // Apprentice Butcher
|
||||||
|
Title00051 = 199 # // Butcher
|
||||||
|
Title00052 = 200 # // Apprentice Florist
|
||||||
|
Title00053 = 201 # // Florist
|
||||||
|
Title00054 = 202 # // Apprentice Water-Carrier
|
||||||
|
Title00055 = 203 # // Water-Carrier
|
||||||
|
Title00056 = 204 # // Apprentice Magnetic
|
||||||
|
Title00057 = 205 # // Magnetic Cartographe
|
||||||
|
Title00058 = 206 # // Apprentice Toolmaker
|
||||||
|
Title00059 = 207 # // Toolmaker
|
||||||
|
Title00060 = 208 # // Apprentice Rescuer
|
||||||
|
Title00061 = 209 # // Rescuer
|
||||||
|
Title00062 = 210 # // Apprentice Larvester
|
||||||
|
Title00063 = 211 # // Larvester
|
||||||
|
Title00064 = 212 # // Apprentice Scrollmaker
|
||||||
|
Title00065 = 213 # // Scrollmaker
|
||||||
|
Title00066 = 214 #
|
||||||
|
Title00067 = 215 #
|
||||||
|
Title00068 = 216 #
|
||||||
|
Title00069 = 217 #
|
||||||
|
Title00070 = 218 #
|
||||||
|
Title00071 = 219 #
|
||||||
|
Title00072 = 220 #
|
||||||
|
Title00073 = 221 #
|
||||||
|
Title00074 = 222 #
|
||||||
|
Title00075 = 223 #
|
||||||
|
Title00076 = 224 #
|
||||||
|
Title00077 = 225 #
|
||||||
|
Title00078 = 226 #
|
||||||
|
Title00079 = 227 # // Wayfarer
|
||||||
|
WIND = Title00079 # // Title for player come from old Windermmer community
|
||||||
|
FBT = 228 #
|
||||||
|
BeginGmTitle = 229 #
|
||||||
|
# SGM = BeginGmTitle #
|
||||||
|
GM = 230 #
|
||||||
|
VG = 231 #
|
||||||
|
SG = 232 #
|
||||||
|
G = 233 #
|
||||||
|
CM = 234 #
|
||||||
|
EM = 235 #
|
||||||
|
EG = 236 #
|
||||||
|
OBSERVER = 237 #
|
||||||
|
# EndGmTitle = OBSERVER,
|
||||||
|
NB_CHARACTER_TITLE = 238
|
||||||
|
|
||||||
|
|
||||||
|
class CLFECOMMON(IntEnum):
|
||||||
|
SYSTEM_LOGIN_CODE = 0
|
||||||
|
SYSTEM_SYNC_CODE = 1
|
||||||
|
SYSTEM_ACK_SYNC_CODE = 2
|
||||||
|
SYSTEM_PROBE_CODE = 3
|
||||||
|
SYSTEM_ACK_PROBE_CODE = 4
|
||||||
|
SYSTEM_DISCONNECTION_CODE = 5
|
||||||
|
SYSTEM_STALLED_CODE = 6
|
||||||
|
SYSTEM_SERVER_DOWN_CODE = 7
|
||||||
|
SYSTEM_QUIT_CODE = 8
|
||||||
|
SYSTEM_ACK_QUIT_CODE = 9
|
||||||
|
NumBitsInLongAck = 512
|
||||||
|
|
||||||
|
class TActionCode(IntEnum):
|
||||||
|
ACTION_POSITION_CODE = 0
|
||||||
|
ACTION_GENERIC_CODE = 1
|
||||||
|
ACTION_GENERIC_MULTI_PART_CODE = 2
|
||||||
|
ACTION_SINT64 = 3
|
||||||
|
ACTION_SYNC_CODE = 10
|
||||||
|
ACTION_DISCONNECTION_CODE = 11
|
||||||
|
ACTION_ASSOCIATION_CODE = 12
|
||||||
|
ACTION_LOGIN_CODE = 13
|
||||||
|
ACTION_TARGET_SLOT_CODE = 40
|
||||||
|
ACTION_DUMMY_CODE = 99
|
||||||
|
|
||||||
|
class Card(IntEnum):
|
||||||
|
BEGIN_TOKEN = 0
|
||||||
|
END_TOKEN = 1
|
||||||
|
SINT_TOKEN = 2
|
||||||
|
UINT_TOKEN = 3
|
||||||
|
FLOAT_TOKEN = 4
|
||||||
|
STRING_TOKEN = 5
|
||||||
|
FLAG_TOKEN = 6
|
||||||
|
EXTEND_TOKEN = 7
|
||||||
|
|
||||||
|
class TType(IntEnum):
|
||||||
|
STRUCT_BEGIN = 0
|
||||||
|
STRUCT_END = 1
|
||||||
|
FLAG = 2
|
||||||
|
SINT32 = 3
|
||||||
|
UINT32 = 4
|
||||||
|
FLOAT32 = 5
|
||||||
|
STRING = 6
|
||||||
|
SINT64 = 7
|
||||||
|
UINT64 = 8
|
||||||
|
FLOAT64 = 9
|
||||||
|
EXTEND_TYPE = 10
|
||||||
|
NB_TYPE = 11
|
24
tools/TExtendType.py
Normal file
24
tools/TExtendType.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module TExtendType
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
class TExtendType:
|
||||||
|
ET_SHEET_ID = 0
|
||||||
|
ET_64_BIT_EXTENDED_TYPES = 0x80000000
|
||||||
|
ET_ENTITY_ID = 0x80000000 # ET_ENTITY_ID = ET_64_BIT_EXTENDED_TYPES
|
27
tools/TMessageType.py
Normal file
27
tools/TMessageType.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module TMessageType
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
class TMessageType(IntEnum):
|
||||||
|
OneWay = 0
|
||||||
|
Request = 1
|
||||||
|
Response = 2
|
||||||
|
Except = 3
|
39
tools/TPVPMode.py
Normal file
39
tools/TPVPMode.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module TPropIndex
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
class TPVPMode(IntEnum):
|
||||||
|
none : 0
|
||||||
|
PvpDuel : 1
|
||||||
|
PvpChallenge : 2
|
||||||
|
PvpZoneFree : 4
|
||||||
|
PvpZoneFaction : 8
|
||||||
|
PvpZoneGuild : 16
|
||||||
|
PvpZoneOutpost : 32
|
||||||
|
PvpFaction : 64
|
||||||
|
PvpFactionFlagged : 128
|
||||||
|
PvpZoneSafe : 256
|
||||||
|
PvpSafe : 512
|
||||||
|
Unknown : 513
|
||||||
|
|
||||||
|
NbModes = 513
|
||||||
|
NbBits = 10 # number of bits needed to store all valid values
|
91
tools/TPropIndex.py
Normal file
91
tools/TPropIndex.py
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module TPropIndex
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
from enum import IntEnum
|
||||||
|
import math
|
||||||
|
|
||||||
|
# Ref : khanat-opennel-code/code/ryzom/common/src/game_share/entity_types.h
|
||||||
|
|
||||||
|
MAX_THRESHOLD = (1024*1024)
|
||||||
|
|
||||||
|
class TPropIndex(IntEnum):
|
||||||
|
PROPERTY_POSITION = 0
|
||||||
|
PROPERTY_POSX = 0
|
||||||
|
PROPERTY_POSY = 1
|
||||||
|
PROPERTY_POSZ = 2
|
||||||
|
PROPERTY_ORIENTATION = 3
|
||||||
|
PROPERTY_SHEET = 4
|
||||||
|
PROPERTY_BEHAVIOUR = 5
|
||||||
|
PROPERTY_NAME_STRING_ID = 6
|
||||||
|
PROPERTY_TARGET_ID = 7
|
||||||
|
PROPERTY_MODE = 8
|
||||||
|
PROPERTY_VPA = 9
|
||||||
|
PROPERTY_VPB = 10
|
||||||
|
PROPERTY_VPC = 11
|
||||||
|
PROPERTY_ENTITY_MOUNTED_ID = 12
|
||||||
|
PROPERTY_RIDER_ENTITY_ID = 13
|
||||||
|
PROPERTY_CONTEXTUAL = 14
|
||||||
|
PROPERTY_BARS = 15
|
||||||
|
PROPERTY_TARGET_LIST = 16
|
||||||
|
PROPERTY_TARGET_LIST_0 = 16
|
||||||
|
PROPERTY_TARGET_LIST_1 = 17
|
||||||
|
PROPERTY_TARGET_LIST_2 = 18
|
||||||
|
PROPERTY_TARGET_LIST_3 = 19
|
||||||
|
PROPERTY_GUILD_SYMBOL = 20
|
||||||
|
PROPERTY_GUILD_NAME_ID = 21
|
||||||
|
PROPERTY_VISUAL_FX = 22
|
||||||
|
PROPERTY_EVENT_FACTION_ID = 23
|
||||||
|
PROPERTY_PVP_MODE = 24
|
||||||
|
PROPERTY_PVP_CLAN = 25
|
||||||
|
PROPERTY_OWNER_PEOPLE = 26
|
||||||
|
PROPERTY_OUTPOST_INFOS = 27
|
||||||
|
INVALID_PROP_INDEX = 0xff
|
||||||
|
|
||||||
|
THRESHOLD_SHEET = MAX_THRESHOLD
|
||||||
|
THRESHOLD_BEHAVIOUR = 60000
|
||||||
|
THRESHOLD_NAME_STRING_ID = 100000
|
||||||
|
THRESHOLD_TARGET_ID = 60000
|
||||||
|
THRESHOLD_TARGET_ID_CLIENT_M = 55.0
|
||||||
|
THRESHOLD_MODE = MAX_THRESHOLD
|
||||||
|
THRESHOLD_VPA = MAX_THRESHOLD
|
||||||
|
THRESHOLD_VPB = MAX_THRESHOLD
|
||||||
|
THRESHOLD_VPC = 10000
|
||||||
|
THRESHOLD_ENTITY_MOUNTED_ID = MAX_THRESHOLD
|
||||||
|
THRESHOLD_CONTEXTUAL = 100000
|
||||||
|
THRESHOLD_CONTEXTUAL_NPC = MAX_THRESHOLD
|
||||||
|
THRESHOLD_BARS = 30000
|
||||||
|
THRESHOLD_BARS_CLIENT_M = 28.0
|
||||||
|
THRESHOLD_TARGET_LIST = (100000 * math.sqrt(2.0))
|
||||||
|
THRESHOLD_GUILD_SYMBOL = MAX_THRESHOLD
|
||||||
|
THRESHOLD_GUILD_NAME_ID = MAX_THRESHOLD
|
||||||
|
THRESHOLD_VISUAL_FX = 30000
|
||||||
|
THRESHOLD_EVENT_FACTION_ID = 60000
|
||||||
|
THRESHOLD_PVP_MODE = 60000
|
||||||
|
THRESHOLD_PVP_CLAN = 60000
|
||||||
|
THRESHOLD_OWNER_PEOPLE = 60000
|
||||||
|
THRESHOLD_OUTPOST_INFOS = 60000
|
||||||
|
|
||||||
|
USER_DEFINED_PROPERTY_NB_BITS = 32
|
||||||
|
INVALID_PROPERTY = 0xFFFF
|
||||||
|
NB_VISUAL_PROPERTIES = 28
|
||||||
|
MAX_PROPERTIES_PER_ENTITY = NB_VISUAL_PROPERTIES
|
||||||
|
THRESHOLD_RIDER_ENTITY_ID = MAX_THRESHOLD
|
||||||
|
|
26
tools/TStampQueue.py
Normal file
26
tools/TStampQueue.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module TStampQueue
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
class TStampQueue:
|
||||||
|
def __init__(self, first=None, second=None):
|
||||||
|
self.first = first
|
||||||
|
self.second = second
|
||||||
|
|
||||||
|
|
26
tools/TStreamFormat.py
Normal file
26
tools/TStreamFormat.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module TStreamFormat
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from enum import IntEnum
|
||||||
|
|
||||||
|
class TStreamFormat(IntEnum):
|
||||||
|
UseDefault = 0
|
||||||
|
Binary = 1
|
||||||
|
String = 2
|
171
tools/World.py
Normal file
171
tools/World.py
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module World
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from tools import Enum
|
||||||
|
from tools import CSessionId
|
||||||
|
from tools import BitStream
|
||||||
|
from tools import CodeMsgXml
|
||||||
|
from tools import CStringManager
|
||||||
|
|
||||||
|
class World():
|
||||||
|
def __init__(self):
|
||||||
|
self.timestamp = 0
|
||||||
|
self.ServerPeopleActive = 255
|
||||||
|
self.ServerCareerActive = 255
|
||||||
|
self.CharacterSummaries = []
|
||||||
|
self.Mainlands = []
|
||||||
|
self.CShardNames = []
|
||||||
|
self.UserPrivileges = ''
|
||||||
|
self.FreeTrial = False
|
||||||
|
self.CurrentState = Enum.TState.st_unknown
|
||||||
|
self.UseFemaleTitles = False
|
||||||
|
self.MessageServerTemplate = {}
|
||||||
|
self.StringManager = CStringManager.CStringManager()
|
||||||
|
|
||||||
|
def CreaterCharacter(self, msgXml, HeadName):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/client/src/connection.cpp # class CAHAskCreateChar : public IActionHandler
|
||||||
|
khanat-opennel-code/code/ryzom/common/src/game_share/msg_client_server.h # void setupFromCharacterSummary (const CCharacterSummary &cs)
|
||||||
|
khanat-opennel-code/code/ryzom/common/src/game_share/msg_client_server.h # void serialBitMemStream(NLMISC::CBitMemStream &f)
|
||||||
|
'''
|
||||||
|
Slot = 0
|
||||||
|
SheetId = 0
|
||||||
|
#Mainland= 302
|
||||||
|
cSessionId = CSessionId.CSessionId(self.CShardNames[0].SessionId)
|
||||||
|
|
||||||
|
# [A-Za-z]{3,15} # quand je pense qu'ils ont code pour avoir du UTF !!!!!
|
||||||
|
name = ''
|
||||||
|
for car in HeadName:
|
||||||
|
if car >= 'a' and car <= 'z':
|
||||||
|
pass
|
||||||
|
elif car >= 'A' and car <= 'Z':
|
||||||
|
pass
|
||||||
|
elif car >= '0' and car <= '9':
|
||||||
|
car = chr(ord(car)+ord('A')-ord('0'))
|
||||||
|
else:
|
||||||
|
car ='Z'
|
||||||
|
name += car
|
||||||
|
#name = 'Tester'
|
||||||
|
People = 1
|
||||||
|
Sex = 0
|
||||||
|
StartPoint = 1
|
||||||
|
NbPointFighter = 2
|
||||||
|
NbPointCaster = 1
|
||||||
|
NbPointCrafter = 1
|
||||||
|
NbPointHarvester = 1
|
||||||
|
GabaritHeight = 9
|
||||||
|
GabaritTorsoWidth = 10
|
||||||
|
GabaritArmsWidth = 7
|
||||||
|
GabaritLegsWidth = 4
|
||||||
|
GabaritBreastSize = 7
|
||||||
|
MorphTarget1 = 3
|
||||||
|
MorphTarget2 = 3
|
||||||
|
MorphTarget3 = 3
|
||||||
|
MorphTarget4 = 5
|
||||||
|
MorphTarget5 = 5
|
||||||
|
MorphTarget6 = 5
|
||||||
|
MorphTarget7 = 4
|
||||||
|
MorphTarget8 = 4
|
||||||
|
EyesColor = 0
|
||||||
|
Tattoo = 0
|
||||||
|
HairType = 5
|
||||||
|
HairColor = 1
|
||||||
|
JacketColor = 0
|
||||||
|
TrousersColor = 0
|
||||||
|
HatColor = 1
|
||||||
|
ArmsColor = 0
|
||||||
|
HandsColor = 0
|
||||||
|
FeetColor = 0
|
||||||
|
msgout = BitStream.BitStream()
|
||||||
|
# GenericMsgHeaderMngr.pushNameToStream("CONNECTION:CREATE_CHAR", out))
|
||||||
|
ref = CodeMsgXml.CodeMsgXml(msgXml, 'CONNECTION:CREATE_CHAR')
|
||||||
|
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)
|
||||||
|
cSessionId.push(msgout)
|
||||||
|
msgout.pushUString(name)
|
||||||
|
msgout.pushUint8(People)
|
||||||
|
msgout.pushUint8(Sex)
|
||||||
|
|
||||||
|
msgout.pushUint8(NbPointFighter)
|
||||||
|
msgout.pushUint8(NbPointCaster)
|
||||||
|
msgout.pushUint8(NbPointCrafter)
|
||||||
|
msgout.pushUint8(NbPointHarvester)
|
||||||
|
|
||||||
|
msgout.pushSint32(StartPoint)
|
||||||
|
|
||||||
|
msgout.pushSint8(HairType)
|
||||||
|
msgout.pushSint8(HairColor)
|
||||||
|
|
||||||
|
# GabaritHeight => 0 - 15
|
||||||
|
msgout.pushSint8(GabaritHeight)
|
||||||
|
msgout.pushSint8(GabaritTorsoWidth)
|
||||||
|
msgout.pushSint8(GabaritArmsWidth)
|
||||||
|
msgout.pushSint8(GabaritLegsWidth)
|
||||||
|
msgout.pushSint8(GabaritBreastSize)
|
||||||
|
|
||||||
|
# MorphTarget1 => 0 - 7
|
||||||
|
msgout.pushSint8(MorphTarget1)
|
||||||
|
msgout.pushSint8(MorphTarget2)
|
||||||
|
msgout.pushSint8(MorphTarget3)
|
||||||
|
msgout.pushSint8(MorphTarget4)
|
||||||
|
msgout.pushSint8(MorphTarget5)
|
||||||
|
msgout.pushSint8(MorphTarget6)
|
||||||
|
msgout.pushSint8(MorphTarget7)
|
||||||
|
msgout.pushSint8(MorphTarget8)
|
||||||
|
# EyesColor => 0 - 7
|
||||||
|
msgout.pushSint8(EyesColor)
|
||||||
|
# Tattoo) => 0 = neutral, 1 - 64 Tattoo
|
||||||
|
msgout.pushSint8(Tattoo)
|
||||||
|
|
||||||
|
#// color for equipement slots (Only for pre-equipped perso created with sheet)
|
||||||
|
msgout.pushSint8(JacketColor)
|
||||||
|
msgout.pushSint8(TrousersColor)
|
||||||
|
msgout.pushSint8(HatColor)
|
||||||
|
msgout.pushSint8(ArmsColor)
|
||||||
|
msgout.pushSint8(HandsColor)
|
||||||
|
msgout.pushSint8(FeetColor)
|
||||||
|
|
||||||
|
#self.Commands.append(msgout)
|
||||||
|
return msgout
|
||||||
|
|
||||||
|
|
||||||
|
def impulsionCreateChar(self, msgXml, uid):
|
||||||
|
'''
|
||||||
|
khanat-opennel-code/code/ryzom/server/src/frontend_service/uid_impulsions.cpp # static void impulsionCreateChar(uint32 uid, NLMISC::CBitMemStream &bms, NLMISC::TGameCycle gameCycle)
|
||||||
|
'''
|
||||||
|
_ = self.CreaterCharacter(msgXml)
|
||||||
|
# bms = self.CreaterCharacter(msgXml)
|
||||||
|
#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.BitStream()
|
||||||
|
ref = CodeMsgXml.CodeMsgXml(msgXml, 'CONNECTION:SELECT_CHAR')
|
||||||
|
for size, value, id in ref:
|
||||||
|
msgout.internalSerial(value, size, typeName=id)
|
||||||
|
msgout.pushUint8(PlayerSelectedSlot)
|
||||||
|
return msgout
|
||||||
|
|
0
tools/__init__.py
Normal file
0
tools/__init__.py
Normal file
27
tools/convertUStringToString.py
Normal file
27
tools/convertUStringToString.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module convertUStringToString
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
def convertUStringToString(name):
|
||||||
|
ret = ''
|
||||||
|
for car in name:
|
||||||
|
if ord(car) >= 32 and ord(car)<=127:
|
||||||
|
ret += car
|
||||||
|
return ret
|
28
tools/getPowerOf2.py
Normal file
28
tools/getPowerOf2.py
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# module getPowerOf2
|
||||||
|
#
|
||||||
|
# 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
def getPowerOf2(v):
|
||||||
|
res=1;
|
||||||
|
ret=0;
|
||||||
|
while res<v:
|
||||||
|
ret += 1
|
||||||
|
res *= 2
|
||||||
|
return ret
|
Loading…
Reference in a new issue