Commit 3121a918 authored by aleajactaest's avatar aleajactaest
Browse files

adding spy tools & update clientbot

parent 733000a0
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/>.
#from tools import Enum
import logging
from tools import TPropIndex
from tools import TPVPMode
LOGGER='CActionFactory'
INVALID_SLOT = 0xff
class CAction:
def __init__(self, slot, code, world):
self.Code = code
self.PropertyCode = code
self.Slot = slot
self._Priority = 1
self.Timeout = 0
self.GameCycle = 0
self.world = world
def unpack(self, message):
raise RuntimeError
def pack(self, msgout):
if self.Code < 4:
modeShort = True
msgout.pushBool(modeShort)
code = self.Code
msgout.internalSerial(self.Code, 2)
else:
modeShort = False
msgout.pushBool(modeShort)
code = self.Code
msgout.pushUint8(code)
def serialIn(self, msgin):
raise RuntimeError
def serialOut(self, msgout):
raise RuntimeError
def size(self):
headerBitSize = 0
if self.Code < 4:
headerBitSize = 1 + 2
else:
headerBitSize = 1 + (1 * 8)
return headerBitSize
def getMaxSizeInBit(self):
logging.getLogger(LOGGER).debug("New Object but missing method reset")
raise RuntimeError
def setPriority(self, prio):
logging.getLogger(LOGGER).debug("New Object but missing method reset")
raise RuntimeError
def priority(self):
logging.getLogger(LOGGER).debug("New Object but missing method reset")
raise RuntimeError
def getValue(self):
logging.getLogger(LOGGER).debug("New Object but missing method reset")
raise RuntimeError
def setValue(self, value):
logging.getLogger(LOGGER).debug("New Object but missing method reset")
raise RuntimeError
def isContinuous(self):
logging.getLogger(LOGGER).debug("New Object but missing method reset")
raise RuntimeError
def reset(self):
logging.getLogger(LOGGER).debug("New Object but missing method reset")
raise RuntimeError
def __str__(self):
return "[%d,%d]" % (self.Code , self.Slot)
class CActionPosition(CAction):
def __init__(self, slot, code, world):
super().__init__(slot, code, world)
self.Position = [0, 0, 0]
self.Position16 = [0, 0, 0]
self.IsRelative = False
self.Interior = False
def __str__(self):
return "CActionPosition" + super().__str__() + " x:" + str(self.Position16[0]) + " y:" + str(self.Position16[1]) + " z:" + str(self.Position16[2]) + " IsRelative:" + str(self.IsRelative) + " Interior:" + str(self.Interior)
def unpack(self, message):
self.Position16[0] = message.readUint16('px')
self.Position16[1] = message.readUint16('py')
self.Position16[2] = message.readUint16('pz')
self.IsRelative = (self.Position16[2] & 0x1) != 0
self.Interior = (self.Position16[2] & 0x2) != 0
# message.serialAndLog1( Position16[0] );
# message.serialAndLog1( Position16[1] );
# message.serialAndLog1( Position16[2] );
# IsRelative = (Position16[2] & (uint16)0x1)!=0;
# Interior = (Position16[2] & (uint16)0x2)!=0;
def reset(self):
pass
class CActionSync(CAction):
def __init__(self, slot, code, world):
super().__init__(slot, code, world)
def __str__(self):
return "CActionSync" + super().__str__()
class CActionDisconnection(CAction):
def __init__(self, slot, code, world):
super().__init__(slot, code, world)
def __str__(self):
return "CActionDisconnection" + super().__str__()
class CActionAssociation(CAction):
def __init__(self, slot, code, world):
super().__init__(slot, code, world)
def __str__(self):
return "CActionAssociation" + super().__str__()
class CActionDummy(CAction):
def __init__(self, slot, code, world):
super().__init__(slot, code, world)
def __str__(self):
return "CActionDummy" + super().__str__()
class CActionLogin(CAction):
def __init__(self, slot, code, world):
super().__init__(slot, code, world)
def __str__(self):
return "CActionLogin" + super().__str__()
class CActionTargetSlot(CAction):
def __init__(self, slot, code, world):
super().__init__(slot, code, world)
def __str__(self):
return "CActionTargetSlot" + super().__str__()
class CActionGeneric(CAction):
def __init__(self, slot, code, world):
super().__init__(slot, code, world)
self._Message = None
self.decoded = False
def set(self, message):
self._Message = message
def unpack(self, message):
size = message.readUint32('size')
self._Message = message.readBitStreamUint8(size, 'message')
def pack(self, msgout):
super().pack(msgout)
sizeMessage = len(self._Message)
msgout.pushUint32(sizeMessage)
msgout.pushBuffer(self._Message)
def reset(self):
self._Message = None
def genericAction(self, decodeImpulse, world, cGenericMultiPartTemp):
decodeImpulse.execute(self._Message, world)
self.decoded = True
def __str__(self):
if self.decoded:
return "CActionGeneric" + super().__str__() + ' => ' + self._Message.showAllData()
else:
return "CActionGeneric" + super().__str__() + "[read:" + self._Message.showAllData() + '/write:' + self._Message.showAllDataWrite() + ']'
def size(self):
size = super().size()
if self._Message:
return 4 + len(self._Message) * 8 + size
else:
return 4 + size
class CActionGenericMultiPart(CAction):
'''
khanat-opennel-code/code/ryzom/common/src/game_share/action_generic_multi_part.h # class CActionGenericMultiPart
'''
def __init__(self, slot, code, world):
super().__init__(slot, code, world)
self.PartCont = []
self.Number = 0
self.Part = 0
self.NbBlock = 0
def set(self, number, part, buffer, bytelen, size, nbBlock):
'''
khanat-opennel-code/code/ryzom/common/src/game_share/action_generic_multi_part.h # void set (uint8 number, uint16 part, const uint8 *buffer, uint32 bytelen, uint32 size, uint16 nbBlock)
'''
logging.getLogger(LOGGER).debug("number:%d part:%d bytelen:%d size:%d nbBlock:%d" %(number, part, bytelen, size, nbBlock))
start = part*size
end = start + size
logging.getLogger(LOGGER).debug("start:%d end:%d bytelen:%d" % (start, end, bytelen))
if end > bytelen:
end = bytelen
logging.getLogger(LOGGER).debug("start:%d end:%d" % (start, end))
self.PartCont = []
# memcpy( &PartCont[0], buffer + start, end - start );
for i in range(start, end):
logging.getLogger(LOGGER).debug("Append : %d/%d" % (i, len(buffer)))
self.PartCont.append(buffer[i])
self.Number = number
self.Part = part
self.NbBlock = nbBlock
def unpack(self, message):
self.Number = message.readUint8('Number')
self.Part = message.readUint16('Part')
self.NbBlock = message.readUint16('NbBlock')
size = message.readUint32('size')
self.PartCont = message.readBitStreamUint8(size, 'PartCont')
logging.getLogger(LOGGER).debug("unpack - Number:%d Part:%d NbBlock:%d" % (self.Number, self.Part, self.NbBlock))
def pack(self, msgout):
super().pack(msgout)
msgout.pushUint8(self.Number)
msgout.pushUint16(self.Part)
msgout.pushUint16(self.NbBlock)
msgout.pushArrayUint8(self.PartCont)
def reset(self):
self.PartCont = []
self.Number = 0
self.Part = 0
self.NbBlock = 0
def genericAction(self, decodeImpulse, world, cGenericMultiPartTemp):
'''
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp # void CNetworkConnection::genericAction (CActionGenericMultiPart *agmp)
'''
logging.getLogger(LOGGER).debug("Number:%d Part:%d NbBlock:%d" % (self.Number, self.Part, self.NbBlock))
cGenericMultiPartTemp.addGenericMultiPartTemp(self.Number)
cGenericMultiPartTemp.setGenericMultiPartTemp(self.Number, self.Part, self.NbBlock, self.PartCont, decodeImpulse, world)
def __str__(self):
return "CActionGenericMultiPart" + super().__str__() + "[" + str(self.Number) + ',' + str(self.Part) + ',' + str(self.NbBlock) + ',read:' + self.PartCont.showAllData() + ',write:' + self.PartCont.showAllDataWrite() + ']'
def size(self):
size = super().size()
bytesize = 1 + 2 + 2 + 4 # header
# self.PartCont
for ele in self.PartCont:
bytesize += len(ele)
return bytesize * 8 + size
class CActionSint64(CAction):
'''
khanat-opennel-code/code/ryzom/common/src/game_share/action_sint64.cpp
A lire :
/home/jerome/Projets/khanat/khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1311 receiveNormalMessage(CBitMemStream &msgin)
/home/jerome/Projets/khanat/khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1472 receiveNormalMessage(CBitMemStream &msgin)
'''
def __init__(self, slot, code, world):
super().__init__(slot, code, world)
self.value = 0
self.NbBits = 0
self.PropertyToNbBit = { TPropIndex.TPropIndex.PROPERTY_ORIENTATION: 32,
TPropIndex.TPropIndex.PROPERTY_SHEET: 52,
TPropIndex.TPropIndex.PROPERTY_BEHAVIOUR: 48,
TPropIndex.TPropIndex.PROPERTY_NAME_STRING_ID: 32,
TPropIndex.TPropIndex.PROPERTY_TARGET_ID: 8,
TPropIndex.TPropIndex.PROPERTY_MODE: 44,
TPropIndex.TPropIndex.PROPERTY_VPA: 64,
TPropIndex.TPropIndex.PROPERTY_VPB: 47,
TPropIndex.TPropIndex.PROPERTY_VPC: 58,
TPropIndex.TPropIndex.PROPERTY_ENTITY_MOUNTED_ID: 8 , # slot
TPropIndex.TPropIndex.PROPERTY_RIDER_ENTITY_ID: 8 , # slot
TPropIndex.TPropIndex.PROPERTY_CONTEXTUAL: 16 ,
TPropIndex.TPropIndex.PROPERTY_BARS: 32 , # please do not lower it (or tell Olivier: used for forage sources)
TPropIndex.TPropIndex.PROPERTY_TARGET_LIST: TPropIndex.USER_DEFINED_PROPERTY_NB_BITS ,
TPropIndex.TPropIndex.PROPERTY_VISUAL_FX: 11 , # please do not lower it (or tell Olivier: used for forage sources)
TPropIndex.TPropIndex.PROPERTY_GUILD_SYMBOL: 60 ,
TPropIndex.TPropIndex.PROPERTY_GUILD_NAME_ID: 32 ,
TPropIndex.TPropIndex.PROPERTY_EVENT_FACTION_ID: 32 ,
TPropIndex.TPropIndex.PROPERTY_PVP_MODE: TPVPMode.NbBits ,
TPropIndex.TPropIndex.PROPERTY_PVP_CLAN: 32 ,
TPropIndex.TPropIndex.PROPERTY_OWNER_PEOPLE: 3 , # 4 races and unknow
TPropIndex.TPropIndex.PROPERTY_OUTPOST_INFOS: 16 } # 15+1
def __str__(self):
return "CActionSint64" + super().__str__()
def unpack(self, msgin):
logging.getLogger(LOGGER).debug("msgin:%s" % msgin.showAllData())
self.value = msgin.readUint64('value')
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.pushUint32(self.NbBits)
def reset(self):
self.value = 0
self.NbBits = 0
class CActionBlock:
def __init__(self):
self.Cycle = 0
self.FirstPacket = 0
self.Actions = []
self.Success = True
def serial(self, msgout, actionFactory):
msgout.pushUint32(self.Cycle)
msgout.pushUint8(len(self.Actions))
for action in self.Actions:
# msgPosBefore = msgout.getPosInBit()
actionFactory.pack(action, msgout)
# msgPosAfter = msgout.getPosInBit()
# actionSize = actionFactory.size(action)
def writeSerial(self, msgout):
msgout.pushUint32(self.Cycle)
numberActions = len(self.Actions)
msgout.pushUint8(numberActions)
for action in self.Actions:
action.pack(msgout)
def insert(self, actions, begin, end):
for i in range(0, end):
if i>= begin:
self.Actions.append(actions[i])
def eraseToEnd(self, begin):
while len(self.Actions) >= begin:
self.Actions.pop()
def push_back(self, action):
self.Actions.append(action)
def __str__(self):
return "CActionBlock [Cycle:" + str(self.Cycle) + ', FirstPacket:' + str(self.FirstPacket) + ', Data:' + ', '.join([ str(x) for x in self.Actions]) + "]"
#!/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):