diff --git a/tools/CPropertyDecoder.py b/tools/CPropertyDecoder.py new file mode 100644 index 0000000..32a2caf --- /dev/null +++ b/tools/CPropertyDecoder.py @@ -0,0 +1,101 @@ +#!/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 . + +#import logging +#from ctypes import * +#import sys +#import inspect +#import copy +#import struct + +LOGGER='CPropertyDecoder' + +class CEntityEntry(): + def __init__(self): + self.Sheet = 0 + self.AssociationBits = 0 + self.EntryUsed = False + self.PosIsRelative = False + self.PosIsInterior = False + +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._RefPosX = 0 + self._RefPosY = 0 + self._RefBitsX = 0 + self._RefBitsY = 0 + self._RefBitsZ = 0 + + def GetAssociationBits(self, slot): + return self.Entities[slot].AssociationBits + + def clear(self): + for i in range(0, 256): + self.Entities[i] = CEntityEntry() + + def associationBitsHaveChanged(self, slot, _associationBits): + res = _associationBits != self.GetAssociationBits(slot) + self.Entities[slot].AssociationBits = _associationBits + return res + + def addEntity(self, entity, sheet): + self.Entities[entity].EntryUsed = True + self.Entities[entity].Sheet = sheet + + def removeEntity(self, entity): + if self.Entities[entity].EntryUsed: + self.Entities[entity].EntryUsed = False + self.Entities[entity].Sheet = 0xffff + + def isUsed(self, slot): + return self.Entities[slot].EntryUsed + + def getSheet(self, slot): + return self.Entities[slot].Sheet + + def decodeAbsPos2D(self, x16, y16): + x = self._RefPosX + (x16 - self._RefBitsX) << 4 + y = self._RefPosY + (y16 - self._RefBitsY) << 4 + + return (x, y) + + def receive(self, actionPosition): + # if (action->Code == ACTION_POSITION_CODE) # normally is always this type + if actionPosition.IsRelative: + # Relative position (entity in a ferry...) + actionPosition.Position[0] = actionPosition.Position16[0] + actionPosition.Position[1] = actionPosition.Position16[1] + actionPosition.Position[2] = actionPosition.Position16[2] + self.Entities[actionPosition.Slot].PosIsRelative = True + self.Entities[actionPosition.Slot].PosIsInterior = False + else: + # Absolute position + # actionPosition.Position[0] , actionPosition.Position[1] = self.decodeAbsPos2D(actionPosition.Position16[0], actionPosition.Position16[1]) + actionPosition.Position[0] = self._RefPosX + (actionPosition.Position16[0] - self._RefBitsX) << 4 + actionPosition.Position[1] = self._RefPosY + (actionPosition.Position16[1] - self._RefBitsY) << 4 + actionPosition.Position[2] = actionPosition.Position16[2] << 4 + if actionPosition.Interior: + actionPosition.Position[2] += 2 + self.Entities[actionPosition.Slot].PosIsRelative = False + self.Entities[actionPosition.Slot].PosIsInterior = actionPosition.Interior diff --git a/tools/DecodeDatabase.py b/tools/DecodeDatabase.py new file mode 100644 index 0000000..6152371 --- /dev/null +++ b/tools/DecodeDatabase.py @@ -0,0 +1,139 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# +# module DecodeDatabase +# +# 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 . + +import logging +from tools import getPowerOf2 + +LOGGER='DecodeDatabase' + +def show_dico(dico, level=1): + for ele in dico: + if isinstance(dico[ele], dict): + print("." * level, ele , ":") + if isinstance(dico[ele], dict): + show_dico(dico[ele], level+1) + else: + print("." * level, ele, ':', dico[ele]) + +def child(ele): + ret = {} + ret_branch = {} + ref_other = {} + id_branch = 0 + id_other = 0 + min_i = -1 + max_i = -1 + for k in ele.keys(): + ret[k] = ele.get(k) + print(k, ele.get(k)) + for _child in list(ele): + x = child(_child) + if x['name'] == 'branch': + ret_branch.setdefault(id_branch, x) + id_branch += 1 + else: + ref_other.setdefault(id_other, x) + id_other += 1 + if ret_branch or ref_other: + ret['child'] = {} + id = 0 + for x in ret_branch: + min_i = max_i + 1 + max_i = min_i + #show_dico( ret_branch[x]) + if 'count' in ret_branch[x]: + max_i = min_i + int(ret_branch[x]['count']) - 1 + ret_branch[x]['min'] = min_i + ret_branch[x]['max'] = max_i + ret['child'].setdefault(id, ret_branch[x]) + id += 1 + for x in ref_other: + min_i = max_i + 1 + max_i = min_i + #show_dico( ref_other[x]) + if 'count' in ref_other[x]: + max_i = min_i + int(ref_other[x]['count']) - 1 + ref_other[x]['min'] = min_i + ref_other[x]['max'] = max_i + ret['child'].setdefault(id, ref_other[x]) + id += 1 + return ret + +def count_elements(head): + try: + return head.items()[-1]['max'] + 1 + except TypeError: + return len(head) + +def get_element(head, id): + print("id:", id) + for ele in head: + if id <= head[ele]['max'] and id >= head[ele]['min']: + return head[ele] + return None + +class DecodeDatabase(): + def __init__(self): + self.databaseXml = None + self.databasePlr = None + + def loadDatabase(self, databaseXml): + logging.getLogger(LOGGER).debug("loadDatabase") + self.databaseXml = databaseXml + id = 0 + self.databasePlr = {} + for ele in self.databaseXml: + if ele.tag == 'branch': + if ele.get('bank') == "PLR": + self.databasePlr[id] = child(ele) + self.databasePlr[id]['min'] = id + self.databasePlr[id]['max'] = id + id += 1 + print(dir(ele)) + print("-" * 80) + show_dico(self.databasePlr) + print("-" * 80) + #raise "Decode" + + def execute(self, msgin, world): + logging.getLogger(LOGGER).debug("execute") + head = self.databasePlr + listpath = [] + while True: + logging.getLogger(LOGGER).debug("count_elements:" + str(count_elements(head))) + nbBit = getPowerOf2.getPowerOf2(count_elements(head)) + logging.getLogger(LOGGER).debug("nbBit:" + str(nbBit)) + id = msgin.readSerial(nbBit, name='DatabaseXML', typeName='Number', emulate=True) + + logging.getLogger(LOGGER).debug("XML DECODE : %3d -> %s" % (nbBit, ':'.join(listpath)) ) + ele = get_element(head, id) + print(ele) + show_dico(ele) + name = ele['name'] + listpath.append(name) + fullname = ':'.join(listpath) + logging.getLogger(LOGGER).debug(fullname) + if 'type' in ele: + print("+"*80) + return True + head = ele + print("-"*80) + return False +