Commit 3121a918 authored by aleajactaest's avatar aleajactaest

adding spy tools & update clientbot

parent 733000a0
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# module CActionFactory
#
# Copyright (C) 2019 AleaJactaEst
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from tools import Enum
from tools import CAction
LOGGER='CActionFactory'
class CActionFactory:
def __init__(self, world):
self.world = world
self.RegisteredAction = {}
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_POSITION_CODE, [])
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_GENERIC_CODE, [])
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_GENERIC_MULTI_PART_CODE, [])
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_SINT64, [])
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_SYNC_CODE, [])
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_DISCONNECTION_CODE, [])
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_ASSOCIATION_CODE, [])
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_LOGIN_CODE, [])
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_TARGET_SLOT_CODE, [])
self.RegisteredAction.setdefault(Enum.TActionCode.ACTION_DUMMY_CODE, [])
def createFactory(self, slot, code):
if code == Enum.TActionCode.ACTION_POSITION_CODE:
logging.getLogger(LOGGER).debug("Create CActionPosition")
return CAction.CActionPosition(slot, code, self.world)
elif code == Enum.TActionCode.ACTION_GENERIC_CODE:
logging.getLogger(LOGGER).debug("Create CActionGeneric")
return CAction.CActionGeneric(slot, code, self.world)
elif code == Enum.TActionCode.ACTION_GENERIC_MULTI_PART_CODE:
logging.getLogger(LOGGER).debug("Create CActionGenericMultiPart")
return CAction.CActionGenericMultiPart(slot, code, self.world)
elif code == Enum.TActionCode.ACTION_SINT64:
logging.getLogger(LOGGER).debug("Create CActionSint64")
return CAction.CActionSint64(slot, code, self.world)
elif code == Enum.TActionCode.ACTION_SYNC_CODE:
logging.getLogger(LOGGER).debug("Create CActionSync")
return CAction.CActionSync(slot, code, self.world)
elif code == Enum.TActionCode.ACTION_DISCONNECTION_CODE:
logging.getLogger(LOGGER).debug("Create CActionDisconnection")
return CAction.CActionDisconnection(slot, code, self.world)
elif code == Enum.TActionCode.ACTION_ASSOCIATION_CODE:
logging.getLogger(LOGGER).debug("Create CActionAssociation")
return CAction.CActionAssociation(slot, code, self.world)
elif code == Enum.TActionCode.ACTION_LOGIN_CODE:
logging.getLogger(LOGGER).debug("Create CActionLogin")
return CAction.CActionLogin(slot, code, self.world)
elif code == Enum.TActionCode.ACTION_TARGET_SLOT_CODE:
logging.getLogger(LOGGER).debug("Create CActionTargetSlot")
return CAction.CActionTargetSlot(slot, code, self.world)
elif code == Enum.TActionCode.ACTION_DUMMY_CODE:
logging.getLogger(LOGGER).debug("Create CActionDummy")
return CAction.CActionDummy(slot, code, self.world)
else:
logging.getLogger(LOGGER).warning('create() try to create an unknown action (%u)' % code)
raise RuntimeError
def create(self, slot, code):
if code not in self.RegisteredAction:
logging.getLogger(LOGGER).warning('try to create an unknown action (code:%u)' % code)
raise None
elif not self.RegisteredAction[code]:
logging.getLogger(LOGGER).debug('new CAction (code:%u)' % code)
action = self.createFactory(slot, code)
action.reset()
return action
else:
logging.getLogger(LOGGER).debug("update CAction")
action = self.RegisteredAction[code][-1]
action.reset()
action.PropertyCode = code
action.Slot = slot
return action
def unpack(self, msgin):
'''
khanat-opennel-code/code/ryzom/common/src/game_share/action_factory.cpp : CAction *CActionFactory::unpack (NLMISC::CBitMemStream &message, NLMISC::TGameCycle /* currentCycle */ )
'''
if msgin.needRead() >= 8:
shortcode = msgin.readBool('shortcode')
if shortcode:
code = msgin.readSerial(2, 'code')
else:
code = msgin.readUint8('code')
action = self.create(CAction.INVALID_SLOT, code)
if action:
try:
action.unpack (msgin);
except RuntimeError:
log = logging.getLogger('myLogger')
log.warning('Missing code to unpack (code :%u)' % code)
raise RuntimeError
else:
log = logging.getLogger('myLogger')
log.warning('Unpacking an action with unknown code, skip it (%u)' % code)
return action
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# module CArg
#
# Copyright (C) 2019 AleaJactaEst
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from ctypes import *
from tools import Enum
# #####################################################
# persistent_data.h:140 # struct CArg
# #####################################################
class CArgV1(Structure):
_fields_ = [("i32_1", c_uint),
("i32_2", c_uint)]
class CArgV2(Structure):
_fields_ = [("ex32_1", c_uint),
("ex32_2", c_uint)]
class CArgV3(Union):
_fields_ = [("ex32", CArgV2),
("ExData32", c_uint),
("ExData64", c_ulong)]
class CArgV4(Structure):
_fields_ = [("ExType", c_uint),
("ex", CArgV3)]
class CArgV5(Union):
_fields_ = [("i", CArgV1),
("ii32", c_int),
("ii64", c_long),
("i32", c_uint),
("i64", c_ulong),
("f32", c_float),
("f64", c_double),
("ex", CArgV4)]
class CArg:
# union
# {
# struct
# {
# uint32 i32_1;
# uint32 i32_2;
# } i;
#
# sint32 i32;
# sint64 i64;
# float f32;
# double f64;
#
# struct
# {
# uint32 ExType;
# union
# {
# struct
# {
# uint32 ex32_1;
# uint32 ex32_2;
# };
#
# uint32 ExData32;
# uint64 ExData64;
# } ex;
# } ex;
# } _Value;
def __init__(self):
self._value = CArgV5()
self._value.ii64 = 0
self._value.i64 = 0
self._type = 0
self._string = 0
self._type64 = False
def read_Type(self):
return self._type
def write_Type(self, value):
self._type = value
def write_Type64(self, value):
self._type64 = value
def read_String(self):
return self._string
def write_String(self, value):
self._string = value
def read_i32_1(self):
return self._value.i.i32_1
def write_i32_1(self, value):
self._value.i.i32_1 = value
def read_i32_2(self):
return self._value.i.i32_2
def write_i32_2(self, value):
self._value.i.i32_2 = value
def read_i32(self):
return self._value.i32
def write_i32(self, value):
self._value.i32 = value
def read_i64(self):
return self._value.i64
def write_i64(self, value):
self._value.i64 = value
def read_f32(self):
return self._value.f32
def write_f32(self, value):
self._value.f32 = value
def read_f64(self):
return self._value.f64
def write_f64(self, value):
self._value.f64 = value
def read_ExType(self):
return self._value.ex.ExType
def write_ExType(self, value):
self._value.ex.ExType = value
def read_ex32_1(self):
return self._value.ex.ex.ex32.ex32_1
def write_ex32_1(self, value):
self._value.ex.ex.ex32.ex32_1 = value
def read_ex32_2(self):
return self._value.ex.ex.ex32.ex32_2
def write_ex32_2(self, value):
self._value.ex.ex.ex32.ex32_2 = value
def read_ExData32(self):
return self._value.ex.ex.ExData32
def write_ExData32(self, value):
self._value.ex.ex.ExData32 = value
def read_ExData64(self):
return self._value.ex.ex.ExData64
def write_ExData64(self, value):
self._value.ex.ex.ExData64 = value
def isExtended(self):
if self._type == Enum.TType.EXTEND_TYPE:
return True
elif self._type == Enum.TType.STRUCT_BEGIN:
self.log.error("Can't extract a value from a structure delimiter")
sys.exit(2)
elif self._type == Enum.TType.STRUCT_END:
self.log.error("Can't extract a value from a structure delimiter")
sys.exit(2)
return False
def isFlag(self):
if self._type == Enum.TType.FLAG:
return True
else:
return False
def asUint(self):
if self._type == Enum.TType.STRUCT_BEGIN or self._type == Enum.TType.STRUCT_END:
self.log.error("Can't extract a value from a structure delimiter")
sys.exit(2)
elif self._type == Enum.TType.SINT32:
return self.read_i32()
elif self._type == Enum.TType.UINT32:
return self.read_i32()
elif self._type == Enum.TType.SINT64:
return self.read_i64()
elif self._type == Enum.TType.UINT64:
return self.read_i64()
elif self._type == Enum.TType.FLOAT32:
return self.read_i32()
elif self._type == Enum.TType.FLOAT64:
return self.read_i64()
elif self._type == Enum.TType.STRING:
return int(self._string)
elif self._type == Enum.TType.FLAG:
return "1"
elif self._type == Enum.TType.EXTEND_TYPE:
if self.read_ExType() == TExtendType.ET_SHEET_ID:
return self.read_ExData32()
elif self.read_ExType() == TExtendType.ET_ENTITY_ID:
return self.read_ExData64()
log = logging.getLogger('myLogger')
log.error("This should never happen!")
sys.exit(2)
def __str__(self):
log = logging.getLogger('myLogger')
log.debug(self._type)
if self._type == Enum.TType.STRUCT_BEGIN or self._type == Enum.TType.STRUCT_END:
return ''
elif self._type64:
# To be confirm for extend
return str(self.read_ExData64())
elif self._type == Enum.TType.SINT32:
return str(self.read_i32())
elif self._type == Enum.TType.UINT32:
return str(self.read_i32())
elif self._type == Enum.TType.SINT64:
return str(self.read_i64())
elif self._type == Enum.TType.UINT64:
return str(self.read_i64())
elif self._type == Enum.TType.FLOAT32:
return str(self.read_i32())
elif self._type == Enum.TType.FLOAT64:
return str(self.read_i64())
elif self._type == Enum.TType.STRING:
return self._string
elif self._type == Enum.TType.FLAG:
return "1"
return '?'
def asSint(self):
self.log.error("TODO")
sys.exit(2)
def asFloat(self):
self.log.error("TODO")
sys.exit(2)
def asDouble(self):
self.log.error("TODO")
sys.exit(2)
def asString(self):
if self._type == Enum.TType.STRUCT_BEGIN or self._type == Enum.TType.STRUCT_END:
self.log.error("Can't extract a value from a structure delimiter")
sys.exit(2)
elif self._type == Enum.TType.SINT32:
return str(self.read_ii32())
elif self._type == Enum.TType.UINT32:
return str(self.read_i32())
elif self._type == Enum.TType.SINT64:
return str(self.read_ii64())
elif self._type == Enum.TType.UINT64:
return str(self.read_i64())
elif self._type == Enum.TType.FLOAT32:
return str(self.read_f32())
elif self._type == Enum.TType.FLOAT64:
return str(self.read_f64())
elif self._type == Enum.TType.STRING:
return self._string
elif self._type == Enum.TType.FLAG:
return "1"
elif self._type == Enum.TType.EXTEND_TYPE:
self.log.error("TODO")
sys.exit(2)
# switch(_Value.ExType)
# {
# case ET_SHEET_ID:
# {
# NLMISC::CSheetId sheetId(_Value.ExData32);
# return sheetId.toString(true);
# }
# case ET_ENTITY_ID:
# {
# NLMISC::CEntityId entityId(_Value.ExData64);
# return entityId.toString();
# }
# default:
# break;
# }
self.log.error("This should never happen!")
sys.exit(2)
def asUCString(self):
self.log.error("TODO")
sys.exit(2)
def asEntityId(self):
self.log.error("TODO")
sys.exit(2)
def asSheetId(self):
self.log.error("TODO")
sys.exit(2)
def typeName(self):
self.log.error("TODO")
sys.exit(2)
# #####################################################
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# module CBNPCategorySet
#
# Copyright (C) 2019 AleaJactaEst
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class CBNPCategorySet:
def __init__(self):
self._Name = ""
self._IsOptional = False
self._UnpackTo = ""
self._IsIncremental = False
self._CatRequired = ""
self._Hidden = False
self._Files = []
def __str__(self):
return self._Name + ' (IsOptional:' + str(self._IsOptional) + ', UnpackTo:' + self._UnpackTo + ', IsIncremental:' + str(self._IsIncremental) + ', CatRequired:' + self._CatRequired + ', Hidden:' + str(self._Hidden) + ', Files:' + str(self._Files) + ')'
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# module CBNPFile
#
# Copyright (C) 2019 AleaJactaEst
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class CBNPFile:
def __init__(self):
self.FileName = None
self.Versions = []
self.IsIncremental = False
def __str__(self):
return str(self.FileName) +' (' + ', '.join( [str(x) for x in self.Versions]) + ')'
def update(self, FileName):
self.FileName = FileName
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# module CBNPFileVersion
#
# Copyright (C) 2019 AleaJactaEst
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class CBNPFileVersion:
def __init__(self):
self.VersionNumber = None
self.FileTime = None
self.FileSize = None
self.v7ZFileSize = None
self.PatchSize = None
self.HashKey = []
def __str__(self):
return "VersionNumber:" + str(self.VersionNumber) + ", FileTime:" + str(self.FileTime) + ", FileSize:" + str(self.FileSize) + ", 7ZFileSize:" + str(self.v7ZFileSize) + ", PatchSize:" + str(self.PatchSize) + ", HashKey:" + str(self.HashKey)
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# module CBitSet
#
# Copyright (C) 2019 AleaJactaEst
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class CBitSet:
def __init__(self, NL_BITLEN=32):
self.NumBits = 0
self.MaskLast = 0
self.NL_BITLEN = NL_BITLEN
self.data = self.resize(1024)
def resize(self, numBits):
self.data = [ 0 for _ in range(0, (numBits + self.NL_BITLEN - 1) // self.NL_BITLEN) ]
self.NumBits = numBits
nLastBits = self.NumBits & (self.NL_BITLEN-1)
if nLastBits == 0:
self.MaskLast = ~0
else:
self.MaskLast = (1 << nLastBits)-1
self.clearAll()
def clearData(self):
self.data = []
self.NumBits = 0
self.MaskLast = 0
def clearAll(self):
for i in range(0, len(self.data)):
self.data[i] = 0
def set(self, bitNumber, value):
#logging.getLogger('myLogger').debug("CBitSet::set %d %s" % (bitNumber, str(value)))
mask = bitNumber & (self.NL_BITLEN-1)
mask = 1 << mask
if value:
self.data[bitNumber >> 5] |= mask
else:
self.data[bitNumber >> 5] &= ~mask
def get(self, bitNumber):
mask= bitNumber&(self.NL_BITLEN-1);
mask= 1<<mask;
return self.data[bitNumber >> 5] & mask != 0
def setBit(self, bitNumber):
self.set(bitNumber, True)
def clearBit(self, bitNumber):
self.set(bitNumber, False)
def __str__(self):
return '.'.join([hex(x) for x in self.data])
def writeSerial(self, msgout):
# v = 0 # currentVersion
# if v >= 0xff:
# msgout.pushUint8(0xff)
# msgout.pushUint8(v)
# else:
# msgout.pushUint8(v)
#log = logging.getLogger('myLogger')
#log.debug("CBitSet::writeSerial NumBits:%d len:%d" % (self.NumBits, len(self.data)))
currentVersion = 0
msgout.pushUint8(currentVersion)
msgout.pushUint32(self.NumBits)
# il est lié à 'self.NumBits' dommage que l'on envoie celui-la
msgout.pushUint32(len(self.data))
for x in self.data:
msgout.pushUint32(x)