decode visual properties

This commit is contained in:
AleaJactaEst 2020-07-27 22:17:48 +02:00
parent 317fd2cf71
commit 9755a2941b
8 changed files with 486 additions and 49 deletions

View file

@ -21,6 +21,11 @@
# Ex.: # Ex.:
# sudo tcpdump -i docker0 -w capture2.pcap # sudo tcpdump -i docker0 -w capture2.pcap
# ./spykhanat.py --pcap-file=../capture2.pcap --msg-xml=../khanat-opennel-code/code/ryzom/common/data_common/msg.xml # ./spykhanat.py --pcap-file=../capture2.pcap --msg-xml=../khanat-opennel-code/code/ryzom/common/data_common/msg.xml
# ./spykhanat.py -m ../khanat-opennel-code/code/ryzom/common/data_common/msg.xml --yaml capture-2020-07-08-00-33-khanatclient.yml -w ../khanat-opennel-code/code/ryzom/common/data_common/database.xml -p capture-2020-07-08-00-33-khanatclient.pcap --filter-host-service='172.17.0.2:47851'
#
# FILEDATA="capture-2020-07-08-00-33-khanatclient.pcap"
# ./spykhanat.py -m ../khanat-opennel-code/code/ryzom/common/data_common/msg.xml --yaml ${FILEDATA::-5}.yml -w ../khanat-opennel-code/code/ryzom/common/data_common/database.xml -p $FILEDATA --filter-host-service='172.17.0.2:47851'
#
# install pcapfile # install pcapfile
# pip install pypcapfile # pip install pypcapfile
@ -47,6 +52,7 @@ from tools import CImpulseDecoder
from tools import CAction from tools import CAction
from tools import Impulse from tools import Impulse
from tools import CPropertyDecoder from tools import CPropertyDecoder
from tools import TVPNodeBase
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from datetime import datetime from datetime import datetime
@ -195,56 +201,111 @@ class SpyPcap():
def add_registered_action(self, clientid, action): def add_registered_action(self, clientid, action):
self.client_state[clientid]['RegisteredAction'].setdefault(action.Code, []) self.client_state[clientid]['RegisteredAction'].setdefault(action.Code, [])
self.client_state[clientid]['RegisteredAction'][action.Code].append(action) self.client_state[clientid]['RegisteredAction'][action.Code].append(action)
self.client_state[clientid]['PropertyDecoder'] = CPropertyDecoder() self.client_state[clientid]['PropertyDecoder'] = CPropertyDecoder.CPropertyDecoder()
self.client_state[clientid]['VisualPropertyTreeRoot'] = TVPNodeBase.TVPNodeBase("_VisualPropertyTreeRoot")
self.client_state[clientid]['VisualPropertyTreeRoot'].build_tree()
# def decodeDiscreetProperties(self, clientid, msgin):
# # khanat-opennel-code/code/ryzom/client/src/network_connection.h:148 void decodeDiscreetProperties( NLMISC::CBitMemStream& msgin )
# BranchHasPayload = msgin.readBool("BranchHasPayload")
# if BranchHasPayload:
# if self.client_state[clientid]['VisualPropertyTreeRoot'].isLeaf():
# PropIndex = self.client_state[clientid]['VisualPropertyTreeRoot'].PropIndex
# self.client_state[clientid]['VisualPropertyTreeRoot'].decodeDiscreetProperty(msgin, PropIndex)
#if ( BranchHasPayload )
# {
# if ( isLeaf() )
# {
# SlotContext.NetworkConnection->decodeDiscreetProperty( msgin, PropIndex );
# }
# else
# {
# if ( a() ) a()->decodeDiscreetProperties( msgin );
# if ( b() ) b()->decodeDiscreetProperties( msgin );
# }
# }
def decodeVisualProperties(self, clientid, msgin): def decodeVisualProperties(self, clientid, msgin):
""" """
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1512 void CNetworkConnection::decodeVisualProperties( CBitMemStream& msgin ) khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1512 void CNetworkConnection::decodeVisualProperties( CBitMemStream& msgin )
""" """
actions = [] actions = []
properties = []
try: try:
while True: while True:
property = {}
# if ( msgin.getPosInBit() + (sizeof(TCLEntityId)*8) > msgin.length()*8 ) return # if ( msgin.getPosInBit() + (sizeof(TCLEntityId)*8) > msgin.length()*8 ) return
if msgin.sizeRead() + (8*8 ) > msgin.sizeData() * 8: # if msgin.sizeRead() + (8*8 ) > msgin.sizeData() * 8:
return #if msgin.needRead() < (8*8):
if msgin.needRead() < 8:
logging.getLogger(LOGGER).debug("too small no decodeVisualProperties [{0} > {1}]".format(msgin.sizeRead() + (8*8 ), msgin.sizeData() * 8 ))
print("-"*80)
print(properties)
return properties
logging.getLogger(LOGGER).debug("too small no decodeVisualProperties [{0} > {1}]".format(msgin.sizeRead() + (8*8 ), msgin.sizeData() * 8 ))
slot = msgin.readUint8("Slot") slot = msgin.readUint8("Slot")
property['slot'] = slot
associationBits = msgin.readSerial(2, "associationBits") associationBits = msgin.readSerial(2, "associationBits")
property['associationBits'] = associationBits
logging.getLogger(LOGGER).debug("slot:{0} (associationBits:{1})".format(slot, associationBits))
if self.client_state[clientid]['PropertyDecoder'] .associationBitsHaveChanged( slot, associationBits ) and (slot==0): if self.client_state[clientid]['PropertyDecoder'] .associationBitsHaveChanged( slot, associationBits ) and (slot==0):
if self.client_state[clientid]['PropertyDecoder'] .isUsed( slot ): if self.client_state[clientid]['PropertyDecoder'] .isUsed( slot ):
sheet = self.client_state[clientid]['PropertyDecoder'] .getSheet(slot) sheet = self.client_state[clientid]['PropertyDecoder'] .getSheet(slot)
property['sheet'] = sheet
logging.getLogger(LOGGER).debug("sheet:{0}".format(sheet))
# TODO - remove sheet found in the list
timestampIsThere = msgin.readBool("timestampIsThere") timestampIsThere = msgin.readBool("timestampIsThere")
if timestampIsThere: if timestampIsThere:
timestampDelta = msgin.readSerial(4, "timestampDelta") timestampDelta = msgin.readSerial(4, "timestampDelta")
timestamp = self.client_state[clientid]['CurrentReceivedNumber'] - timestampDelta timestamp = self.client_state[clientid]['CurrentReceivedNumber'] - timestampDelta
logging.getLogger(LOGGER).debug("timestamp:{0} (timestampDelta:{1})".format(timestamp, timestampDelta))
else: else:
timestamp = self.client_state[clientid]['CurrentReceivedNumber'] timestamp = self.client_state[clientid]['CurrentReceivedNumber']
logging.getLogger(LOGGER).debug("timestamp:{0}".format(timestamp))
property['timestamp'] = timestamp
property.setdefault('Actions', [])
# Tree # Tree
# currentNode->a() # currentNode->a()
BranchHasPayload = msgin.readBool("BranchHasPayload") BranchHasPayload = msgin.readBool("BranchHasPayload [_VisualPropertyTreeRoot.VPA]")
logging.getLogger(LOGGER).debug("_VisualPropertyTreeRoot.VPA->BranchHasPayload:{0}".format(BranchHasPayload))
if BranchHasPayload: if BranchHasPayload:
# _PropertyDecoder.receive( _CurrentReceivedNumber, ap ); # _PropertyDecoder.receive( _CurrentReceivedNumber, ap );
# Create a new action # Create a new action
cActionPosition = CAction.CActionPosition(slot, Enum.TActionCode.ACTION_POSITION_CODE, self.client_state[clientid]['world']) cActionPosition = CAction.CActionPosition(slot, Enum.TActionCode.ACTION_POSITION_CODE, self.client_state[clientid]['world'])
cActionPosition.set_name('POSITION_CODE')
self.client_state[clientid]['PropertyDecoder'] .receive(cActionPosition) self.client_state[clientid]['PropertyDecoder'] .receive(cActionPosition)
cActionPosition.unpack(msgin) cActionPosition.unpack(msgin)
actions.append(cActionPosition) actions.append(cActionPosition)
property['Actions'] .append(cActionPosition)
# currentNode->b() # currentNode->b()
BranchHasPayload = msgin.readBool("BranchHasPayload") BranchHasPayload = msgin.readBool("BranchHasPayload [_VisualPropertyTreeRoot.VPB]")
logging.getLogger(LOGGER).debug("_VisualPropertyTreeRoot.VPB->BranchHasPayload:{0}".format(BranchHasPayload))
if BranchHasPayload: if BranchHasPayload:
# currentNode->b()->a() # currentNode->b()->a()
BranchHasPayload = msgin.readBool("BranchHasPayload") BranchHasPayload = msgin.readBool("BranchHasPayload [_VisualPropertyTreeRoot.VPB.VPA]")
logging.getLogger(LOGGER).debug("_VisualPropertyTreeRoot.VPB.VPA->BranchHasPayload:{0}".format(BranchHasPayload))
if BranchHasPayload:
# Create a new action -> PROPERTY_ORIENTATION # Create a new action -> PROPERTY_ORIENTATION
cActionOrientation= CAction.CActionSint64(slot, self.client_state[clientid]['world']) cActionOrientation= CAction.CActionSint64(slot, Enum.TPropIndex.PROPERTY_ORIENTATION, self.client_state[clientid]['world'])
cActionOrientation.PropertyCode = Enum.TPropIndex.PROPERTY_ORIENTATION cActionOrientation.setNbBits(Enum.TPropIndex.PROPERTY_ORIENTATION, 'PROPERTY_ORIENTATION')
cActionOrientation.set_name('PROPERTY_ORIENTATION')
cActionOrientation.unpack(msgin) cActionOrientation.unpack(msgin)
#self.client_state[clientid]['PropertyDecoder'] .receive(cActionPosition) #self.client_state[clientid]['PropertyDecoder'] .receive(cActionPosition)
actions.append(cActionOrientation) actions.append(cActionOrientation)
property['Actions'] .append(cActionOrientation)
# Discreet properties # Discreet properties
# _VisualPropertyTreeRoot->b()->b()
actions = self.client_state[clientid]['VisualPropertyTreeRoot'].decodeDiscreetPropertiesVpbVpb(clientid, msgin, slot, self.client_state[clientid]['world'])
for action in actions:
property['Actions'] .append(action)
#self.decodeDiscreetProperties(clientid, msgin)
properties.append(property)
except Exception as e:
raise e
except: except:
# Detect end of stream (little hard to close) # Detect end of stream (little hard to close)
pass pass
return properties
def decode_server(self, clientid, msgin, receivedPacket, receivedAck, nextSentPacket=0): def decode_server(self, clientid, msgin, receivedPacket, receivedAck, nextSentPacket=0):
""" """
@ -282,7 +343,12 @@ class SpyPcap():
pass pass
num += 1 num += 1
#actionFactory = CAction.CActionFactory(None) #actionFactory = CAction.CActionFactory(None)
logging.getLogger(LOGGER).debug("[decode_server] (%s)" % (msgin.showAllData()))
try:
action = self.actionFactory.unpack(msgin) action = self.actionFactory.unpack(msgin)
except Exception as e:
logging.getLogger(LOGGER).debug("[decode_server] (%s)" % (msgin.showAllData()))
raise e
logging.getLogger(LOGGER).debug("action:%s" % action) logging.getLogger(LOGGER).debug("action:%s" % action)
#action = self._CActionFactory.unpack(msgin) #action = self._CActionFactory.unpack(msgin)
if keep: if keep:
@ -292,8 +358,8 @@ class SpyPcap():
logging.getLogger(LOGGER).debug("append Code:%s" % str(action.Code)) logging.getLogger(LOGGER).debug("append Code:%s" % str(action.Code))
self.add_registered_action(clientid, action) self.add_registered_action(clientid, action)
# khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1512 void CNetworkConnection::decodeVisualProperties( CBitMemStream& msgin ) # khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1512 void CNetworkConnection::decodeVisualProperties( CBitMemStream& msgin )
self.decodeVisualProperties(clientid, msgin) properties = self.decodeVisualProperties(clientid, msgin)
return actions return actions, properties
def decode_client_send_normal_message(self, msgin, clientid, dst, sequenceid, name, Reference): def decode_client_send_normal_message(self, msgin, clientid, dst, sequenceid, name, Reference):
''' '''
@ -428,6 +494,7 @@ class SpyPcap():
def decode_khanat_message(self, msgin, src, dst, sequenceid, clientname, Parent, Source): def decode_khanat_message(self, msgin, src, dst, sequenceid, clientname, Parent, Source):
target = "%s_%s" % (Source, Parent[7:]) target = "%s_%s" % (Source, Parent[7:])
actions = [] actions = []
properties = []
impulses = [] impulses = []
databases = [] databases = []
CurrentSendNumber = msgin.readSint32('CurrentSendNumber') CurrentSendNumber = msgin.readSint32('CurrentSendNumber')
@ -439,7 +506,7 @@ class SpyPcap():
if not SystemMode: if not SystemMode:
_LastReceivedAck = msgin.readSint32('LastReceivedAck'); _LastReceivedAck = msgin.readSint32('LastReceivedAck');
logging.getLogger(LOGGER).debug("[Server -> Client] Normal Mode {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d}" % (CurrentSendNumber, src, dst, _LastReceivedAck)) logging.getLogger(LOGGER).debug("[Server -> Client] Normal Mode {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d}" % (CurrentSendNumber, src, dst, _LastReceivedAck))
actions = self.decode_server(dst, msgin, CurrentSendNumber, CurrentSendNumber-1) actions, properties = self.decode_server(dst, msgin, CurrentSendNumber, CurrentSendNumber-1)
if actions: if actions:
logging.getLogger(LOGGER).debug('list actions: [' + str(len(actions)) + '] ' +','.join( [ str(x) for x in actions] ) ) logging.getLogger(LOGGER).debug('list actions: [' + str(len(actions)) + '] ' +','.join( [ str(x) for x in actions] ) )
else: else:
@ -624,7 +691,7 @@ class SpyPcap():
#cActionFactory.unpack(msgin) #cActionFactory.unpack(msgin)
logging.getLogger(LOGGER).debug("[Server -> Client] msg:%s" % msgin.showAllData()) logging.getLogger(LOGGER).debug("[Server -> Client] msg:%s" % msgin.showAllData())
#logging.getLogger(LOGGER).info("impulses:%s" % str(impulses)) #logging.getLogger(LOGGER).info("impulses:%s" % str(impulses))
return actions, impulses, databases return actions, impulses, databases, properties
def read(self): def read(self):
file = open( self.pcap_file , 'rb') file = open( self.pcap_file , 'rb')
@ -659,6 +726,7 @@ class SpyPcap():
actions_servers = [] actions_servers = []
impulses_servers = [] impulses_servers = []
impulses_clients = [] impulses_clients = []
properties_servers = []
if self.show_raw_packet: if self.show_raw_packet:
logging.getLogger(LOGGER).debug("[raw packet] timestamp:%s [%s] src:%s:%d dst:%s:%d data:%s" % (pkt.timestamp, logging.getLogger(LOGGER).debug("[raw packet] timestamp:%s [%s] src:%s:%d dst:%s:%d data:%s" % (pkt.timestamp,
datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"),
@ -695,7 +763,7 @@ class SpyPcap():
if (self.khanat_host_service and self.khanat_host_service.match(src)) or ( not self.khanat_host_service and khanat_host == src): if (self.khanat_host_service and self.khanat_host_service.match(src)) or ( not self.khanat_host_service and khanat_host == src):
_provenance = 'Server -> Client' _provenance = 'Server -> Client'
logging.getLogger(LOGGER).debug("[%s] (message received) [%s] %s" % (_provenance, datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), msgin.showAllData())) logging.getLogger(LOGGER).debug("[%s] (message received) [%s] %s" % (_provenance, datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), msgin.showAllData()))
actions_servers, impulses_servers, databases_servers = self.decode_khanat_message(msgin, src, dst, sequenceid, list_host[dst], Reference, list_host[src]) actions_servers, impulses_servers, databases_servers, properties_servers = self.decode_khanat_message(msgin, src, dst, sequenceid, list_host[dst], Reference, list_host[src])
else: else:
_provenance = 'Client -> Server' _provenance = 'Client -> Server'
logging.getLogger(LOGGER).debug("[%s] (message received) [%s] %s" % (_provenance, datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), msgin.showAllData())) logging.getLogger(LOGGER).debug("[%s] (message received) [%s] %s" % (_provenance, datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), msgin.showAllData()))
@ -802,6 +870,29 @@ class SpyPcap():
id += 1 id += 1
#print("-"*30) #print("-"*30)
if properties_servers:
self.outyaml.write("\nvisual_properties_%s_%d:\n" %(list_host[src], sequenceid))
for property in properties_servers:
self.outyaml.write(" slot: %d\n" % (property['slot']))
self.outyaml.write(" parents: %s\n" % Reference)
self.outyaml.write(" associationBits: %d\n" % (property['associationBits']))
self.outyaml.write(" timestamp: %d\n" % (property['timestamp']))
for action in property['Actions']:
try:
self.outyaml.write(" %s: %s\n" % (action.get_name(), str(action.value)))
except AttributeError:
# TODO - change print if CAtion is Position or other (and not CActionSint64)
params = action.get_parameter()
self.outyaml.write(" %s:\n" % (action.get_name()))
for key in params:
if key == "Reference":
pass
elif key == "GameCycle":
pass
elif key == "Slot":
pass
else:
self.outyaml.write(" %s: %s\n" % (key, params[key]))
if actions_clients: if actions_clients:
self.outyaml.write("\nblock_%s_%d:\n" %(list_host[src], sequenceid)) self.outyaml.write("\nblock_%s_%d:\n" %(list_host[src], sequenceid))
@ -834,6 +925,8 @@ class SpyPcap():
# params = Impulse.get_parameter() # params = Impulse.get_parameter()
# self.outyaml.write(" %s:\n" % (Impulse.get_name())) # self.outyaml.write(" %s:\n" % (Impulse.get_name()))
# id += 1 # id += 1
#if Reference == 'packet_409':
# raise "STOP"
sequenceid += 1 sequenceid += 1
sequencenum += 1 sequencenum += 1
for client in self.client_state: for client in self.client_state:
@ -850,12 +943,13 @@ def main():
# #logger.append(logging.getLogger(DecodeImpuls.LOGGER)) # #logger.append(logging.getLogger(DecodeImpuls.LOGGER))
# #logger.append(logging.getLogger(BitStream.LOGGER)) # #logger.append(logging.getLogger(BitStream.LOGGER))
# logger.append(logging.getLogger(CStringManager.LOGGER)) # logger.append(logging.getLogger(CStringManager.LOGGER))
# logger.append(logging.getLogger(CAction.LOGGER)) #logger.append(logging.getLogger(CAction.LOGGER))
# logger.append(logging.getLogger(CActionFactory.LOGGER)) #logger.append(logging.getLogger(CActionFactory.LOGGER))
# logger.append(logging.getLogger(BitStream.LOGGER)) # logger.append(logging.getLogger(BitStream.LOGGER))
logger.append(logging.getLogger(DecodeDatabase.LOGGER)) #logger.append(logging.getLogger(DecodeDatabase.LOGGER))
logger.append(logging.getLogger(Impulse.LOGGER)) #logger.append(logging.getLogger(Impulse.LOGGER))
CImpulseDecoder #logger.append(logging.getLogger(TVPNodeBase.LOGGER))
# CImpulseDecoder
# logger.append(logging.getLogger('CGenericMultiPartTemp')) # logger.append(logging.getLogger('CGenericMultiPartTemp'))
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()

View file

@ -125,6 +125,20 @@ class BitStream():
name = name.strip().split(' ')[0].strip() name = name.strip().split(' ')[0].strip()
self._groupWrite.append((p1, p1+nbits, name, typeName, value)) self._groupWrite.append((p1, p1+nbits, name, typeName, value))
def pushSerial64(self, value, nbits, decode=True, typeName=None):
if nbits > 32:
p1 = self._pos
msd = value >> 32
self.internalSerial(msd, nbits - 32, False, typeName)
self.internalSerial(value, 32, False, typeName)
value = msd << 32 | msd2
if typeName is None:
typeName = 'Uint{0}'.format(nbits)
self._groupWrite.append((p1, p1+nbits, name, typeName, value))
return value
else:
return self.internalSerial(value, nbits, decode, typeName)
def pushBool(self, value, decode=True): def pushBool(self, value, decode=True):
p1 = self._pos p1 = self._pos
if value: if value:
@ -553,6 +567,22 @@ class BitStream():
self._groupRead.append((v1, v1+nbits, name, typeName, value)) self._groupRead.append((v1, v1+nbits, name, typeName, value))
return value return value
def readSerial64(self, nbits, name="", decode=True, typeName=None):
if nbits > 32:
v1 = self._read
msd = self.readSerial(nbits - 32, name, False, typeName)
msd2 = self.readSerial(32, name, False, typeName)
value = msd << 32 | msd2
if decode:
if typeName is None:
typeName = 'Uint{0}'.format(nbits)
self._groupRead.append((v1, v1+nbits, name, typeName, value))
return value
else:
if typeName is None:
typeName = 'Uint{0}'.format(nbits)
return self.readSerial(nbits, name, decode, typeName)
def readBool(self, name): def readBool(self, name):
v1 = self._read v1 = self._read
v = self.readSerial(1, name=name, decode=False, typeName='Bool') v = self.readSerial(1, name=name, decode=False, typeName='Bool')

View file

@ -27,6 +27,32 @@ from tools import Enum
LOGGER='CActionFactory' LOGGER='CActionFactory'
INVALID_SLOT = 0xff INVALID_SLOT = 0xff
# khanat-opennel-code/code/ryzom/common/src/game_share/action_sint64.cpp:55 void CActionSint64::registerNumericPropertiesRyzom()
PROPERTY_TO_NB_BIT = [0 for _ in range(0, Enum.TPropIndex.NB_VISUAL_PROPERTIES)]
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_ORIENTATION] = 32
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_SHEET] = 52
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_BEHAVIOUR] = 48
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_NAME_STRING_ID] = 32
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_TARGET_ID] = 8
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_MODE] = 44
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_VPA] = 64
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_VPB] = 47
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_VPC] = 58
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_ENTITY_MOUNTED_ID] = 8
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_RIDER_ENTITY_ID] = 8
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_CONTEXTUAL] = 16
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_BARS] = 32
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_TARGET_LIST] = 32 # USER_DEFINED_PROPERTY_NB_BITS
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_VISUAL_FX] = 11
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_GUILD_SYMBOL] = 60
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_GUILD_NAME_ID] = 32
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_EVENT_FACTION_ID] = 32
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_PVP_MODE] = Enum.TPVPMode.NbBits
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_PVP_CLAN] = 32
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_OWNER_PEOPLE] = 3 # 4 races + unknow
PROPERTY_TO_NB_BIT[Enum.TPropIndex.PROPERTY_OUTPOST_INFOS] = 16 # 15+1
class CAction: class CAction:
def __init__(self, slot, code, world): def __init__(self, slot, code, world):
self.Code = code self.Code = code
@ -385,8 +411,10 @@ class CActionSint64(CAction):
def __init__(self, slot, code, world): def __init__(self, slot, code, world):
super().__init__(slot, code, world) super().__init__(slot, code, world)
self.value = 0 self.value = 0
self.NbBits = 0 self.NbBits = 64
self.PropertyToNbBit = { TPropIndex.TPropIndex.PROPERTY_ORIENTATION: 32, self.NameProperty = 'None'
self.PropertyToNbBit = {
TPropIndex.TPropIndex.PROPERTY_ORIENTATION: 32,
TPropIndex.TPropIndex.PROPERTY_SHEET: 52, TPropIndex.TPropIndex.PROPERTY_SHEET: 52,
TPropIndex.TPropIndex.PROPERTY_BEHAVIOUR: 48, TPropIndex.TPropIndex.PROPERTY_BEHAVIOUR: 48,
TPropIndex.TPropIndex.PROPERTY_NAME_STRING_ID: 32, TPropIndex.TPropIndex.PROPERTY_NAME_STRING_ID: 32,
@ -418,22 +446,31 @@ class CActionSint64(CAction):
return "CActionSint64" + super().__str__() return "CActionSint64" + super().__str__()
def unpack(self, msgin): def unpack(self, msgin):
logging.getLogger(LOGGER).debug("nb bit:{0}".format(self.NbBits))
logging.getLogger(LOGGER).debug("msgin:%s" % msgin.showAllData()) logging.getLogger(LOGGER).debug("msgin:%s" % msgin.showAllData())
self.value = msgin.readUint64('value') # self.value = msgin.readSerial( self.NbBits, 'value')
self.value = msgin.readSerial64( self.NbBits, self.NameProperty)
logging.getLogger(LOGGER).debug("msgin:%s" % msgin.showAllData()) logging.getLogger(LOGGER).debug("msgin:%s" % msgin.showAllData())
#self.NbBits = msgin.readUint32('NbBits') #self.NbBits = msgin.readUint32('NbBits')
logging.getLogger(LOGGER).debug("value:%u" % self.value) logging.getLogger(LOGGER).debug("value:%u" % self.value)
logging.getLogger(LOGGER).debug("msgin:%s" % msgin.showAllData()) logging.getLogger(LOGGER).debug("msgin:%s" % msgin.showAllData())
def pack(self, msgout): def pack(self, msgout):
super().pack(msgout) super().pack(msgout)
msgout.pushUint64(self.value) #msgout.pushUint64(self.value)
msgout.pushSerial64(self.value, self.NbBits)
#msgout.pushUint32(self.NbBits) #msgout.pushUint32(self.NbBits)
def reset(self): def reset(self):
self.value = 0 self.value = 0
self.NbBits = 0 self.NbBits = 0
self.NameProperty = 'None'
def setNbBits(self, propIndex, nameproperty):
self.NbBits = PROPERTY_TO_NB_BIT[propIndex]
self.NameProperty = nameproperty
self.set_name(nameproperty)
logging.getLogger(LOGGER).debug("NameProperty:{1} NbBits:{0}".format(self.NbBits, self.NameProperty ))
class CActionBlock: class CActionBlock:

View file

@ -91,6 +91,18 @@ class CActionFactory:
action.Slot = slot action.Slot = slot
return action return action
def createByPropIndex(self, slot, propIndex, nameproperty):
logging.getLogger(LOGGER).debug('createByPropIndex (slot:{0}, propIndex:{1}, nameproperty:{2})'.format(slot, propIndex, nameproperty))
if propIndex == Enum.TPropIndex.PROPERTY_POSITION:
action = self.create(slot, Enum.TActionCode.ACTION_POSITION_CODE)
else:
action =self. create(slot, Enum.TActionCode.ACTION_SINT64)
action.setNbBits(propIndex, nameproperty)
action.PropertyCode = propIndex
return action
# khanat-opennel-code/code/ryzom/common/src/game_share/action_factory.cpp:152
def unpack(self, msgin, Reference = None, Name = None): def unpack(self, msgin, Reference = None, Name = None):
''' '''
khanat-opennel-code/code/ryzom/common/src/game_share/action_factory.cpp : CAction *CActionFactory::unpack (NLMISC::CBitMemStream &message, NLMISC::TGameCycle /* currentCycle */ ) khanat-opennel-code/code/ryzom/common/src/game_share/action_factory.cpp : CAction *CActionFactory::unpack (NLMISC::CBitMemStream &message, NLMISC::TGameCycle /* currentCycle */ )
@ -107,12 +119,10 @@ class CActionFactory:
try: try:
action.unpack (msgin); action.unpack (msgin);
except RuntimeError: except RuntimeError:
log = logging.getLogger('myLogger') logging.getLogger(LOGGER).warning('Missing code to unpack (code :%u)' % code)
log.warning('Missing code to unpack (code :%u)' % code)
raise RuntimeError raise RuntimeError
else: else:
log = logging.getLogger('myLogger') logging.getLogger(LOGGER).warning('Unpacking an action with unknown code, skip it (%u)' % code)
log.warning('Unpacking an action with unknown code, skip it (%u)' % code)
if Reference: if Reference:
action.add_reference(Reference) action.add_reference(Reference)
if Name: if Name:

View file

@ -38,9 +38,9 @@ class CEntityEntry():
class CPropertyDecoder(): class CPropertyDecoder():
def __init__(self): def __init__(self):
# khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:2937 _PropertyDecoder.init (256); # khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:2937 _PropertyDecoder.init (256);
self.Entities = [CEntityEntry() for _ in range(0, 256)]
for i in range(0, 256): #for i in range(0, 256):
self.Entities[i] = CEntityEntry() # self.Entities[i] = CEntityEntry()
self._RefPosX = 0 self._RefPosX = 0
self._RefPosY = 0 self._RefPosY = 0
self._RefBitsX = 0 self._RefBitsX = 0

View file

@ -266,7 +266,6 @@ class TPeople(IntEnum):
EndPeople = 142 EndPeople = 142
class ECharacterTitle(IntEnum): class ECharacterTitle(IntEnum):
''' '''
khanat-opennel-code/code/ryzom/common/src/game_share/character_title.h # enum ECharacterTitle khanat-opennel-code/code/ryzom/common/src/game_share/character_title.h # enum ECharacterTitle
@ -646,3 +645,18 @@ class TPropIndex(IntEnum):
PROPERTY_OUTPOST_INFOS = 27, PROPERTY_OUTPOST_INFOS = 27,
NB_VISUAL_PROPERTIES = 28 NB_VISUAL_PROPERTIES = 28
class TPVPMode(IntEnum):
NONE = 0,
PvpDuel = 1,
PvpChallenge = 2,
PvpZoneFree = 4,
PvpZoneFaction = 8,
PvpZoneGuild = 16,
PvpZoneOutpost = 32,
PvpFaction = 64,
PvpFactionFlagged = 128,
PvpZoneSafe = 256,
PvpSafe = 512,
#Unknown = 513,
#NbModes = 513,
NbBits = 10 #// number of bits needed to store all valid values

252
tools/TVPNodeBase.py Normal file
View file

@ -0,0 +1,252 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# module BitStream
#
# Copyright (C) 2019 AleaJactaEst
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
#from ctypes import *
#import sys
#import inspect
#import copy
#import struct
#from tools import TPropIndex
from tools import Enum
#from tools import BitStream
from tools import CActionFactory
LOGGER='TVPNodeBase'
class TVPNodeBase():
def __init__(self, name=""):
# khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:414
self.VPParent = None # TVPNodeBase
self.VPA = None # TVPNodeBase
self.VPB = None # TVPNodeBase
self.PropIndex = Enum.TPropIndex.NB_VISUAL_PROPERTIES
self.BranchHasPayload = False
self.Name = name
self.NameProperty = ""
def setNodePropIndex(self, property , name_property = ""):
self.PropIndex = property
self.NameProperty = name_property
def makeChildren(self):
self.VPA = TVPNodeBase(self.Name + '.VPA')
self.VPA.VPParent = self
self.VPB = TVPNodeBase(self.Name + '.VPB')
self.VPB.VPParent = self
def makeDescendants(self, nbLevels ):
self.makeChildren()
if nbLevels > 1:
self.VPA.makeDescendants( nbLevels-1 );
self.VPB.makeDescendants( nbLevels-1 );
def build_tree(self):
# khanat-opennel-code/code/ryzom/common/src/game_share/entity_types.h:458 uint buildTree()
self.makeChildren()
self.VPA.setNodePropIndex(Enum.TPropIndex.PROPERTY_POSITION, 'PROPERTY_POSITION')
self.VPB.makeChildren()
self.VPB.VPA.setNodePropIndex(Enum.TPropIndex.PROPERTY_ORIENTATION, 'PROPERTY_ORIENTATION')
self.VPB.VPB.makeDescendants( 3 ) # 8 leaves + those created by additional makeChildren()
self.VPB.VPB.VPA.VPA.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_SHEET, 'PROPERTY_SHEET');
self.VPB.VPB.VPA.VPA.VPB.makeChildren();
self.VPB.VPB.VPA.VPA.VPB.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_BEHAVIOUR, 'PROPERTY_BEHAVIOUR');
self.VPB.VPB.VPA.VPA.VPB.VPB.setNodePropIndex( Enum.TPropIndex.PROPERTY_OWNER_PEOPLE, 'PROPERTY_OWNER_PEOPLE');
self.VPB.VPB.VPA.VPB.VPA.makeChildren();
self.VPB.VPB.VPA.VPB.VPA.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_NAME_STRING_ID, 'PROPERTY_NAME_STRING_ID');
self.VPB.VPB.VPA.VPB.VPA.VPB.setNodePropIndex( Enum.TPropIndex.PROPERTY_CONTEXTUAL, 'PROPERTY_CONTEXTUAL');
self.VPB.VPB.VPA.VPB.VPB.makeChildren();
self.VPB.VPB.VPA.VPB.VPB.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_TARGET_LIST, 'PROPERTY_TARGET_LIST');
self.VPB.VPB.VPA.VPB.VPB.VPB.setNodePropIndex( Enum.TPropIndex.PROPERTY_TARGET_ID, 'PROPERTY_TARGET_ID');
self.VPB.VPB.VPB.VPA.VPA.makeChildren();
self.VPB.VPB.VPB.VPA.VPA.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_MODE, 'PROPERTY_MODE');
self.VPB.VPB.VPB.VPA.VPA.VPB.setNodePropIndex( Enum.TPropIndex.PROPERTY_VPA, 'PROPERTY_VPA');
self.VPB.VPB.VPB.VPA.VPB.makeChildren();
self.VPB.VPB.VPB.VPA.VPB.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_BARS, 'PROPERTY_BARS');
self.VPB.VPB.VPB.VPA.VPB.VPB.setNodePropIndex( Enum.TPropIndex.PROPERTY_VISUAL_FX, 'PROPERTY_VISUAL_FX');
self.VPB.VPB.VPB.VPB.VPA.makeChildren();
self.VPB.VPB.VPB.VPB.VPA.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_VPB, 'PROPERTY_VPB');
self.VPB.VPB.VPB.VPB.VPA.VPB.makeChildren();
self.VPB.VPB.VPB.VPB.VPA.VPB.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_VPC, 'PROPERTY_VPC');
self.VPB.VPB.VPB.VPB.VPA.VPB.VPB.makeChildren();
self.VPB.VPB.VPB.VPB.VPA.VPB.VPB.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_EVENT_FACTION_ID, 'PROPERTY_EVENT_FACTION_ID');
self.VPB.VPB.VPB.VPB.VPA.VPB.VPB.VPB.makeChildren();
self.VPB.VPB.VPB.VPB.VPA.VPB.VPB.VPB.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_PVP_MODE, 'PROPERTY_PVP_MODE');
self.VPB.VPB.VPB.VPB.VPA.VPB.VPB.VPB.VPB.setNodePropIndex( Enum.TPropIndex.PROPERTY_PVP_CLAN, 'PROPERTY_PVP_CLAN');
self.VPB.VPB.VPB.VPB.VPB.makeChildren();
self.VPB.VPB.VPB.VPB.VPB.VPA.makeChildren();
self.VPB.VPB.VPB.VPB.VPB.VPA.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_ENTITY_MOUNTED_ID, 'PROPERTY_ENTITY_MOUNTED_ID');
self.VPB.VPB.VPB.VPB.VPB.VPA.VPB.setNodePropIndex( Enum.TPropIndex.PROPERTY_RIDER_ENTITY_ID, 'PROPERTY_RIDER_ENTITY_ID');
self.VPB.VPB.VPB.VPB.VPB.VPB.makeChildren();
self.VPB.VPB.VPB.VPB.VPB.VPB.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_OUTPOST_INFOS, 'PROPERTY_OUTPOST_INFOS');
self.VPB.VPB.VPB.VPB.VPB.VPB.VPB.makeChildren();
self.VPB.VPB.VPB.VPB.VPB.VPB.VPB.VPA.setNodePropIndex( Enum.TPropIndex.PROPERTY_GUILD_SYMBOL, 'PROPERTY_GUILD_SYMBOL');
self.VPB.VPB.VPB.VPB.VPB.VPB.VPB.VPB.setNodePropIndex( Enum.TPropIndex.PROPERTY_GUILD_NAME_ID, 'PROPERTY_GUILD_NAME_ID');
# TVPNodeBase *getPOSITIONnode() { return VPA; }
# TVPNodeBase *getORIENTATIONnode() { return VPB->VPA; }
#
# // From the discrete root (mainroot->VPB->VPB)
# TVPNodeBase *getSHEETnode() { return VPA->VPA->VPA; }
# TVPNodeBase *getBEHAVIOURnode() { return VPA->VPA->VPB->VPA; }
# TVPNodeBase *getOWNER_PEOPLEnode() { return VPA->VPA->VPB->VPB; }
# TVPNodeBase *getNAME_STRING_IDnode() { return VPA->VPB->VPA->VPA; }
# TVPNodeBase *getCONTEXTUALnode() { return VPA->VPB->VPA->VPB; }
# TVPNodeBase *getTARGET_LISTnode() { return VPA->VPB->VPB->VPA; }
# TVPNodeBase *getTARGET_IDnode() { return VPA->VPB->VPB->VPB; }
# TVPNodeBase *getMODEnode() { return VPB->VPA->VPA->VPA; }
# TVPNodeBase *getVPAnode() { return VPB->VPA->VPA->VPB; }
# TVPNodeBase *getBARSnode() { return VPB->VPA->VPB->VPA; }
# TVPNodeBase *getVISUAL_FXnode() { return VPB->VPA->VPB->VPB; }
# TVPNodeBase *getVPBnode() { return VPB->VPB->VPA->VPA; }
# TVPNodeBase *getVPCnode() { return VPB->VPB->VPA->VPB->VPA; }
# TVPNodeBase *getEVENT_FACTION_IDnode() { return VPB->VPB->VPA->VPB->VPB->VPA; }
# TVPNodeBase *getPVP_MODEnode() { return VPB->VPB->VPA->VPB->VPB->VPB->VPA; }
# TVPNodeBase *getPVP_CLANnode() { return VPB->VPB->VPA->VPB->VPB->VPB->VPB; }
# TVPNodeBase *getENTITY_MOUNTED_IDnode() { return VPB->VPB->VPB->VPA->VPA; }
# TVPNodeBase *getRIDER_ENTITY_IDnode() { return VPB->VPB->VPB->VPA->VPB; }
# TVPNodeBase *getOUTPOST_INFOSnode() { return VPB->VPB->VPB->VPB->VPA; }
# TVPNodeBase *getGUILD_SYMBOLnode() { return VPB->VPB->VPB->VPB->VPB->VPA; }
# TVPNodeBase *getGUILD_NAME_IDnode() { return VPB->VPB->VPB->VPB->VPB->VPB; }
#uint buildTree()
# {
# makeChildren();
# setNodePropIndex( POSITION );
# VPB->makeChildren();
# setNodePropIndex( ORIENTATION );
#
# TVPNodeBase *discreetRoot = VPB->VPB;
# discreetRoot->makeDescendants( 3 ); // 8 leaves + those created by additional makeChildren()
# discreetRoot->setNodePropIndex( SHEET );
# discreetRoot->VPA->VPA->VPB->makeChildren();
# discreetRoot->setNodePropIndex( BEHAVIOUR );
# discreetRoot->setNodePropIndex( OWNER_PEOPLE );
# discreetRoot->VPA->VPB->VPA->makeChildren();
# discreetRoot->setNodePropIndex( NAME_STRING_ID );
# discreetRoot->setNodePropIndex( CONTEXTUAL );
# discreetRoot->VPA->VPB->VPB->makeChildren();
# discreetRoot->setNodePropIndex( TARGET_LIST );
# discreetRoot->setNodePropIndex( TARGET_ID );
# discreetRoot->VPB->VPA->VPA->makeChildren();
# discreetRoot->setNodePropIndex( MODE );
# discreetRoot->setNodePropIndex( VPA );
# discreetRoot->VPB->VPA->VPB->makeChildren();
# discreetRoot->setNodePropIndex( BARS );
# discreetRoot->setNodePropIndex( VISUAL_FX );
# discreetRoot->VPB->VPB->VPA->makeChildren();
# discreetRoot->setNodePropIndex( VPB );
# discreetRoot->VPB->VPB->VPA->VPB->makeChildren();
# discreetRoot->setNodePropIndex( VPC );
# discreetRoot->VPB->VPB->VPA->VPB->VPB->makeChildren();
# discreetRoot->setNodePropIndex( EVENT_FACTION_ID );
# discreetRoot->VPB->VPB->VPA->VPB->VPB->VPB->makeChildren();
# discreetRoot->setNodePropIndex( PVP_MODE );
# discreetRoot->setNodePropIndex( PVP_CLAN );
# discreetRoot->VPB->VPB->VPB->makeChildren();
# discreetRoot->VPB->VPB->VPB->VPA->makeChildren();
# discreetRoot->setNodePropIndex( ENTITY_MOUNTED_ID );
# discreetRoot->setNodePropIndex( RIDER_ENTITY_ID );
# discreetRoot->VPB->VPB->VPB->VPB->makeChildren();
# discreetRoot->setNodePropIndex( OUTPOST_INFOS );
# discreetRoot->VPB->VPB->VPB->VPB->VPB->makeChildren();
# discreetRoot->setNodePropIndex( GUILD_SYMBOL );
# discreetRoot->setNodePropIndex( GUILD_NAME_ID );
#
# return NB_VISUAL_PROPERTIES;
def isRoot(self):
# khanat-opennel-code/code/ryzom/common/src/game_share/entity_types.h:407 bool isRoot()
return self.VPParent == None
def isLeaf(self):
# khanat-opennel-code/code/ryzom/common/src/game_share/entity_types.h:410 bool isLeaf()
return self.PropIndex != Enum.TPropIndex.NB_VISUAL_PROPERTIES
def getLevel(self):
level = 0
node = self
while node != None:
level += 1
node = node.VPParent
return level
def decodeDiscreetProperty(self, msgin, propIndex, slot, world):
# khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1746 void CNetworkConnection::decodeDiscreetProperty
logging.getLogger(LOGGER).debug("decodeDiscreetProperty")
action = None
if propIndex == Enum.TPropIndex.PROPERTY_TARGET_LIST:
logging.getLogger(LOGGER).debug("PROPERTY_TARGET_LIST")
listSize = msgin.readUint8("listSize")
logging.getLogger(LOGGER).debug("listSize:{0}".format(listSize))
# TargetSlotsList.resize(listSize);
if listSize > 0:
for i in range(0, listSize):
d1 = msgin.readUint8( "TargetSlots_{0}".format(i));
logging.getLogger(LOGGER).debug("data:{0}".format(d1))
# Update property
return []
logging.getLogger(LOGGER).debug("CActionFactory : {0}".format(slot))
action = CActionFactory.CActionFactory(world).createByPropIndex(slot, self.PropIndex, self.NameProperty)
logging.getLogger(LOGGER).debug("unpack: {0}".format(slot))
action.unpack(msgin)
if self.PropIndex == Enum.TPropIndex.PROPERTY_SHEET:
aliasBit = msgin.readBool("aliasBit")
logging.getLogger(LOGGER).debug("aliasBit:{0}".format(aliasBit))
if aliasBit:
alias = msgin.readUint32("alias");
logging.getLogger(LOGGER).debug("alias:{0}".format(alias))
elif self.PropIndex == Enum.TPropIndex.PROPERTY_MODE:
pass
else:
pass
logging.getLogger(LOGGER).debug("[decodeDiscreetProperty] (%s)" % (msgin.showAllData()))
return action
def decodeDiscreetProperties(self, clientid, msgin, slot, world):
# khanat-opennel-code/code/ryzom/client/src/network_connection.h:148 void decodeDiscreetProperties
logging.getLogger(LOGGER).debug("decodeDiscreetProperties " + self.Name)
self.BranchHasPayload = msgin.readBool("BranchHasPayload [{0}, NameProperty:{1}]".format(self.Name, self.NameProperty))
actions = []
if self.BranchHasPayload:
if self.isLeaf():
# SlotContext.NetworkConnection->decodeDiscreetProperty( msgin, PropIndex );
logging.getLogger(LOGGER).debug("isLeaf")
action = self.decodeDiscreetProperty(msgin, self.PropIndex, slot, world)
if action:
actions.append(action)
else:
if self.VPA:
tmp = self.VPA.decodeDiscreetProperties(clientid, msgin, slot, world)
for action in tmp:
actions.append(action)
if self.VPB:
tmp = self.VPB.decodeDiscreetProperties(clientid, msgin, slot, world)
for action in tmp:
actions.append(action)
return actions
def decodeDiscreetPropertiesVpbVpb(self, clientid, msgin, slot, world):
return self.VPB.VPB.decodeDiscreetProperties(clientid, msgin, slot, world)