adding spy tools & update clientbot

This commit is contained in:
AleaJactaEst 2019-10-24 19:45:24 +02:00
parent 733000a09c
commit 3121a918bb
36 changed files with 6431 additions and 4818 deletions

4901
client.py

File diff suppressed because it is too large Load diff

416
spykhanat.py Executable file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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]) + ']'

View 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
View 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
View 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
View 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')

View 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
View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View file

View 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
View 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