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.:
# 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 -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
# pip install pypcapfile
@ -47,6 +52,7 @@ from tools import CImpulseDecoder
from tools import CAction
from tools import Impulse
from tools import CPropertyDecoder
from tools import TVPNodeBase
import xml.etree.ElementTree as ET
from datetime import datetime
@ -195,56 +201,111 @@ class SpyPcap():
def add_registered_action(self, clientid, action):
self.client_state[clientid]['RegisteredAction'].setdefault(action.Code, [])
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):
"""
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1512 void CNetworkConnection::decodeVisualProperties( CBitMemStream& msgin )
"""
actions = []
properties = []
try:
while True:
property = {}
# if ( msgin.getPosInBit() + (sizeof(TCLEntityId)*8) > msgin.length()*8 ) return
if msgin.sizeRead() + (8*8 ) > msgin.sizeData() * 8:
return
# if msgin.sizeRead() + (8*8 ) > msgin.sizeData() * 8:
#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")
property['slot'] = slot
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'] .isUsed( 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")
if timestampIsThere:
timestampDelta = msgin.readSerial(4, "timestampDelta")
timestamp = self.client_state[clientid]['CurrentReceivedNumber'] - timestampDelta
logging.getLogger(LOGGER).debug("timestamp:{0} (timestampDelta:{1})".format(timestamp, timestampDelta))
else:
timestamp = self.client_state[clientid]['CurrentReceivedNumber']
logging.getLogger(LOGGER).debug("timestamp:{0}".format(timestamp))
property['timestamp'] = timestamp
property.setdefault('Actions', [])
# Tree
# currentNode->a()
BranchHasPayload = msgin.readBool("BranchHasPayload")
BranchHasPayload = msgin.readBool("BranchHasPayload [_VisualPropertyTreeRoot.VPA]")
logging.getLogger(LOGGER).debug("_VisualPropertyTreeRoot.VPA->BranchHasPayload:{0}".format(BranchHasPayload))
if BranchHasPayload:
# _PropertyDecoder.receive( _CurrentReceivedNumber, ap );
# Create a new action
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)
cActionPosition.unpack(msgin)
actions.append(cActionPosition)
property['Actions'] .append(cActionPosition)
# currentNode->b()
BranchHasPayload = msgin.readBool("BranchHasPayload")
BranchHasPayload = msgin.readBool("BranchHasPayload [_VisualPropertyTreeRoot.VPB]")
logging.getLogger(LOGGER).debug("_VisualPropertyTreeRoot.VPB->BranchHasPayload:{0}".format(BranchHasPayload))
if BranchHasPayload:
# 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
cActionOrientation= CAction.CActionSint64(slot, self.client_state[clientid]['world'])
cActionOrientation.PropertyCode = Enum.TPropIndex.PROPERTY_ORIENTATION
cActionOrientation= CAction.CActionSint64(slot, Enum.TPropIndex.PROPERTY_ORIENTATION, self.client_state[clientid]['world'])
cActionOrientation.setNbBits(Enum.TPropIndex.PROPERTY_ORIENTATION, 'PROPERTY_ORIENTATION')
cActionOrientation.set_name('PROPERTY_ORIENTATION')
cActionOrientation.unpack(msgin)
#self.client_state[clientid]['PropertyDecoder'] .receive(cActionPosition)
actions.append(cActionOrientation)
property['Actions'] .append(cActionOrientation)
# 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:
# Detect end of stream (little hard to close)
pass
return properties
def decode_server(self, clientid, msgin, receivedPacket, receivedAck, nextSentPacket=0):
"""
@ -282,7 +343,12 @@ class SpyPcap():
pass
num += 1
#actionFactory = CAction.CActionFactory(None)
logging.getLogger(LOGGER).debug("[decode_server] (%s)" % (msgin.showAllData()))
try:
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)
#action = self._CActionFactory.unpack(msgin)
if keep:
@ -292,8 +358,8 @@ class SpyPcap():
logging.getLogger(LOGGER).debug("append Code:%s" % str(action.Code))
self.add_registered_action(clientid, action)
# khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1512 void CNetworkConnection::decodeVisualProperties( CBitMemStream& msgin )
self.decodeVisualProperties(clientid, msgin)
return actions
properties = self.decodeVisualProperties(clientid, msgin)
return actions, properties
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):
target = "%s_%s" % (Source, Parent[7:])
actions = []
properties = []
impulses = []
databases = []
CurrentSendNumber = msgin.readSint32('CurrentSendNumber')
@ -439,7 +506,7 @@ class SpyPcap():
if not SystemMode:
_LastReceivedAck = msgin.readSint32('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:
logging.getLogger(LOGGER).debug('list actions: [' + str(len(actions)) + '] ' +','.join( [ str(x) for x in actions] ) )
else:
@ -624,7 +691,7 @@ class SpyPcap():
#cActionFactory.unpack(msgin)
logging.getLogger(LOGGER).debug("[Server -> Client] msg:%s" % msgin.showAllData())
#logging.getLogger(LOGGER).info("impulses:%s" % str(impulses))
return actions, impulses, databases
return actions, impulses, databases, properties
def read(self):
file = open( self.pcap_file , 'rb')
@ -659,6 +726,7 @@ class SpyPcap():
actions_servers = []
impulses_servers = []
impulses_clients = []
properties_servers = []
if self.show_raw_packet:
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"),
@ -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):
_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()))
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:
_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()))
@ -802,6 +870,29 @@ class SpyPcap():
id += 1
#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:
self.outyaml.write("\nblock_%s_%d:\n" %(list_host[src], sequenceid))
@ -834,6 +925,8 @@ class SpyPcap():
# params = Impulse.get_parameter()
# self.outyaml.write(" %s:\n" % (Impulse.get_name()))
# id += 1
#if Reference == 'packet_409':
# raise "STOP"
sequenceid += 1
sequencenum += 1
for client in self.client_state:
@ -853,9 +946,10 @@ def main():
#logger.append(logging.getLogger(CAction.LOGGER))
#logger.append(logging.getLogger(CActionFactory.LOGGER))
# logger.append(logging.getLogger(BitStream.LOGGER))
logger.append(logging.getLogger(DecodeDatabase.LOGGER))
logger.append(logging.getLogger(Impulse.LOGGER))
CImpulseDecoder
#logger.append(logging.getLogger(DecodeDatabase.LOGGER))
#logger.append(logging.getLogger(Impulse.LOGGER))
#logger.append(logging.getLogger(TVPNodeBase.LOGGER))
# CImpulseDecoder
# logger.append(logging.getLogger('CGenericMultiPartTemp'))
parser = argparse.ArgumentParser()

View file

@ -125,6 +125,20 @@ class BitStream():
name = name.strip().split(' ')[0].strip()
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):
p1 = self._pos
if value:
@ -553,6 +567,22 @@ class BitStream():
self._groupRead.append((v1, v1+nbits, name, typeName, 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):
v1 = self._read
v = self.readSerial(1, name=name, decode=False, typeName='Bool')

View file

@ -27,6 +27,32 @@ from tools import Enum
LOGGER='CActionFactory'
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:
def __init__(self, slot, code, world):
self.Code = code
@ -385,8 +411,10 @@ class CActionSint64(CAction):
def __init__(self, slot, code, world):
super().__init__(slot, code, world)
self.value = 0
self.NbBits = 0
self.PropertyToNbBit = { TPropIndex.TPropIndex.PROPERTY_ORIENTATION: 32,
self.NbBits = 64
self.NameProperty = 'None'
self.PropertyToNbBit = {
TPropIndex.TPropIndex.PROPERTY_ORIENTATION: 32,
TPropIndex.TPropIndex.PROPERTY_SHEET: 52,
TPropIndex.TPropIndex.PROPERTY_BEHAVIOUR: 48,
TPropIndex.TPropIndex.PROPERTY_NAME_STRING_ID: 32,
@ -418,22 +446,31 @@ class CActionSint64(CAction):
return "CActionSint64" + super().__str__()
def unpack(self, msgin):
logging.getLogger(LOGGER).debug("nb bit:{0}".format(self.NbBits))
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())
#self.NbBits = msgin.readUint32('NbBits')
logging.getLogger(LOGGER).debug("value:%u" % self.value)
logging.getLogger(LOGGER).debug("msgin:%s" % msgin.showAllData())
def pack(self, msgout):
super().pack(msgout)
msgout.pushUint64(self.value)
#msgout.pushUint64(self.value)
msgout.pushSerial64(self.value, self.NbBits)
#msgout.pushUint32(self.NbBits)
def reset(self):
self.value = 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:

View file

@ -91,6 +91,18 @@ class CActionFactory:
action.Slot = slot
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):
'''
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:
action.unpack (msgin);
except RuntimeError:
log = logging.getLogger('myLogger')
log.warning('Missing code to unpack (code :%u)' % code)
logging.getLogger(LOGGER).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)
logging.getLogger(LOGGER).warning('Unpacking an action with unknown code, skip it (%u)' % code)
if Reference:
action.add_reference(Reference)
if Name:

View file

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

View file

@ -266,7 +266,6 @@ class TPeople(IntEnum):
EndPeople = 142
class ECharacterTitle(IntEnum):
'''
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,
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)