#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# script to emulate client 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 .
# Ex.: ./client.py --khanat-host 172.17.0.3 -d --size-buffer-file 10241024
# Modifier les droits pour les nouveaux joueurs (accès à tout)
# mysql -u root -e "use nel_ams_lib;UPDATE settings SET Value = 7 WHERE settings.Setting = 'Domain_Auto_Add';"
import argparse
import http.client
import crypt
import logging
import os
import os.path
import sys
import urllib.request
import urllib.parse
import tempfile
from enum import IntEnum
from ctypes import *
import re
import random
import lzma
import socket
import struct
import xml.etree.ElementTree as ET
import hashlib
import time
import signal
import inspect
INVALID_SLOT = 0xff
def convertUStringToString(name):
ret = ''
for car in name:
if ord(car) >= 32 and ord(car)<=127:
ret += car
return ret
class BitStream():
def __init__(self):
self._pos = 0
self._read = 0
self._tampon = []
self._groupRead = []
self._groupWrite = []
def __len__(self):
return (self._pos + 7) // 8
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
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
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('> 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:
logging.getLogger('myLogger').debug(self.showAllData())
logging.getLogger('myLogger').error("Stream Overflow - nbits:%d name:%s decode:%s typeName:%s emulate:%s" %(nbits, name, str(decode), typeName, str(emulate)))
raise "Stream Overflow"
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):
v1 = self._read
v = self.readSerial(32, decode=False)
v1 = self.readSerial(32, decode=False)
v2 = v | (v1 << 32)
self._groupRead.append((v1, v1+64, name, 'Uint64', v2))
return v2
def readSint64(self, name):
v1 = self._read
v = self.readSerial(32, decode=False)
v1 = self.readSerial(32, decode=False)
v2 = v | (v1 << 32)
self._groupRead.append((v1, v1+64, name, 'Sint64', c_int64(v2).value))
return c_int64(v2).value
def readFloat(self, name):
p1 = self._read
v = self.readSerial(32, name=name, decode=False, typeName='Float')
v1 = struct.pack('I', v)
v2 = struct.unpack(' 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 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 __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)
NL_BITLEN = 32
class CBitSet:
def __init__(self):
self.data = self.resize(1024)
self.NumBits = 0
self.MaskLast = 0
def resize(self, numBits):
self.data = [ 0 for _ in range(0, (numBits +NL_BITLEN - 1) // NL_BITLEN) ]
self.NumBits = numBits
nLastBits = self.NumBits & (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 & (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&(NL_BITLEN-1);
mask= 1<> 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 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))
def getTextMD5(dataRawXml):
log = logging.getLogger('myLogger')
dataNew = ''
for data in dataRawXml:
if data != '\r': # '\015' ignore caractère \r\n =>
dataNew += data
else:
log.debug("***** data:%d" % (ord(data)))
m = hashlib.md5()
m.update(dataNew.encode('utf-8'))
#print(m.hexdigest())
#print(m.digest())
return m.digest()
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) + ')'
class CFileList():
def __init__(self, name, fullpath):
self.name = name
self.fullpath = fullpath
self.child = []
def addchild(self, name, pos, size):
child = CFileChild(name, pos, size)
self.child.append(child)
def __str__(self):
return self.name + '[' + ', '.join([str(x) for x in self.child]) + ']'
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(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
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 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 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 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
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 TExtendType:
ET_SHEET_ID = 0
ET_64_BIT_EXTENDED_TYPES = 0x80000000
ET_ENTITY_ID = 0x80000000 # ET_ENTITY_ID = ET_64_BIT_EXTENDED_TYPES
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)
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
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) + ')'
# #####################################################
# 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 == TType.EXTEND_TYPE:
return True
elif self._type == TType.STRUCT_BEGIN:
self.log.error("Can't extract a value from a structure delimiter")
sys.exit(2)
elif self._type == 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 == TType.FLAG:
return True
else:
return False
def asUint(self):
if self._type == TType.STRUCT_BEGIN or self._type == TType.STRUCT_END:
self.log.error("Can't extract a value from a structure delimiter")
sys.exit(2)
elif self._type == TType.SINT32:
return self.read_i32()
elif self._type == TType.UINT32:
return self.read_i32()
elif self._type == TType.SINT64:
return self.read_i64()
elif self._type == TType.UINT64:
return self.read_i64()
elif self._type == TType.FLOAT32:
return self.read_i32()
elif self._type == TType.FLOAT64:
return self.read_i64()
elif self._type == TType.STRING:
return int(self._string)
elif self._type == TType.FLAG:
return "1"
elif self._type == 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 == TType.STRUCT_BEGIN or self._type == TType.STRUCT_END:
return ''
elif self._type64:
# To be confirm for extend
return str(self.read_ExData64())
elif self._type == TType.SINT32:
return str(self.read_i32())
elif self._type == TType.UINT32:
return str(self.read_i32())
elif self._type == TType.SINT64:
return str(self.read_i64())
elif self._type == TType.UINT64:
return str(self.read_i64())
elif self._type == TType.FLOAT32:
return str(self.read_i32())
elif self._type == TType.FLOAT64:
return str(self.read_i64())
elif self._type == TType.STRING:
return self._string
elif self._type == 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 == TType.STRUCT_BEGIN or self._type == TType.STRUCT_END:
self.log.error("Can't extract a value from a structure delimiter")
sys.exit(2)
elif self._type == TType.SINT32:
return str(self.read_ii32())
elif self._type == TType.UINT32:
return str(self.read_i32())
elif self._type == TType.SINT64:
return str(self.read_ii64())
elif self._type == TType.UINT64:
return str(self.read_i64())
elif self._type == TType.FLOAT32:
return str(self.read_f32())
elif self._type == TType.FLOAT64:
return str(self.read_f64())
elif self._type == TType.STRING:
return self._string
elif self._type == TType.FLAG:
return "1"
elif self._type == 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)
# #####################################################
#
# #####################################################
class CGenericMultiPartTemp():
def __init__(self, log):
self.log = log
self.NbBlock = 0xFFFFFFFF
self.NbCurrentBlock = 0
self.TempSize = 0
self.Temp = []
self.BlockReceived = []
def set(self, Number, Part, NbBlock, PartCont, decodeImpulse):
'''
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::CGenericMultiPartTemp::set (CActionGenericMultiPart *agmp, CNetworkConnection *parent)
'''
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]:
self.log.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)
self.log.debug("NbCurrentBlock:%d / NbBlock:%d" % (self.NbCurrentBlock, self.NbBlock))
if self.NbCurrentBlock == self.NbBlock:
# reform the total action
bms = BitStream()
self.NbBlock == 0xFFFFFFFF
for data in self.Temp:
bms.pushBitStream(data)
self.log.debug("CGenericMultiPartTemp : data : %s" % bms.showAllData())
self.log.debug("TODO")
decodeImpulse.execute(bms)
else:
self.log.debug("CGenericMultiPartTemp : Wait other block")
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 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 = TPeople.Unknown
self.Location = 0
self.sPropVisualA = SPropVisualA()
self.sPropVisualB = SPropVisualB()
self.sPropVisualC = SPropVisualC()
self.sheetId = 0
self.Title = 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(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')
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)
class CMainlandSummary():
def __init__(self):
self.Id = CSessionId()
self.Name = ""
self.Description = ""
self.LanguageCode = ""
self.Online = False
def read(self, msgin):
'''
khanat-opennel-code/code/ryzom/common/src/game_share/mainland_summary.h # void serial(NLMISC::IStream &f)
'''
self.Id.read(msgin)
self.Name = msgin.readUString('Name')
self.Description = msgin.readUString('Description')
self.LanguageCode = msgin.readString('LanguageCode')
self.Online = msgin.readBool('Online')
class CShardName():
def __init__(self, SessionId, DisplayName, ShortName):
self.SessionId = SessionId
self.DisplayName = DisplayName
self.ShortName = ShortName
def CodeMsgXml(msgXml, key):
head = msgXml
listpath = key.split(':')
ret = []
for id in listpath:
nbBit = 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:
log = logging.getLogger('myLogger')
log.error("Impossible to found value (all key:%s, value:%s)" % (key, id))
raise ValueError
head = ele
return ret
class GenericMultiPartTemp():
def __init__(self, log):
self.log = log
self.data = {}
def addGenericMultiPartTemp(self, id):
self.data.setdefault(id, CGenericMultiPartTemp(self.log))
def setGenericMultiPartTemp(self, Number, Part, NbBlock, PartCont, decodeImpulse):
self.data[Number].set(Number, Part, NbBlock, PartCont, decodeImpulse)
class TStreamFormat(IntEnum):
UseDefault = 0
Binary = 1
String = 2
class TMessageType(IntEnum):
OneWay = 0
Request = 1
Response = 2
Except = 3
#class CMessage():
# def __init__(self, name, inputStream=False, streamformat=TStreamFormat.UseDefault, defaultCapacity=1000 ):
# self._Name = name
# self._Type = TMessageType.OneWay
# self._SubMessagePosR = 0
# self._LengthR = 0
# self._HeaderSize = 0xFFFFFFFF
# self._TypeSet = False
# if streamformat == TStreamFormat.UseDefault:
# self._DefaultStringMode = False
# else:
# self._DefaultStringMode = (streamformat == TStreamFormat.String)
# self.msgout = BitStream()
#
# def serial(self, uid, bms):
# self.msgout.pushUint64(uid)
class World():
def __init__(self, log, HeadName):
self.log = log
#self.GenericMultiPartTemp = {}
self.timestamp = 0
self.ServerPeopleActive = 255
self.ServerCareerActive = 255
self.CharacterSummaries = []
self.Mainlands = []
self.CShardNames = []
self.UserPrivileges = ''
self.FreeTrial = False
self.HeadName = HeadName
self.CurrentState = TState.st_unknown
self.UseFemaleTitles = False
def CreaterCharacter(self, msgXml):
'''
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(self.CShardNames[0].SessionId)
# [A-Za-z]{3,15} # quand je pense qu'ils ont code pour avoir du UTF !!!!!
name = ''
for car in self.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()
# GenericMsgHeaderMngr.pushNameToStream("CONNECTION:CREATE_CHAR", out))
ref = 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)
'''
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()
ref = CodeMsgXml(msgXml, 'CONNECTION:SELECT_CHAR')
for size, value, id in ref:
msgout.internalSerial(value, size, typeName=id)
msgout.pushUint8(PlayerSelectedSlot)
return msgout
class CPersistentDataRecord:
def __init__(self, log):
self.log = log
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:
self.log.debug("File:%s" % str(x))
for x in self.Categories:
self.log.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)
self.log.debug("token:%d, extend:%d" % (token, extend))
if token == Card.BEGIN_TOKEN:
return TType.STRUCT_BEGIN
elif token == Card.END_TOKEN:
return TType.STRUCT_END
elif token == Card.FLAG_TOKEN:
return TType.FLAG
elif token == Card.SINT_TOKEN:
if extend:
return TType.SINT64
else:
return TType.SINT32
elif token == Card.UINT_TOKEN:
if extend:
return TType.UINT64
else:
return TType.UINT32
elif token == Card.FLOAT_TOKEN:
if extend:
return TType.FLOAT64
else:
return TType.FLOAT32
elif token == Card.STRING_TOKEN:
if extend:
return TType.EXTEND_TYPE
else:
return TType.STRING
self.log.error('This should never happen!')
sys.exit(2)
def type2Token(self, type): # persistent_data_inline.h:1118 CPersistentDataRecord::TToken CPersistentDataRecord::CArg::type2Token(uint32 type)
self.log.debug("type: %d" %(type))
if type == TType.STRUCT_BEGIN:
return Card.BEGIN_TOKEN
elif type == TType.STRUCT_END:
return Card.END_TOKEN
elif type == TType.FLAG:
return Card.FLAG_TOKEN
elif type == TType.SINT32:
return Card.SINT_TOKEN
elif type == TType.UINT32:
return Card.UINT_TOKEN
elif type == TType.FLOAT32:
return Card.FLOAT_TOKEN
elif type == TType.STRING:
return Card.STRING_TOKEN
elif type == TType.SINT64:
return Card.SINT_TOKEN
elif type == TType.UINT64:
return Card.UINT_TOKEN
elif type == TType.FLOAT64:
return Card.FLOAT_TOKEN
elif type == TType.EXTEND_TYPE:
return Card.STRING_TOKEN
self.log.error('This should never happen!')
sys.exit(2)
def peekNextToken(self):
token = self.TokenTable[self.offsetToken]
self.log.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
self.log.debug("peekNextTokenType - old offset token:%d" % self.offsetToken)
if self.isEndOfData():
self.log.error('Attempt to read past end of input data')
sys.exit(2)
token = self.TokenTable[self.offsetToken]
tokenType = token & 7
if tokenType == Card.EXTEND_TOKEN:
if self.offsetToken + 1 > self.tokenCount:
self.log.error('Attempt to read past end of input data')
sys.exit(2)
tokenType = self.TokenTable[self.offsetToken+1]
self.log.debug("peekNextTokenType [%d] token:%d type:%d" %(self.offsetToken, token, tokenType))
return self.token2Type(tokenType, True)
self.log.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():
self.log.debug("isEndOfData")
return True
elif len(self.ReadingStructStack) == 0:
self.log.debug("ReadingStructStack")
return False
elif self.peekNextTokenType() != TType.STRUCT_END:
self.log.debug("peekNextTokenType != TType.STRUCT_END")
return False
elif self.ReadingStructStack[-1] != self.peekNextToken():
self.log.error("Opening and closing structure tokens don't match")
sys.exit(2)
self.log.debug("isEndOfStruct")
return True
def isStartOfStruct(self):
if self.peekNextTokenType() == TType.STRUCT_BEGIN:
return True
return False
def popStructBegin(self, token):
if self.peekNextToken() != token:
self.log.error('Attempting to enter a structure with the wrong delimiting token')
sys.exit(2)
if self.peekNextTokenType() != TType.STRUCT_BEGIN:
self.log.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:
self.log.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:
self.log.error('Attempting to pop end of a structure with the wrong delimiting token')
sys.exit(2)
if nextToken != token:
self.log.error('Attempting to pop end of a structure with the wrong delimiting token')
sys.exit(2)
if self.peekNextTokenType() != TType.STRUCT_END:
self.log.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:
self.log.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()
result.write_Type(_type)
result.write_Type64(False)
self.log.debug("peekNextArg - Type:%d ArgOffset:%d" % (_type, self.ArgOffset))
if result.isExtended():
self.log.debug("Extended")
result.write_i32_1(self.ArgTable[self.ArgOffset])
result.write_i32_2(self.ArgTable[self.ArgOffset+1])
if result.read_Type() == TType.EXTEND_TYPE and result.read_ExType() == 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])
self.log.debug("peekNextArg - id :%d" % result.read_i32_1())
if result.read_Type() == TType.STRING:
result.write_String(self.lookupString(result.read_i32_1()))
self.log.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() == TType.EXTEND_TYPE and result.read_ExType() == TExtendType.ET_64_BIT_EXTENDED_TYPES:
self.ArgOffset += 1
self.offsetToken += 1
else:
self.ArgOffset += 1
self.offsetToken += 1
self.log.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)
self.log.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
self.log.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:
self.log.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:
self.log.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):
self.log.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:
self.log.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)
self.log.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
self.log.debug(self.StringTable)
if chaine != '':
self.log.error("PDR ERROR: Too few strings found in string table (file:%s)" % (filename))
sys.exit(2)
self.log.debug("Red %s" % filename)
def decrypt_token(self):
i = 0
lvl = 0
posArg = 0
extend = False
extend64 = False
result = 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(TType.STRUCT_BEGIN)
if lvl <= 1:
print("| |||||||")
lvl += 1
elif tokenTypeValue == 1:
tokenCard = 'END_TOKEN'
tokenType = 'STRUCT_END'
result.write_Type(TType.STRUCT_END)
extend = False
extend64 = False
elif tokenTypeValue == 2:
tokenCard = 'SINT_TOKEN'
if extend:
tokenType = 'SINT64'
result.write_Type(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(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(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(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(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(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(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(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(TType.FLAG)
extend = False
extend64 = False
elif tokenTypeValue == 7:
if extend:
extend64 = True
tokenCard = 'EXTEND_TOKEN'
result.write_Type(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")
self.log.debug("MapKey:%d, MapVal:%d, Files:%d, Categories:%d" %(__Tok__MapKey, __Tok__MapVal, __Tok_Files, __Tok_Categories))
while not self.isEndOfStruct():
nextToken = self.peekNextToken()
self.log.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
self.log.error("TODO")
sys.exit(2)
def CBNPFileSet_apply(self):
__Tok__MapKey = self.addString("__Key__")
__Tok__MapVal = self.addString("__Val__")
__Tok_Files = self.addString("_Files")
self.log.debug("MapKey:%d, MapVal:%d, Files:%d" %(__Tok__MapKey, __Tok__MapVal, __Tok_Files))
while not self.isEndOfStruct():
nextToken = self.peekNextToken()
self.log.debug("nextToken:%d" % (nextToken))
if nextToken == __Tok_Files:
self.popStructBegin(__Tok_Files)
self.CBNPFile.append(CBNPFile())
self.CBNPFile_apply(self.CBNPFile[-1])
self.popStructEnd(__Tok_Files)
continue
self.log.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
self.log.debug("MapKey:%d, MapVal:%d, Filename:%d, Versions:%d" %(__Tok__MapKey, __Tok__MapVal, __Tok_FileName, __Tok_Versions))
while not self.isEndOfStruct():
nextToken = self.peekNextToken()
self.log.debug("nextToken:%d" % (nextToken))
if nextToken == __Tok_FileName:
_FileName = self.popString(nextToken)
_CBNPFile.FileName = _FileName
self.log.debug("filename: %s" % _FileName)
continue
if nextToken == __Tok_Versions:
self.popStructBegin(__Tok_Versions)
# vectAppend(_Versions).apply(pdr);
_CBNPFile.Versions.append(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
self.log.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")
self.log.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()
self.log.debug("nextToken:%d" % (nextToken))
if nextToken == __Tok_VersionNumber:
self.log.debug("__Tok_VersionNumber")
_CBNPFileVersion.VersionNumber = self.popUint32(__Tok_VersionNumber)
self.log.debug("VersionNumber: %s" % _CBNPFileVersion.VersionNumber)
continue
elif nextToken == __Tok_FileSize:
self.log.debug("__Tok_FileSize")
_CBNPFileVersion.FileSize = self.popUint32(__Tok_FileSize)
self.log.debug("FileSize: %s" % _CBNPFileVersion.FileSize)
continue
elif nextToken == __Tok_7ZFileSize:
self.log.debug("__Tok_7ZFileSize")
_CBNPFileVersion.v7ZFileSize = self.popUint32(__Tok_7ZFileSize)
self.log.debug("7ZFileSize: %s" % _CBNPFileVersion.v7ZFileSize)
continue
elif nextToken == __Tok_FileTime:
self.log.debug("__Tok_FileTime")
_CBNPFileVersion.FileTime = self.popUint32(__Tok_FileTime)
self.log.debug("FileTime: %s" % _CBNPFileVersion.FileTime)
continue
elif nextToken == __Tok_PatchSize:
self.log.debug("__Tok_PatchSize")
_CBNPFileVersion.PatchSize = self.popUint32(__Tok_PatchSize)
self.log.debug("PatchSize: %s" % _CBNPFileVersion.PatchSize)
continue
elif nextToken == __Tok_HashKey:
self.log.debug("__Tok_HashKey")
_CBNPFileVersion.HashKey.append(self.popUint32(__Tok_HashKey))
self.log.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()
self.log.debug("nextToken:%d" % (nextToken))
if nextToken == __Tok_Category:
self.log.debug("__Tok_Category")
self.popStructBegin(__Tok_Category)
self.Categories.append(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")
self.log.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()
self.log.debug("nextToken:%d" % (nextToken))
if nextToken == __Tok_Name:
self.log.debug("__Tok_Name")
_CBNPCategory._Name = self.popString(nextToken)
self.log.debug("_Name: %s" % _CBNPCategory._Name)
continue
elif nextToken == __Tok_IsOptional:
self.log.debug("__Tok_IsOptional")
_CBNPCategory._IsOptional = self.popBool(nextToken)
self.log.debug("_IsOptional: %s" % str(_CBNPCategory._IsOptional))
continue
elif nextToken == __Tok_UnpackTo:
self.log.debug("__Tok_UnpackTo")
_CBNPCategory._UnpackTo = self.popString(nextToken)
self.log.debug("_UnpackTo: %s" % str(_CBNPCategory._UnpackTo))
continue
elif nextToken == __Tok_IsIncremental:
self.log.debug("__Tok_IsIncremental")
_CBNPCategory._IsIncremental = self.popBool(nextToken)
self.log.debug("_IsIncremental: %s" % str(_CBNPCategory._IsIncremental))
continue
elif nextToken == __Tok_CatRequired:
self.log.debug("__Tok_CatRequired")
_CBNPCategory._CatRequired = self.popString(nextToken)
self.log.debug("_CatRequired: %s" % str(_CBNPCategory._CatRequired))
continue
elif nextToken == __Tok_Hidden:
self.log.debug("__Tok_Hidden")
_CBNPCategory._Hidden = self.popBool(nextToken)
self.log.debug("_Hidden: %s" % str(_CBNPCategory._Hidden))
continue
elif nextToken == __Tok_Files:
self.log.debug("__Tok_Files")
_CBNPCategory._Files.append(self.popString(nextToken))
self.log.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
def getPowerOf2(v):
res=1;
ret=0;
while res %d' % (key, id))
ret.append(id)
head = ele
break
id += 1
return ret
def execute(self, msgin):
self.log.debug("execute")
head = self.msgXml
listpath = []
while True:
nbBit = 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 + '>')
self.log.debug(fullname)
if fullname in self.GenericMsgHeaderMngr:
self.log.debug("Found : %s" % fullname)
self.GenericMsgHeaderMngr[fullname](msgin)
self.log.debug("MessageXML decoded: %s" % msgin.showAllData() )
return True
else:
#self.log.debug("Non trouve")
for ele in head:
if ele.attrib['name'] == name:
head = ele
break
if head != ele:
self.log.error("Impossible to found %s" % fullname )
self.log.debug("MessageXML decoded: %s" % msgin.showAllData() )
return False
self.log.debug("MessageXML decoded: %s" % msgin.showAllData() )
return False
def loadMsg(self, msgXml):
self.msgXml = msgXml
def loadDatabase(self, databaseXml):
self.databaseXml = databaseXml
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):
raise RuntimeError
def setPriority(self, prio):
raise RuntimeError
def priority(self):
raise RuntimeError
def getValue(self):
raise RuntimeError
def setValue(self, value):
raise RuntimeError
def isContinuous(self):
raise RuntimeError
def reset(self):
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)
def __str__(self):
return "CActionPosition" + super().__str__()
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
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):
decodeImpulse.execute(self._Message)
def __str__(self):
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('myLogger').debug("number:%d part:%d bytelen:%d size:%d nbBlock:%d" %(number, part, bytelen, size, nbBlock))
start = part*size
end = start + size
logging.getLogger('myLogger').debug("start:%d end:%d bytelen:%d" % (start, end, bytelen))
if end > bytelen:
end = bytelen
logging.getLogger('myLogger').debug("start:%d end:%d" % (start, end))
self.PartCont = []
# memcpy( &PartCont[0], buffer + start, end - start );
for i in range(start, end):
logging.getLogger('myLogger').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')
self.log = logging.getLogger('myLogger')
self.log.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):
'''
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::genericAction (CActionGenericMultiPart *agmp)
'''
self.log = logging.getLogger('myLogger')
self.log.debug("Number:%d Part:%d NbBlock:%d" % (self.Number, self.Part, self.NbBlock))
decodeImpulse.GenericMultiPartTemp.addGenericMultiPartTemp(self.Number)
decodeImpulse.GenericMultiPartTemp.setGenericMultiPartTemp(self.Number, self.Part, self.NbBlock, self.PartCont, decodeImpulse)
def __str__(self):
return "CActionGenericMultiPart" + super().__str__() + "[" + str(self.Number) + ',' + str(self.Part) + ',' + str(self.NbBlock) + ',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):
def __init__(self, slot, code, world):
super().__init__(slot, code, world)
def __str__(self):
return "CActionSint64" + super().__str__()
class CActionFactory:
def __init__(self, log, world):
self.log = log
self.world = world
self.RegisteredAction = {}
self.RegisteredAction.setdefault(TActionCode.ACTION_POSITION_CODE, [])
self.RegisteredAction.setdefault(TActionCode.ACTION_GENERIC_CODE, [])
self.RegisteredAction.setdefault(TActionCode.ACTION_GENERIC_MULTI_PART_CODE, [])
self.RegisteredAction.setdefault(TActionCode.ACTION_SINT64, [])
self.RegisteredAction.setdefault(TActionCode.ACTION_SYNC_CODE, [])
self.RegisteredAction.setdefault(TActionCode.ACTION_DISCONNECTION_CODE, [])
self.RegisteredAction.setdefault(TActionCode.ACTION_ASSOCIATION_CODE, [])
self.RegisteredAction.setdefault(TActionCode.ACTION_LOGIN_CODE, [])
self.RegisteredAction.setdefault(TActionCode.ACTION_TARGET_SLOT_CODE, [])
self.RegisteredAction.setdefault(TActionCode.ACTION_DUMMY_CODE, [])
def createFactory(self, slot, code):
if code == TActionCode.ACTION_POSITION_CODE:
self.log.debug("Create CActionPosition")
return CActionPosition(slot, code, self.world)
elif code == TActionCode.ACTION_GENERIC_CODE:
self.log.debug("Create CActionGeneric")
return CActionGeneric(slot, code, self.world)
elif code == TActionCode.ACTION_GENERIC_MULTI_PART_CODE:
self.log.debug("Create CActionGenericMultiPart")
return CActionGenericMultiPart(slot, code, self.world)
elif code == TActionCode.ACTION_SINT64:
self.log.debug("Create CActionSint64")
return CActionSint64(slot, code, self.world)
elif code == TActionCode.ACTION_SYNC_CODE:
self.log.debug("Create CActionSync")
return CActionSync(slot, code, self.world)
elif code == TActionCode.ACTION_DISCONNECTION_CODE:
self.log.debug("Create CActionDisconnection")
return CActionDisconnection(slot, code, self.world)
elif code == TActionCode.ACTION_ASSOCIATION_CODE:
self.log.debug("Create CActionAssociation")
return CActionAssociation(slot, code, self.world)
elif code == TActionCode.ACTION_LOGIN_CODE:
self.log.debug("Create CActionLogin")
return CActionLogin(slot, code, self.world)
elif code == TActionCode.ACTION_TARGET_SLOT_CODE:
self.log.debug("Create CActionTargetSlot")
return CActionTargetSlot(slot, code, self.world)
elif code == TActionCode.ACTION_DUMMY_CODE:
self.log.debug("Create CActionDummy")
return CActionDummy(slot, code, self.world)
else:
log = logging.getLogger('myLogger')
log.warning('create() try to create an unknown action (%u)' % code)
raise RuntimeError
def create(self, slot, code):
if code not in self.RegisteredAction:
log = logging.getLogger('myLogger')
log.warning('try to create an unknown action (%u)' % code)
raise None
elif not self.RegisteredAction[code]:
self.log.debug("new CAction")
action = self.createFactory(slot, code)
action.reset()
return action
else:
self.log.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(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
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]) + "]"
class CImpulseDecoder:
'''
see : khanat-opennel-code/code/ryzom/client/src/impulse_decoder.cpp
'''
def __init__(self, log, world):
self.log = log
self.world = world
self.reset()
self._CActionFactory = CActionFactory(log, world)
def removeCAction(self, action):
self._CActionFactory.RegisteredAction[action.Code].append(action)
def decode(self, msgin, receivedPacket, receivedAck, nextSentPacket):
self.log.debug("receivedPacket:%d receivedAck:%d nextSentPacket:%d" %(receivedPacket, receivedAck, nextSentPacket))
actions = []
for level in range(0, 3):
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
self.log.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]
self.log.debug("keep:%s [%d => %d]" % (str(keep), receivedAck, lAck[channel]))
if keep:
lAck[channel] = nextSentPacket
self.log.debug("lAck:%s" % ':'.join([str(x) for x in lAck]))
num += 1
action = self._CActionFactory.unpack(msgin)
if keep:
self.log.debug("keep")
actions.append(action)
elif action:
self.log.debug("append")
self.removeCAction(action)
return actions
def reset(self):
self._LastAck0 = [-1]
self._LastAck1 = [-1, -1]
self._LastAck2 = [-1, -1, -1, -1]
class TStampQueue:
def __init__(self, first=None, second=None):
self.first = first
self.second = second
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.log = logging.getLogger('myLogger')
self._CurrentSendNumber = 0
self.GenericMsgHeaderMngr = {}
self.GenericMultiPartTemp = GenericMultiPartTemp(self.log)
self.LanguageCode = LanguageCode
self._QuitId = 0
self._ConnectionState = 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()
self._LatestSyncTime = 0
self.world = World(self.log, headAccount)
self._ImpulseDecoder = CImpulseDecoder(self.log, 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(self.log, self.world, self.GenericMsgHeaderMngr, self.GenericMultiPartTemp)
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):
self.log.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:
self.log.error("Impossible to connect on khanat")
return False
self._ConnectionState = 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(self._CurrentSendNumber, self._UpdateTime) )
self._CurrentSendNumber += 1
def sendSystemLogin(self): # code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::sendSystemLogin()
self.log.debug("sendSystemLogin")
if self._sock is None:
raise ValueError
msgout = BitStream()
self.buildSystemHeader(msgout)
msgout.pushUint8(CLFECOMMON.SYSTEM_LOGIN_CODE)
msgout.pushUint32(self.UserAddr)
msgout.pushUint32(self.UserKey)
msgout.pushUint32(self.UserId)
msgout.pushString(self.LanguageCode)
self.log.debug("sendSystemLogin:%s" % msgout.showAllDataWrite())
self._sock.sendto(msgout.toBytes(), self.frontend)
self._CurrentSendNumber += 1
self._ConnectionState = TConnectionState.Login
def sendSystemQuit(self): # code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::sendSystemQuit()
self.log.debug("sendSystemQuit")
# Disconnect
if self._sock is None:
raise ValueError
self._QuitId += 1
msgout = BitStream()
self.buildSystemHeader(msgout)
msgout.pushUint8(CLFECOMMON.SYSTEM_QUIT_CODE)
msgout.pushSint32(self._QuitId)
self.log.debug("sendSystemQuit:%s" % msgout.showAllDataWrite())
self._sock.sendto(msgout.toBytes(), self.frontend)
self._ConnectionState = TConnectionState.Quit
def sendSystemAckSync(self):
'''
code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::sendSystemAckSync()
'''
self.log.debug("sendSystemAckSync _LastReceivedNumber:%d _LastAckInLongAck:%d _LatestSync:%d" % (self._LastReceivedNumber, self._LastAckInLongAck, self._LatestSync))
msgout = BitStream()
self.buildSystemHeader(msgout)
msgout.pushUint8(CLFECOMMON.SYSTEM_ACK_SYNC_CODE)
msgout.pushSint32(self._LastReceivedNumber)
msgout.pushSint32(self._LastAckInLongAck)
self._LongAckBitField.writeSerial(msgout)
msgout.pushSint32(self._LatestSync)
self.log.debug("sendSystemAckSync:%s" % msgout.showAllDataWrite())
self._sock.sendto(msgout.toBytes(), self.frontend)
self._LatestSyncTime = self._UpdateTime
def sendSystemAckProbe(self):
self.log.debug("sendSystemAckProbe")
msgout = BitStream()
self.buildSystemHeader(msgout)
msgout.pushUint8(CLFECOMMON.SYSTEM_ACK_PROBE_CODE)
msgout.pushSint32(len(self._LatestProbes))
for data in self._LatestProbes:
msgout.pushSint32(data)
self._LatestProbes = []
self.log.debug("sendSystemAckProbe:%s" % msgout.showAllDataWrite())
self._sock.sendto(msgout.toBytes(), self.frontend)
def sendSystemDisconnection(self):
self.log.debug("sendSystemDisconnection")
if self._sock is None:
raise ValueError
msgout = BitStream()
self.buildSystemHeader(msgout)
msgout.pushUint8(CLFECOMMON.SYSTEM_DISCONNECTION_CODE)
self._sock.sendto(msgout.toBytes(), self.frontend)
def sendNormalMessage(self):
'''
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::sendNormalMessage()
'''
self.log.debug("sendNormalMessage")
if self._sock is None:
raise ValueError
msgout = 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
self.log.debug("Send:%s" % msgout.showAllDataWrite())
self._sock.sendto(msgout.toBytes(), self.frontend)
self._LastSendTime = int(time.clock_gettime(1)*1000)
self._PacketStamps.append( TStampQueue(self._CurrentSendNumber, self._UpdateTime) )
self._CurrentSendNumber += 1
def readDelta(self, msg):
propertyCount = msg.readUint16('propertyCount')
self.log.debug("propertyCount:%d" % propertyCount)
self.log.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');
self.log.debug("Normal Mode _LastReceivedAck:%d" % self._LastReceivedAck)
else:
self.log.debug("System Mode")
if self._CurrentReceivedNumber > self._LastReceivedNumber+1:
self.log.debug("lost messages server->client [%d; %d]" %(self._LastReceivedPacketInBothModes + 1, self._CurrentReceivedNumber - 1))
elif self._CurrentReceivedNumber == self._LastReceivedNumber:
self.log.debug("awaiting packet %d, received packet %d" %(self._LastReceivedPacketInBothModes + 1, self._CurrentReceivedNumber))
return False
elif self._CurrentReceivedNumber < self._LastReceivedNumber:
self.log.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 == TConnectionState.Connected or self._ConnectionState == 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
self.log.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
self.log.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):
self.log.debug("receiveSystemProbe")
self._LatestProbeTime = self._UpdateTime
self._LatestProbe = msg.readSint32('LatestProbe')
self.log.debug("LatestProbe: %d" % self._LatestProbe)
self._LatestProbes.append(self._LatestProbe)
def receiveSystemStalled(self, msg):
self.log.debug("received STALLED")
def receiveSystemSync(self, msg):
self.log.debug("receiveSystemSync")
self._LatestSyncTime = self._UpdateTime
self._Synchronize = msg.readUint32('Synchronize')
stime = msg.readSint64('stime')
self._LatestSync = msg.readUint32('LatestSync')
self.log.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')
self.log.debug("MsgData:" + str(MsgData))
self.log.debug("DatabaseData:" + str(DatabaseData))
md5Msg = bytes(MsgData)
md5Database = bytes(DatabaseData)
if md5Msg == self._MsgXmlMD5:
self.log.info("Check MD5 msg.xml : OK")
else:
self.log.error("Check MD5 msg.xml : KO")
if md5Database == self._DatabaseXmlMD5:
self.log.info("Check MD5 database.xml : OK")
else:
self.log.error("Check MD5 database.xml : KO")
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')
self.log.debug("TODO")
return
def receiveNormalMessage(self, msgin):
self.log.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:
self.log.debug('actions: ' +','.join( [ str(x) for x in actions] ) )
else:
self.log.debug('actions: None')
self.log.debug("Message not read (%d) %s" % (msgin.needRead(), msgin.showLastData() ))
# remove all old actions that are acked
while self._Actions and self._Actions[0].FirstPacket != 0 and self._Actions[0].FirstPacket < self._LastReceivedAck:
self.log.debug("remove old action [%d/%d] : %s" % (self._Actions[0].FirstPacket, self._LastReceivedAck, self._Actions[0]))
self._Actions.pop(0)
self._CurrentServerTick = self._CurrentReceivedNumber * 2 + self._Synchronize
# 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:
self.log.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)
# Decode the actions received in the impulsions
for action in actions:
if action.Code == TActionCode.ACTION_DISCONNECTION_CODE:
self.log.debug("Action : ACTION_DISCONNECTION_CODE")
self.disconnect()
elif action.Code == TActionCode.ACTION_GENERIC_CODE:
self.log.debug("Action : ACTION_GENERIC_CODE")
action.genericAction(self.decodeImpulse)
elif action.Code == TActionCode.ACTION_GENERIC_MULTI_PART_CODE:
self.log.debug("Action : ACTION_GENERIC_MULTI_PART_CODE")
action.genericAction(self.decodeImpulse)
elif action.Code == TActionCode.ACTION_DUMMY_CODE:
self.log.debug("Action : ACTION_DUMMY_CODE")
self._ImpulseDecoder.removeCAction(action)
# Decode the visual properties
self.decodeVisualProperties( msgin );
self._LastReceivedNormalTime = int(time.clock_gettime(1)*1000)
def receiveSystemAckQuit(self, msgin):
self.log.debug("received ACK_QUIT")
self._ReceivedAckQuit = True
def disconnect(self):
self.log.info("Disconnect")
self.sendSystemDisconnection()
self._sock.close()
selc._sock = None
self._ConnectionState = TConnectionState.Disconnect
def stateLogin(self, msgin):
self.decodeHeader(msgin)
if self._SystemMode:
message = msgin.readUint8('message')
self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead()))
if message == CLFECOMMON.SYSTEM_SYNC_CODE:
self._ConnectionState = TConnectionState.Synchronize
self.log.debug("Login->synchronize")
self.receiveSystemSync(msgin)
return True
elif message == CLFECOMMON.SYSTEM_STALLED_CODE:
self.log.debug("received STALLED")
self._ConnectionState = TConnectionState.Stalled
self.receiveSystemStalled(msgin)
return True
elif message == CLFECOMMON.SYSTEM_PROBE_CODE:
self.log.debug("Login->probe")
self._ConnectionState = TConnectionState.Probe
self.receiveSystemProbe(msgin)
return True
elif message == CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
self.disconnect()
self.log.warning("BACK-END DOWN")
return False
else:
self.log.warning("CNET: received system %d in state Login" % message)
self.log.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.log.warning("CNET: received normal in state Login")
return False
def stateSynchronize(self, msgin):
self.log.debug("stateSynchronize")
self.decodeHeader(msgin)
if self._SystemMode:
message = msgin.readUint8('message')
self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead()))
if message == CLFECOMMON.SYSTEM_PROBE_CODE:
self.log.debug("synchronize->probe")
self._ConnectionState = TConnectionState.Probe
self.receiveSystemProbe(msgin)
return True
elif message == CLFECOMMON.SYSTEM_STALLED_CODE:
self.log.debug("received STALLED")
self._ConnectionState = TConnectionState.Stalled
self.receiveSystemStalled(msgin)
return True
elif message == CLFECOMMON.SYSTEM_SYNC_CODE:
self.log.debug("synchronize->synchronize")
self.receiveSystemSync(msgin)
elif message == CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
self.disconnect()
self.log.warning("BACK-END DOWN")
return False
else:
self.log.warning("CNET: received system %d in state Synchronize" % message)
self.log.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 = TConnectionState.Connected
self.log.warning("CNET: synchronize->connected")
# _Changes.push_back(CChange(0, ConnectionReady));
self._ImpulseDecoder.reset();
self.receiveNormalMessage(msgin);
return True
self.log.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')
self.log.debug("SystemMode _CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead()))
if message == CLFECOMMON.SYSTEM_PROBE_CODE:
self.log.debug("Connected->probe")
self._ConnectionState = TConnectionState.Probe
self.receiveSystemProbe(msgin)
return True
elif message == CLFECOMMON.SYSTEM_SYNC_CODE:
self.log.debug("Connected->synchronize")
self.receiveSystemSync(msgin)
return True
elif message == CLFECOMMON.SYSTEM_STALLED_CODE:
self.log.debug("received STALLED")
self._ConnectionState = TConnectionState.Stalled
self.receiveSystemStalled(msgin)
return True
elif message == CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
self.disconnect()
self.log.warning("BACK-END DOWN")
return False
else:
self.log.warning("CNET: received system %d in state Connected" % message)
self.log.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')
self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead()))
if message == CLFECOMMON.SYSTEM_SYNC_CODE:
self.log.debug("probe->synchronize")
self._ConnectionState = TConnectionState.Synchronize
self.receiveSystemSync(msgin)
return True
elif message == CLFECOMMON.SYSTEM_STALLED_CODE:
self.log.debug("probe->stalled")
self._ConnectionState = TConnectionState.Stalled
self.receiveSystemStalled(msgin)
return True
elif message == CLFECOMMON.SYSTEM_PROBE_CODE:
self.receiveSystemProbe(msgin)
elif message == CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
self.disconnect()
self.log.warning("BACK-END DOWN")
return False
else:
self.log.warning("CNET: received system %d in state Probe" % message)
self.log.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.log.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')
self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead()))
if message == CLFECOMMON.SYSTEM_SYNC_CODE:
self.log.debug("stalled->synchronize")
self._ConnectionState = TConnectionState.Synchronize
self.receiveSystemSync(msgin)
return True
elif message == CLFECOMMON.SYSTEM_PROBE_CODE:
self.log.debug("stalled->probe")
self._ConnectionState = TConnectionState.Probe
self.receiveSystemProbe(msgin)
elif message == CLFECOMMON.SYSTEM_STALLED_CODE:
self.receiveSystemStalled(msgin)
elif message == CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
self.disconnect()
self.log.warning("BACK-END DOWN")
return False
else:
self.log.warning("CNET: received system %d in state Stalled" % message)
self.log.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.log.warning("received normal in state Stalled")
return False
def stateQuit(self, msgin):
self.decodeHeader(msgin)
if self._SystemMode:
message = msgin.readUint8('message')
self.log.debug("_CurrentReceivedNumber:%d (mode:%s) %d [%d/%d/%d]" % (self._CurrentReceivedNumber, str(self._SystemMode), message, msgin.sizeData(), msgin.sizeRead(), msgin.needRead()))
if message == CLFECOMMON.SYSTEM_SYNC_CODE:
self.log.debug("quit->synchronize")
self._ConnectionState = TConnectionState.Synchronize
self.receiveSystemSync(msgin)
return True
elif message == CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
self.disconnect()
self.log.warning("BACK-END DOWN")
return False
elif message == CLFECOMMON.SYSTEM_ACK_QUIT_CODE:
self.receiveSystemAckQuit(msgin)
else:
self.log.warning("CNET: received system %d in state Quit" % message)
self.log.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.log.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()
msgin.fromBytes(buffer)
self.log.debug("received message: %s" % msgin.showAllData())
if self._ConnectionState == TConnectionState.Login:
self.log.debug("state:Login")
stateBroke = self.stateLogin(msgin)
elif self._ConnectionState == TConnectionState.Synchronize:
self.log.debug("state:Synchronize")
stateBroke = self.stateSynchronize(msgin)
elif self._ConnectionState == TConnectionState.Connected:
self.log.debug("state:Connected")
stateBroke = self.stateConnected(msgin)
elif self._ConnectionState == TConnectionState.Probe:
self.log.debug("state:Probe")
stateBroke = self.stateProbe(msgin)
elif self._ConnectionState == TConnectionState.Stalled:
self.log.debug("state:Stalled")
stateBroke = self.stateStalled(msgin)
elif self._ConnectionState == TConnectionState.Quit:
self.log.debug("state:Quit")
stateBroke = self.stateQuit(msgin)
else:
stateBroke = False
self.log.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(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)
'''
self.log.debug("Push :%s" % msgout.showAllDataWrite())
maxImpulseBitSize = 1840 # = 230*8
cp = CActionFactory(self.log, self.world)
ag = cp.createFactory(INVALID_SLOT, TActionCode.ACTION_GENERIC_CODE)
bytelen = (msgout.sizeData() + 7) // 8
impulseMinBitSize = ag.size()
impulseBitSize = impulseMinBitSize + (4 + bytelen)*8
self.log.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(INVALID_SLOT, TActionCode.ACTION_GENERIC_MULTI_PART_CODE)
minimumBitSizeForMP = agmp.size()
availableSize = (maxImpulseBitSize - minimumBitSizeForMP) // 8
nbBlock = (bytelen + availableSize - 1) // availableSize
num = self._ImpulseMultiPartNumber
self._ImpulseMultiPartNumber += 1
self.log.debug("minimumBitSizeForMP:%d availableSize:%d nbBlock:%d num:%d _ImpulseMultiPartNumber:%d" % (minimumBitSizeForMP, availableSize, nbBlock, num, self._ImpulseMultiPartNumber))
for i in range(0, nbBlock):
self.log.debug("i:%d nbBlock:%d" % (i, nbBlock))
if i != 0:
# Create a new CActionFactory
agmp = cp.createFactory(INVALID_SLOT, 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 == 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:
self.log.debug("No Action")
pass
else:
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 = CActionBlock()
newBlock.Cylce = 0
newBlock.insert(self._Actions, i, len(block.Actions))
block.eraseToEnd(i)
if self._ConnectionState == TConnectionState.Connected:
self.sendNormalMessage()
#if len(self.world.Commands) > 0:
# cmd = self.world.Commands.pop(0)
def analyze(self):
if self.world.CurrentState == TState.st_connect:
if self.world.CShardNames != []:
if self.stepAction == 0 and self.world.CharacterSummaries != [] and self.clientTick > 0:
if self.world.CharacterSummaries[0].People == TPeople.Unknown:
bms = self.world.CreaterCharacter(self.msgXml)
self.push(bms)
self.stepAction = 1
else:
self.stepAction = 1
elif self.stepAction == 1 and self.world.CharacterSummaries != []:
if self.world.CharacterSummaries[0].People != TPeople.Unknown:
self.log.info("Account defined %s" % self.world.CharacterSummaries[0].Name)
bms = self.world.SelectChar(self.msgXml, 0)
self.push(bms)
self.stepAction = 2
def EmulateFirst(self, msgRawXml, databaseRawXml):
self.world.CurrentState = TState.st_start
self.msgXml = ET.fromstring(msgRawXml)
#ET.dump(msgXml)
self.databaseXml = ET.fromstring(databaseRawXml)
#ET.dump(databaseXml)
self._MsgXmlMD5 = getTextMD5(msgRawXml)
self._DatabaseXmlMD5 = getTextMD5(databaseRawXml)
self.decodeImpulse.loadMsg(self.msgXml)
self.decodeImpulse.loadDatabase(self.databaseXml)
self.connect()
self.log.info("Client Login")
self.sendSystemLogin()
self.world.CurrentState = TState.st_connect
self.log.info("Receive Message")
self.clientTick = 0
for _ in range(0, 50):
#while True:
self.log.debug("%s [%s: %d / %d] %s" % ("*" * 40, "Loop", self.clientTick, self.stepAction, "*" * 40))
self.update()
self.analyze()
self.send()
self.clientTick += 1
self.log.info("Client Quit")
self.sendSystemQuit()
class ClientKhanat:
def __init__(self,
khanat_host,
khanat_port_login = 40916,
khanat_port_frontend = 47851,
login="tester",
password="tester",
clientApp="Lirria",
LanguageCode="fr",
url="/login/r2_login.php",
suffix = None,
download_patch = False,
show_patch_detail=False,
size_buffer_file=1024):
self.log = logging.getLogger('myLogger')
if suffix is None:
suffix = str(random.randrange(1, 9999))
self.log.debug("suffix : %s" % suffix)
self.download_patch = download_patch
self.show_patch_detail = show_patch_detail
self.khanat_host = khanat_host
self.khanat_port_login = khanat_port_login
self.khanat_port_frontend = khanat_port_frontend
self.login = login + suffix
self.password = password
self.clientApp = clientApp
self.LanguageCode = LanguageCode
self.url = url
self.cookie, self.fsaddr, self.ringmainurl, self.fartp, self.stat, self.r2serverversion, self.r2backuppatchurl, self.r2patchurl = None, None, None, None, None, None, None, None
self.tempdir = tempfile.TemporaryDirectory(".khanat")
self.log.debug("Temporary directory:%s" % self.tempdir)
self.khanat_idx = CPersistentDataRecord(self.log)
self.UserAddr, self.UserKey, self.UserId = None, None, None
self.clientNetworkConnection = ClientNetworkConnection(self.khanat_host, self.khanat_port_frontend, self.login)
self.size_buffer_file = size_buffer_file
self.cFileContainer = CFileContainer()
def createAccount(self):
conn = http.client.HTTPConnection(host=self.khanat_host, port=self.khanat_port_login)
cmd = "/ams/index.php?page=register"
headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language' : 'en-US',
'Connection': 'keep-alive',
'DNT': '1',
'Cookie': 'PHPSESSID=lsoumn9f0ljgm3vo3hgjdead03',
'Host': self.khanat_host+':'+ str(self.khanat_port_login),
'Referer': 'http://' + self.khanat_host+':'+ str(self.khanat_port_login) + '/ams/index.php?page=register',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20100101 Firefox/6.0',
'Content-Type': 'application/x-www-form-urlencoded'}
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
params = urllib.parse.urlencode({'Username': self.login, 'Password': self.password, 'ConfirmPass': self.password, 'Email': self.login+'@khaganat.net', 'TaC': 'on', 'function': 'add_user'})
conn.request("POST", cmd, params, headers)
response = conn.getresponse()
if ( int(response.status) == 302 ):
conn.close()
self.log.info("Account : %s" % self.login)
return
elif ( int(response.status) != 200 ):
self.log.error("Impossible to create account (return code:" + str(response.status) + ")")
sys.exit(2)
ret = response.read()
conn.close()
ret2 = ret.decode()
try:
state, comment = ret2.split(":", 2)
except:
state = 1
comment = ""
if int(state) != 1:
self.log.error("Impossible to create account (state:" + state + ", comment:" + comment.strip() + ")")
sys.exit(2)
errordetected = False
for line in ret2.split('\n'):
m = re.search("((?P.*) Error )(?P[^.]+)", line)
if m:
if m.group('comment') == 'Username ' + self.login + ' is in use':
continue
if m.group('comment') == 'Email is in use':
continue
self.log.error('Impossible to create account: field:%s (%s)' % (m.group('type'), m.group('comment')))
errordetected = True
if errordetected:
sys.exit(2)
self.log.info("Reuse account : %s" % self.login)
def connectR2(self):
conn = http.client.HTTPConnection(host=self.khanat_host, port=self.khanat_port_login)
cmd = self.url + "?cmd=ask&cp=2&login=" + self.login + "&lg=" + self.LanguageCode
conn.request("GET", cmd)
response = conn.getresponse()
if ( int(response.status) != 200 ):
self.log.error("Impossible to get salt (return code:" + str(response.status) + ")")
sys.exit(2)
ret = response.read()
conn.close()
try:
state, salt = ret.decode().split(":", 1)
except UnicodeDecodeError:
try:
state, salt = ret.decode(encoding='cp1252').split(":", 1)
except UnicodeDecodeError:
self.log.error("Impossible to read output login")
sys.exit(2)
if int(state) != 1:
self.log.error("Impossible to get salt (state:" + state + ")")
cryptedPassword = crypt.crypt(self.password, salt)
conn = http.client.HTTPConnection(host=self.khanat_host, port=self.khanat_port_login)
cmd = self.url + "?cmd=login&login=" + self.login + "&password=" + cryptedPassword + "&clientApplication=" + self.clientApp + "&cp=2" + "&lg=" + self.LanguageCode
conn.request("GET", cmd)
response = conn.getresponse()
self.log.debug("%s %s" %(response.status, response.reason))
ret = response.read()
self.log.debug(ret)
try:
line = ret.decode().split('\n')
except UnicodeDecodeError:
try:
line = ret.decode(encoding='cp1252').split('\n')
except UnicodeDecodeError:
self.log.error("Impossible to read output login")
sys.exit(2)
self.log.debug(line[0])
self.log.debug("line 0 '%s'" % line[0])
self.log.debug("line 1 '%s'" % line[1])
try:
state, self.cookie, self.fsaddr, self.ringmainurl, self.fartp, self.stat = line[0].split("#", 6)
except:
try:
state, self.cookie, self.fsaddr, self.ringmainurl, self.fartp = line[0].split("#", 5)
self.stat = 0
except:
state, error = line[0].split(":", 1)
if int(state) != 1:
self.log.error(error)
sys.exit(2)
self.r2serverversion, self.r2backuppatchurl, self.r2patchurl = line[1].split("#")
self.log.debug("%s %s %s %s %s %s %s %s %s" % (state, self.cookie, self.fsaddr, self.ringmainurl, self.fartp, self.stat, self.r2serverversion, self.r2backuppatchurl, self.r2patchurl))
self.UserAddr, self.UserKey, self.UserId = [ int(x, 16) for x in self.cookie.split('|') ]
conn.close()
self.log.info("Login Ok")
self.clientNetworkConnection.cookiesInit(self.UserAddr, self.UserKey, self.UserId)
def downloadFileUrl(self, source, dest):
self.log.info("Download %s (destination:%s)" % (source, dest))
with urllib.request.urlopen(source) as conn :
header = conn.getheaders()
file_size = 0
for key, value in header:
if key == 'Content-Length':
file_size = int(value)
break
self.log.debug("size:%d", file_size)
file_size_dl = 0
block_size = self.size_buffer_file # 1024
with open(dest, 'wb') as fp:
while True:
buffer = conn.read(block_size)
if not buffer:
break
file_size_dl += len(buffer)
fp.write(buffer)
self.log.debug("Download %s %10d [%6.2f%%]" % (source, file_size_dl, file_size_dl * 100. / file_size))
fp.close()
self.log.debug("Downloaded %s (%d)" % (source, file_size))
def getServerFile(self, name, bZipped = False, specifyDestName = None):
srcName = name
if specifyDestName:
dstName = specifyDestName
else:
dstName = os.path.basename(name)
if bZipped:
srcName += ".ngz"
dstName += ".ngz"
self.log.info("Download %s (destination:%s, zip:%d)" % (srcName, dstName, bZipped))
dstName = os.path.join(self.tempdir.name, dstName)
self.downloadFileUrl( 'http://' + self.r2patchurl + '/' + srcName, dstName)
return dstName
def downloadAllPatch(self):
# TODO - check where client search file to download
for file in self.khanat_idx.CBNPFile:
tmp = self.getServerFile("%05d/%s.lzma" % (int(self.r2serverversion), file.FileName), False, "")
with lzma.open(tmp) as fin:
dstName = os.path.join(self.tempdir.name, file.FileName)
with open(dstName, "wb") as fout:
data = fin.read()
fout.write(data)
self.log.info("%s" % dstName)
os.remove(tmp)
# khanat-opennel-code/code/ryzom/client/src/login_patch.cpp # void CCheckThread::run ()
FilesToPatch = []
for file in self.khanat_idx.CBNPFile:
FilesToPatch.append(file)
# Here we got all the files to patch in FilesToPatch and all the versions that must be obtained Now we have to get the optional categories
OptionalCat = []
for category in self.khanat_idx.Categories:
if category._IsOptional:
for file in category._Files:
bAdded = False
for file2 in FilesToPatch:
if file2 == file:
OptionalCat.append(category._Name)
bAdded = True
break
if bAdded:
break
# For all categories that required an optional category if the cat required is present the category that reference it must be present
for category in self.khanat_idx.Categories:
if category._IsOptional and not len(category._CatRequired) == 0:
bFound = False
for cat in OptionalCat:
if category._Name == cat:
bFound = True
break
if bFound:
for cat in OptionalCat:
if category._CatRequired == cat:
OptionalCat.append(category._Name)
break
# Delete categories optional cat that are hidden
for category in self.khanat_idx.Categories:
if category._IsOptional and category._Hidden:
for cat in OptionalCat:
if category._Name == cat:
OptionalCat.remove(category._Name)
break
# Get all extract to category and check files inside the bnp with real files
for category in self.khanat_idx.Categories:
if len(category._UnpackTo) != 0:
for file in category._Files:
# TODO
# readHeader()
pass
def DownloadMinimum(self):
self.log.debug("-" * 80)
for file in self.khanat_idx.CBNPFile:
if file.FileName != "kh_server.bnp":
continue
tmp = self.getServerFile("%05d/%s.lzma" % (int(self.r2serverversion), file.FileName), False, "")
with lzma.open(tmp) as fin:
dstName = os.path.join(self.tempdir.name, file.FileName)
with open(dstName, "wb") as fout:
data = fin.read()
fout.write(data)
self.log.info("%s" % dstName)
os.remove(tmp)
def Emulate(self):
self.createAccount()
self.connectR2()
# download patch
self.ryzomidx = self.getServerFile("%05d/ryzom_%05d.idx" % (int(self.r2serverversion), int(self.r2serverversion)), False, "")
self.khanat_idx.readFromBinFile(self.ryzomidx)
self.khanat_idx.CProductDescriptionForClient_apply()
# Show detail patch
if self.show_patch_detail:
self.khanat_idx.decrypt_token()
self.khanat_idx.show()
# Todo analyze patch and download if necessary or update if incremental - see category
# Download all file in patch - login_patch.cpp:2578 # void CPatchThread::processFile (CPatchManager::SFileToPatch &rFTP)
if self.download_patch:
self.downloadAllPatch()
else:
self.DownloadMinimum()
self.cFileContainer = CFileContainer()
self.cFileContainer.addSearchPath(self.tempdir.name)
msgRawXml = self.cFileContainer.getdata("msg.xml").decode()
databaseRawXml = self.cFileContainer.getdata("database.xml").decode()
self.clientNetworkConnection.EmulateFirst(msgRawXml, databaseRawXml)
def main():
FORMAT = '%(asctime)-15s %(levelname)s %(filename)s:%(lineno)d %(message)s'
logging.basicConfig(format=FORMAT)
log = logging.getLogger('myLogger')
parser = argparse.ArgumentParser()
parser.add_argument("--khanat-host", help="khanat host to auhtenticate", default='localhost')
parser.add_argument("--suffix", help="define suffix")
parser.add_argument("-d", "--debug", help="show debug message", action='store_true')
parser.add_argument("-p", "--download-patch", help="show debug message", action='store_true')
parser.add_argument("-s", "--show-patch-detail", help="show debug message", action='store_true')
parser.add_argument("--size-buffer-file", help="size buffer to download file", type=int, default=1024)
parser.add_argument("--khanat-port-login", help="port http login", type=int, default=40916)
parser.add_argument("--khanat-port-frontend", help="port UDP frontend", type=int, default=47851)
args = parser.parse_args()
if args.debug:
level = logging.getLevelName('DEBUG')
else:
level = logging.getLevelName('INFO')
log.setLevel(level)
client = ClientKhanat(args.khanat_host, khanat_port_login=args.khanat_port_login, khanat_port_frontend=args.khanat_port_frontend, suffix=args.suffix, download_patch=args.download_patch, show_patch_detail=args.show_patch_detail, size_buffer_file=args.size_buffer_file)
client.Emulate()
log.info("End")
if __name__ == "__main__":
#TestBitStream()
#TestCBitSet()
main()