Add project files.

This commit is contained in:
k0t9i
2023-01-16 15:33:32 +04:00
parent 0f6fb75cff
commit 3c20df7683
130 changed files with 7756 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
#pragma once
#include "GameStructs.h"
class FNameInterface
{
public:
FNameInterface() = default;
virtual ~FNameInterface() = default;
virtual void Init(HMODULE hModule) = 0;
};

View File

@@ -0,0 +1,31 @@
#pragma once
#include <map>
#include <math.h>
#include <functional>
#include "GameStructs.h"
class FindObjectsTrait
{
public:
template <typename T>
std::map<uint32_t, T> GetAllObjects(float_t radius, std::function<const T(float_t, int32_t)> getNextObject) const
{
std::map<uint32_t, T> result;
auto object = getNextObject(radius, -1);
while (object)
{
if (result.find(object->objectId) != result.end()) {
break;
}
else {
result.emplace(object->objectId, object);
}
object = getNextObject(radius, object->objectId);
}
return result;
}
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <Windows.h>
class GameEngineInterface
{
public:
GameEngineInterface() = default;
virtual ~GameEngineInterface() = default;
virtual void Init(HMODULE hModule) = 0;
virtual void Restore() = 0;
};

View File

@@ -0,0 +1,184 @@
#pragma once
#include "pch.h"
namespace L2
{
enum class UserType : int32_t
{
NPC = 1,
USER = 0
};
enum class Race : int32_t
{
DARK_ELF = 2,
DWARF = 4,
ELF = 1,
HUMAN = 0,
ORC = 3
};
enum class Gender : int32_t
{
FEMALE = 1,
MALE = 0
};
enum class ItemSlot : int32_t
{
BABYPET = 4194304,
BACK = 8192,
CHEST = 1024,
DHAIR = 524288,
FACE = 262144,
FEET = 4096,
FULL_ARMOR = 32768,
GLOVES = 512,
HAIR = 65536,
HATCHLING = 1048576,
HEAD = 64,
L_EAR = 4,
L_FINGER = 32,
L_HAND = 256,
LEGS = 2048,
LR_HAND = 16384,
NECK = 8,
NONE = 0,
R_EAR = 2,
R_FINGER = 16,
LoR_EAR = L_EAR | R_EAR,
LoR_FINGER = L_FINGER | R_FINGER,
R_HAND = 128,
STRIDER = 2097152,
UNDERWEAR = 1,
WOLF = 131072
};
enum class ItemDataType : int32_t
{
ARMOR = 1,
ETC = 2,
WEAPON = 0
};
enum class ItemType2 : int16_t
{
ACCESSORY = 2,
MONEY = 4,
OTHER = 5,
PET_BABY = 9,
PET_HATCHLING = 7,
PET_STRIDER = 8,
PET_WOLF = 6,
QUEST = 3,
SHIELD_ARMOR = 1,
WEAPON = 0
};
enum class CrystalType : int32_t
{
A = 4,
B = 3,
C = 2,
D = 1,
NG = 0,
S = 5,
NONE = -1
};
enum class WeaponType : int32_t
{
BLUNT = 2,
BOW = 6,
DAGGER = 3,
DUALSWORD = 8,
ETC = 7,
FISHING_ROD = 10,
FIST = 5,
PET = 9,
POLE = 4,
SHIELD = 0,
SWORD = 1
};
enum class ArmorType : int32_t
{
NONE = 0,
HEAVY = 2,
LIGHT = 1,
ROBE = 3
};
class UserWear
{
public:
char pad_0000[4]; //0x0000
int32_t leftEarring; //0x0004
int32_t rightEarring; //0x0008
int32_t neclace; //0x000C
int32_t leftRing; //0x0010
int32_t rightRing; //0x0014
int32_t helmet; //0x0018
int32_t weapon; //0x001C
int32_t shield; //0x0020
int32_t gloves; //0x0024
int32_t breastplate; //0x0028
int32_t gaiters; //0x002C
int32_t boots; //0x0030
char pad_0034[64]; //0x0034
}; //Size: 0x0074
class FColor
{
public:
uint8_t r; //0x0000
uint8_t g; //0x0001
uint8_t b; //0x0002
uint8_t a; //0x0003
}; //Size: 0x0004
class FVector
{
public:
float x = 0; //0x0000
float y = 0; //0x0004
float z = 0; //0x0008
}; //Size: 0x000C
class FRotator
{
public:
int32_t Pitch; //0x0000
int32_t Yaw; //0x0004
int32_t Roll; //0x0008
}; //Size: 0x000C
#pragma pack(push, 1)
struct NetworkPacket
{
unsigned char id, _padding1, exid, _padding2;
unsigned short size, _padding3;
unsigned char* data;
};
#pragma pack(pop)
struct SystemMessagePacket : NetworkPacket
{
enum class Type
{
ALREADY_SPOILED = 357,
SPOIL_SUCCESS = 612,
};
const uint32_t GetMessageId() const
{
return ((uint32_t*)data)[0];
}
};
enum class NetworkPacketId
{
SYSTEM_MESSAGE = 0x64
};
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "GameStructs.h"
class L2GameDataInterface
{
public:
L2GameDataInterface() = default;
virtual ~L2GameDataInterface() = default;
virtual void Init(HMODULE hModule) = 0;
virtual void Restore() = 0;
};

View File

@@ -0,0 +1,13 @@
#pragma once
#include <Windows.h>
class NetworkHandlerInterface
{
public:
NetworkHandlerInterface() = default;
virtual ~NetworkHandlerInterface() = default;
virtual void Init(HMODULE hModule) = 0;
virtual void Restore() = 0;
};

View File

@@ -0,0 +1,93 @@
#pragma once
#include "../VersionAbstractFactory.h"
#include "Factories/HeroFactory.h"
#include "Factories/DropFactory.h"
#include "Factories/NPCFactory.h"
#include "Factories/PlayerFactory.h"
#include "Factories/SkillFactory.h"
#include "Repositories/HeroRepository.h"
#include "Repositories/DropRepository.h"
#include "Repositories/NPCRepository.h"
#include "Repositories/PlayerRepository.h"
#include "Repositories/SkillRepository.h"
#include "GameStructs/NetworkHandlerWrapper.h"
#include "GameStructs/GameEngineWrapper.h"
#include "GameStructs/L2GameDataWrapper.h"
#include "GameStructs/FName.h"
namespace Interlude
{
class AbstractFactory : public VersionAbstractFactory
{
public:
AbstractFactory(const uint16_t radius) :
m_Radius(radius)
{
}
AbstractFactory() = delete;
virtual ~AbstractFactory() = default;
HeroRepository& GetHeroRepository() const override
{
static auto factory = HeroFactory();
static auto result = HeroRepository(
GetNetworkHandler(),
factory
);
return result;
}
DropRepository& GetDropRepository() const override
{
static auto factory = DropFactory(GetL2GameData(), GetFName());
static auto result = DropRepository(
GetNetworkHandler(),
factory,
m_Radius
);
return result;
}
NPCRepository& GetNPCRepository() const override
{
static auto factory = NPCFactory();
static auto result = NPCRepository(GetNetworkHandler(), factory, m_Radius);
return result;
}
PlayerRepository& GetPlayerRepository() const override
{
static auto factory = PlayerFactory();
static auto result = PlayerRepository(GetNetworkHandler(), factory, m_Radius);
return result;
}
SkillRepository& GetSkillRepository() const override
{
static auto factory = SkillFactory(GetL2GameData(), GetFName());
static auto result = SkillRepository(GetNetworkHandler(), factory);
return result;
}
NetworkHandlerWrapper& GetNetworkHandler() const override
{
static NetworkHandlerWrapper result;
return result;
}
GameEngineWrapper& GetGameEngine() const override
{
static GameEngineWrapper result;
return result;
}
L2GameDataWrapper& GetL2GameData() const override
{
static L2GameDataWrapper result;
return result;
}
FName& GetFName() const override
{
static FName result;
return result;
}
private:
const uint16_t m_Radius;
};
}

View File

@@ -0,0 +1,50 @@
#pragma once
#include "../GameStructs/L2GameDataWrapper.h"
#include "../GameStructs/FName.h"
#include "../../../Common/Common.h"
namespace Interlude
{
class DropFactory
{
public:
DropFactory(const L2GameDataWrapper& l2GameData, const FName& fName) :
m_L2GameData(l2GameData),
m_FName(fName)
{
}
DropFactory() = delete;
virtual ~DropFactory() = default;
const DTO::Drop Create(const Item* item) const
{
const auto itemData = m_L2GameData.GetItemData(item->itemId);
const auto nameEntry = itemData ? m_FName.GetEntry(itemData->nameIndex) : nullptr;
const auto iconEntry = itemData ? m_FName.GetEntry(itemData->iconNameIndex) : nullptr;
return DTO::Drop{
item->objectId,
ValueObjects::Transform(
ValueObjects::Vector3(item->pawn->Location.x, item->pawn->Location.y, item->pawn->Location.z),
ValueObjects::Vector3(
static_cast<float_t>(item->pawn->Rotation.Pitch),
static_cast<float_t>(item->pawn->Rotation.Yaw),
static_cast<float_t>(item->pawn->Rotation.Roll)
),
ValueObjects::Vector3(item->pawn->Velocity.x, item->pawn->Velocity.y, item->pawn->Velocity.z),
ValueObjects::Vector3(item->pawn->Acceleration.x, item->pawn->Acceleration.y, item->pawn->Acceleration.z)
),
item->itemId,
item->amount,
nameEntry ? ConvertFromWideChar(nameEntry->value) : "",
iconEntry ? ConvertFromWideChar(iconEntry->value) : ""
};
}
private:
const L2GameDataWrapper& m_L2GameData;
const FName& m_FName;
};
}

View File

@@ -0,0 +1,86 @@
#pragma once
#include "../GameStructs/NetworkHandlerWrapper.h"
#include "../../../Common/Common.h"
namespace Interlude
{
class HeroFactory
{
public:
HeroFactory() = default;
virtual ~HeroFactory() = default;
const DTO::Hero Create(const User* item) const
{
const auto playerController = item->pawn ? item->pawn->lineagePlayerController : nullptr;
return DTO::Hero{
item->objectId,
ValueObjects::Transform(
ValueObjects::Vector3(item->pawn->Location.x, item->pawn->Location.y, item->pawn->Location.z),
ValueObjects::Vector3(
static_cast<float_t>(item->pawn->Rotation.Pitch),
static_cast<float_t>(item->pawn->Rotation.Yaw),
static_cast<float_t>(item->pawn->Rotation.Roll)
),
ValueObjects::Vector3(item->pawn->Velocity.x, item->pawn->Velocity.y, item->pawn->Velocity.z),
ValueObjects::Vector3(item->pawn->Acceleration.x, item->pawn->Acceleration.y, item->pawn->Acceleration.z)
),
ValueObjects::FullName(
ConvertFromWideChar(item->nickname),
ConvertFromWideChar(item->title)
),
ValueObjects::VitalStats(
item->maxHp, item->hp,
item->maxMp, item->mp,
item->maxCp, item->cp
),
ValueObjects::Phenotype(
(Enums::RaceEnum)item->raceId,
item->gender == L2::Gender::MALE,
(Enums::ClassEnum)item->classId,
(Enums::ClassEnum)item->activeClassId
),
ValueObjects::ExperienceInfo(
item->lvl,
item->exp,
item->sp
),
ValueObjects::PermanentStats(
item->str,
item->dex,
item->con,
item->int_,
item->men,
item->wit
),
ValueObjects::VariableStats(
item->accuracy,
item->critRate,
item->pAttack,
item->attackSpeed,
item->pDefense,
item->evasion,
item->mAttack,
item->mDefense,
item->castingSpeed
),
ValueObjects::Reputation(
item->karma,
item->pkKills,
item->pvpKills,
static_cast<uint8_t>(item->recRemaining),
static_cast<uint8_t>(item->evalScore)
),
ValueObjects::InventoryInfo(
item->maxWeight,
item->weight,
item->invSlotCount
),
playerController ? playerController->targetObjectId : 0,
playerController ? playerController->isStanding == 1 : true
};
}
};
}

View File

@@ -0,0 +1,43 @@
#pragma once
#include "../../../Common/Common.h"
namespace Interlude
{
class NPCFactory
{
public:
NPCFactory() = default;
virtual ~NPCFactory() = default;
const DTO::NPC Create(const User* item, const Enums::SpoilStateEnum spoiledState) const
{
return DTO::NPC{
item->objectId,
ValueObjects::Transform(
ValueObjects::Vector3(item->pawn->Location.x, item->pawn->Location.y, item->pawn->Location.z),
ValueObjects::Vector3(
static_cast<float_t>(item->pawn->Rotation.Pitch),
static_cast<float_t>(item->pawn->Rotation.Yaw),
static_cast<float_t>(item->pawn->Rotation.Roll)
),
ValueObjects::Vector3(item->pawn->Velocity.x, item->pawn->Velocity.y, item->pawn->Velocity.z),
ValueObjects::Vector3(item->pawn->Acceleration.x, item->pawn->Acceleration.y, item->pawn->Acceleration.z)
),
item->isMob != 0,
item->npcId,
spoiledState,
ValueObjects::FullName(
ConvertFromWideChar(item->nickname),
ConvertFromWideChar(item->title)
),
ValueObjects::VitalStats(
item->maxHp, item->hp,
item->maxMp, item->mp,
item->maxCp, item->cp
)
};
}
};
}

View File

@@ -0,0 +1,40 @@
#pragma once
#include "../../../Common/Common.h"
namespace Interlude
{
class PlayerFactory
{
public:
PlayerFactory() = default;
virtual ~PlayerFactory() = default;
const DTO::Player Create(const User* item) const
{
return DTO::Player{
item->objectId,
ValueObjects::Transform(
ValueObjects::Vector3(item->pawn->Location.x, item->pawn->Location.y, item->pawn->Location.z),
ValueObjects::Vector3(
static_cast<float_t>(item->pawn->Rotation.Pitch),
static_cast<float_t>(item->pawn->Rotation.Yaw),
static_cast<float_t>(item->pawn->Rotation.Roll)
),
ValueObjects::Vector3(item->pawn->Velocity.x, item->pawn->Velocity.y, item->pawn->Velocity.z),
ValueObjects::Vector3(item->pawn->Acceleration.x, item->pawn->Acceleration.y, item->pawn->Acceleration.z)
),
ValueObjects::FullName(
ConvertFromWideChar(item->nickname),
ConvertFromWideChar(item->title)
),
ValueObjects::Phenotype(
(Enums::RaceEnum)item->raceId,
item->gender == L2::Gender::MALE,
(Enums::ClassEnum)item->classId,
(Enums::ClassEnum)item->activeClassId
),
};
}
};
}

View File

@@ -0,0 +1,107 @@
#pragma once
#include <map>
#include <chrono>
#include "../GameStructs/L2GameDataWrapper.h"
#include "../GameStructs/FName.h"
#include "../../../Common/Common.h"
namespace Interlude
{
class SkillFactory
{
public:
SkillFactory(const L2GameDataWrapper& l2GameData, const FName& fName) :
m_L2GameData(l2GameData),
m_FName(fName)
{
}
SkillFactory() = delete;
virtual ~SkillFactory() = default;
const DTO::Skill Create(const DTO::Skill source, const uint32_t skillId, const uint32_t level, const uint32_t isActive) const
{
const auto data = m_L2GameData.GetMSData(skillId, level);
const auto cost = data ? data->mpCost : 0;
const auto range = data ? data->range : 0;
const auto name = data ? data->name : L"";
const auto description = data ? data->description : L"";
const auto iconEntry = data ? m_FName.GetEntry(data->iconNameIndex) : nullptr;
return DTO::Skill
{
skillId,
static_cast<uint8_t>(level),
isActive != 1,
static_cast<uint8_t>(cost),
static_cast<int16_t>(range),
ConvertFromWideChar(name),
ConvertFromWideChar(description),
iconEntry ? ConvertFromWideChar(iconEntry->value) : "",
source.isToggled,
source.isCasting,
source.isReloading
};
}
const DTO::Skill UpdateToggle(const DTO::Skill source, const bool isToggled) const
{
return DTO::Skill
{
source.skillId,
source.level,
source.isActive,
source.cost,
source.range,
source.name,
source.description,
source.iconName,
isToggled,
source.isCasting,
source.isReloading
};
}
const DTO::Skill UpdateCastingState(const DTO::Skill source, const bool isCasting) const
{
return DTO::Skill
{
source.skillId,
source.level,
source.isActive,
source.cost,
source.range,
source.name,
source.description,
source.iconName,
source.isToggled,
isCasting,
source.isReloading
};
}
const DTO::Skill UpdateReloadingState(const DTO::Skill source, const bool isReloading) const
{
return DTO::Skill
{
source.skillId,
source.level,
source.isActive,
source.cost,
source.range,
source.name,
source.description,
source.iconName,
source.isToggled,
source.isCasting,
isReloading
};
}
private:
const L2GameDataWrapper& m_L2GameData;
const FName& m_FName;
};
}

View File

@@ -0,0 +1,21 @@
#include "pch.h"
#include "FName.h"
namespace Interlude
{
FNameEntry* (__cdecl* FName::__GetEntry)(int) = 0;
//todo exception(?)
FNameEntry* FName::GetEntry(int index) const
{
if (__GetEntry) {
return(*__GetEntry)(index);
}
return 0;
}
void FName::Init(HMODULE hModule)
{
(FARPROC&)__GetEntry = GetProcAddress(hModule, "?GetEntry@FName@@SAPAUFNameEntry@@H@Z");
}
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include "pch.h"
#include "GameStructs.h"
#include "../../GameStructs/FNameInterface.h"
namespace Interlude
{
class FName : public FNameInterface
{
public:
FName() = default;
virtual ~FName() = default;
FNameEntry* GetEntry(int index) const;
void Init(HMODULE hModule) override;
private:
static FNameEntry* (__cdecl* __GetEntry)(int);
};
}

View File

@@ -0,0 +1,88 @@
#include "pch.h"
#include "../../../Common/apihook.h"
#include "GameEngineWrapper.h"
#include "ProcessManipulation.h"
#include "../../../Events/SkillCreatedEvent.h"
#include "../../../Events/SkillUsedEvent.h"
#include "../../../Events/SkillCancelledEvent.h"
#include "../../../Events/AbnormalEffectChangedEvent.h"
#include "../../../Events/EventDispatcher.h"
namespace Interlude
{
void* GameEngineWrapper::originalInitAddress = 0;
GameEngineWrapper::GameEngine* GameEngineWrapper::_target = 0;
void(__thiscall* GameEngineWrapper::__Init)(GameEngine*, float_t) = 0;
void(__thiscall* GameEngineWrapper::__OnSkillListPacket)(GameEngine*, L2ParamStack&) = 0;
int(__thiscall* GameEngineWrapper::__OnReceiveMagicSkillUse)(GameEngine*, User*, User*, L2ParamStack&) = 0;
void(__thiscall* GameEngineWrapper::__OnReceiveMagicSkillCanceled)(GameEngine*, User*) = 0;
void(__thiscall* GameEngineWrapper::__AddAbnormalStatus)(GameEngine*, L2ParamStack&) = 0;
void GameEngineWrapper::Init(HMODULE hModule)
{
void* initAddress = GetProcAddress(hModule, "?Tick@UGameEngine@@UAEXM@Z");
originalInitAddress = splice(initAddress, __Init_hook);
(FARPROC&)__Init = (FARPROC)initAddress;
(FARPROC&)__OnSkillListPacket = (FARPROC)splice(
GetProcAddress(hModule, "?OnSkillListPacket@UGameEngine@@UAEXAAVL2ParamStack@@@Z"), __OnSkillListPacket_hook
);
(FARPROC&)__OnReceiveMagicSkillUse = (FARPROC)splice(
GetProcAddress(hModule, "?OnReceiveMagicSkillUse@UGameEngine@@UAEXPAUUser@@0AAVL2ParamStack@@@Z"), __OnReceiveMagicSkillUse_hook
);
(FARPROC&)__OnReceiveMagicSkillCanceled = (FARPROC)splice(
GetProcAddress(hModule, "?OnReceiveMagicSkillCanceled@UGameEngine@@UAEXPAUUser@@@Z"), __OnReceiveMagicSkillCanceled_hook
);
(FARPROC&)__AddAbnormalStatus = (FARPROC)splice(
GetProcAddress(hModule, "?AddAbnormalStatus@UGameEngine@@UAEXAAVL2ParamStack@@@Z"), __AddAbnormalStatus_hook
);
}
void GameEngineWrapper::Restore()
{
restore(originalInitAddress);
restore((void*&)__OnSkillListPacket);
restore((void*&)__OnReceiveMagicSkillUse);
restore((void*&)__OnReceiveMagicSkillCanceled);
restore((void*&)__AddAbnormalStatus);
}
void __fastcall GameEngineWrapper::__Init_hook(GameEngine* This, uint32_t /*edx*/, float_t unk)
{
if (_target == 0) {
_target = This;
InjectLibrary::StopCurrentProcess();
restore(originalInitAddress);
InjectLibrary::StartCurrentProcess();
(*__Init)(This, unk);
}
}
void __fastcall GameEngineWrapper::__OnSkillListPacket_hook(GameEngine* This, uint32_t, L2ParamStack& stack)
{
EventDispatcher::GetInstance().Dispatch(SkillCreatedEvent{stack.GetBufferAsVector<int32_t>()});
(*__OnSkillListPacket)(This, stack);
}
int __fastcall GameEngineWrapper::__OnReceiveMagicSkillUse_hook(GameEngine* This, uint32_t, User* u1, User* u2, L2ParamStack& stack)
{
EventDispatcher::GetInstance().Dispatch(SkillUsedEvent{ stack.GetBufferAsVector<int32_t>() });
return (*__OnReceiveMagicSkillUse)(This, u1, u2, stack);
}
void __fastcall GameEngineWrapper::__OnReceiveMagicSkillCanceled_hook(GameEngine* This, uint32_t, User* user)
{
EventDispatcher::GetInstance().Dispatch(SkillCancelledEvent{ user->objectId });
(*__OnReceiveMagicSkillCanceled)(This, user);
}
void __fastcall GameEngineWrapper::__AddAbnormalStatus_hook(GameEngine* This, uint32_t, L2ParamStack& stack)
{
EventDispatcher::GetInstance().Dispatch(AbnormalEffectChangedEvent{ stack.GetBufferAsVector<int32_t>(3) });
(*__AddAbnormalStatus)(This, stack);
}
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include <math.h>
#include <cstdint>
#include "../../GameStructs/GameEngineInterface.h"
#include "GameStructs.h"
#include "L2ParamStack.h"
namespace Interlude
{
class GameEngineWrapper : public GameEngineInterface
{
public:
class GameEngine {};
GameEngineWrapper() = default;
virtual ~GameEngineWrapper() = default;
void Init(HMODULE hModule) override;
void Restore() override;
private:
static void(__thiscall* __Init)(GameEngine*, float_t);
static void(__thiscall* __OnSkillListPacket)(GameEngine*, L2ParamStack& stack);
static int(__thiscall* __OnReceiveMagicSkillUse)(GameEngine*, User*, User*, L2ParamStack&);
static void(__thiscall* __OnReceiveMagicSkillCanceled)(GameEngine*, User*);
static void(__thiscall* __AddAbnormalStatus)(GameEngine*, L2ParamStack&);
static void __fastcall __Init_hook(GameEngine* This, uint32_t /*edx*/, float_t unk);
static void __fastcall __OnSkillListPacket_hook(GameEngine* This, uint32_t /*edx*/, L2ParamStack& stack);
static int __fastcall __OnReceiveMagicSkillUse_hook(GameEngine* This, uint32_t /*edx*/, User* u1, User* u2, L2ParamStack& stack);
static void __fastcall __OnReceiveMagicSkillCanceled_hook(GameEngine* This, uint32_t /*edx*/, User* user);
static void __fastcall __AddAbnormalStatus_hook(GameEngine* This, uint32_t /*edx*/, L2ParamStack& stack);
private:
static void* originalInitAddress;
static GameEngine* _target;
};
}

View File

@@ -0,0 +1,258 @@
#pragma once
#include "../../GameStructs/GameStructs.h"
namespace Interlude
{
class User
{
public:
char pad_0000[8]; //0x0000
L2::UserType userType; //0x0008
char pad_000C[4]; //0x000C
int32_t isMob; //0x0010
uint32_t npcId; //0x0014
uint32_t objectId; //0x0018
wchar_t nickname[24]; //0x001C
L2::Race raceId; //0x004C
L2::Gender gender; //0x0050
int32_t classId; //0x0054
uint32_t lvl; //0x0058
int32_t exp; //0x005C
char pad_0060[4]; //0x0060
int32_t str; //0x0064
int32_t dex; //0x0068
int32_t con; //0x006C
int32_t int_; //0x0070
int32_t wit; //0x0074
int32_t men; //0x0078
int32_t maxHp; //0x007C
int32_t hp; //0x0080
int32_t maxMp; //0x0084
int32_t mp; //0x0088
int32_t maxWeight; //0x008C
char pad_0090[8]; //0x0090
class L2::UserWear wear; //0x0098
char pad_010C[132]; //0x010C
class L2::FColor titleColor; //0x0190
int32_t pad_0194; //0x0194 pvp state: 0 - normal, 1 - pvp, 2 - blinking
int32_t karma; //0x0198
char pad_019C[104]; //0x019C
class APawn* pawn; //0x0204
char pad_0208[12]; //0x0208
int32_t weight; //0x0214
int32_t sp; //0x0218
int32_t accuracy; //0x021C
int32_t critRate; //0x0220
int32_t pAttack; //0x0224
int32_t attackSpeed; //0x0228
int32_t pDefense; //0x022C
int32_t evasion; //0x0230
int32_t mAttack; //0x0234
int32_t mDefense; //0x0238
int32_t castingSpeed; //0x023C
char pad_0240[20]; //0x0240
wchar_t title[16]; //0x0254
char pad_0274[32]; //0x0274
int32_t pad_0294; //0x0294
char pad_0298[16]; //0x0298
int32_t hasDwarvenCraft; //0x02A8
int32_t attackSpeed2; //0x02AC
char pad_02B0[4]; //0x02B0
int32_t pkKills; //0x02B4
int32_t pvpKills; //0x02B8
char pad_02BC[4]; //0x02BC
int32_t activeClassId; //0x02C0
int32_t maxCp; //0x02C4
int32_t cp; //0x02C8
char pad_02CC[20]; //0x02CC
int16_t recRemaining; //0x02E0
int16_t evalScore; //0x02E2
int32_t invSlotCount; //0x02E4
char pad_02E8[32]; //0x02E8
class L2::FColor nicknameColor; //0x0308
char pad_030C[164]; //0x030C
}; //Size: 0x03B0
class APawn
{
public:
char pad_0000[8]; //0x0000
void* uStaticMeshInstance; //0x0008
void* fStateFrame; //0x000C
char pad_0010[8]; //0x0010
void* uPackage; //0x0018
char pad_001C[32]; //0x001C
class ALineagePlayerController* lineagePlayerController; //0x003C
void* terrainInfo; //0x0040
char pad_0044[28]; //0x0044
int32_t ownerObjectId; //0x0060
char pad_0064[344]; //0x0064
class L2::FVector Location; //0x01BC
class L2::FRotator Rotation; //0x01C8
class L2::FVector Velocity; //0x01D4
class L2::FVector Acceleration; //0x01E0
char pad_01EC[336]; //0x01EC
class L2::FVector Location2; //0x033C
char pad_0348[1244]; //0x0348
}; //Size: 0x0824
class ALineagePlayerController
{
public:
char pad_0000[444]; //0x0000
class L2::FVector cameraPosition; //0x01BC
class L2::FRotator cameraRotation; //0x01C8
char pad_01D4[544]; //0x01D4
class L2::FVector moveLocation; //0x03F4
char pad_0400[16]; //0x0400
int32_t isIdle; //0x0410
uint32_t targetObjectId; //0x0414
char pad_0418[28]; //0x0418
int8_t isRunning; //0x0434
int8_t isStanding; //0x0435
char pad_0436[26]; //0x0436
}; //Size: 0x0450
struct Item
{
uint32_t objectId;
unsigned int itemId;
unsigned int isStackable; // ??
unsigned int amount;
APawn* pawn;
};
class ItemInfo
{
public:
L2::ItemType2 type2; //0x0000
char pad_0002[2]; //0x0002
uint32_t objectId; //0x0004
uint32_t itemId; //0x0008
uint32_t amount; //0x000C
char pad_0010[8]; //0x0010
L2::ItemSlot itemSlot; //0x0018
uint16_t customType1; //0x001C
uint16_t isEquipped; //0x001E
uint16_t enchantLevel; //0x0020
char pad_0022[2]; //0x0022
uint16_t customType2; //0x0024
char pad_0026[10]; //0x0026
uint32_t augmentation1; //0x0030
uint32_t augmentation2; //0x0034
int32_t mana; //0x0038
}; //Size: 0x003C
class FL2ItemDataBase
{
public:
char pad_0000[4]; //0x0000
L2::ItemDataType dataType; //0x0004
char pad_0008[4]; //0x0008
int32_t itemId; //0x000C
char pad_0010[20]; //0x0010
int32_t dropItemsNameIndex; //0x0024
char pad_0028[8]; //0x0028
int32_t dropItemsTexNameIndex; //0x0030
char pad_0034[8]; //0x0034
int32_t iconNameIndex; //0x003C
char pad_0040[16]; //0x0040
int32_t nameIndex; //0x0050
char pad_0054[4]; //0x0054
wchar_t* description; //0x0058
char pad_005C[12]; //0x005C
wchar_t* setItem; //0x0068
char pad_006C[8]; //0x006C
wchar_t* setEffect; //0x0074
char pad_0078[8]; //0x0078
wchar_t* addSetItem; //0x0080
char pad_0084[8]; //0x0084
wchar_t* addSetEffect; //0x008C
char pad_0090[36]; //0x0090
wchar_t* enchantEffect; //0x00B4
char pad_00B8[12]; //0x00B8
int32_t weight; //0x00C4
}; //Size: 0x0140
class FL2EtcItemData : public FL2ItemDataBase
{
};
class FL2ArmorItemData : public FL2ItemDataBase
{
public:
char pad_00C8[1308]; //0x00C8
L2::ArmorType armorType; //0x05E4
L2::CrystalType crystalType; //0x05E8
char pad_05EC[4]; //0x05EC
int32_t pDef; //0x05F0
int32_t mDef; //0x05F4
char pad_05F8[8]; //0x05F8
};
class FL2WeaponItemData : public FL2ItemDataBase
{
public:
char pad_00C8[24]; //0x00C8
int32_t wtfNameIndex1; //0x00E0
char pad_00E4[16]; //0x00E4
int32_t wtfNameIndex2; //0x00F4
int32_t wtfNameIndex3; //0x00F8
char pad_00FC[12]; //0x00FC
int32_t wtfNameIndex4; //0x0108
int32_t wtfNameIndex5; //0x010C
int32_t wtfNameIndex6; //0x0110
int32_t wtfNameIndex7; //0x0114
int32_t wtfNameIndex8; //0x0118
int32_t wtfNameIndex9; //0x011C
char pad_0120[4]; //0x0120
int32_t rndDamage; //0x0124
int32_t pAtk; //0x0128
int32_t mAtk; //0x012C
L2::WeaponType weaponType; //0x0130
L2::CrystalType crystalType; //0x0134
int32_t critical; //0x0138
int32_t hitModify; //0x013C
int32_t shieldEvasion; //0x0140
int32_t shieldPdef; //0x0144
int32_t shieldDefRate; //0x0148
int32_t atkSpd; //0x014C
int32_t mpConsume; //0x0150
int32_t soulshotCount; //0x0154
int32_t spiritshotCount; //0x0158
char pad_015C[16]; //0x015C
int32_t wtfNameIndex10; //0x016C
char pad_0170[220]; //0x0170
int32_t wtfNameIndex11; //0x024C
char pad_0250[48]; //0x0250
}; //Size: 0x0280
class FNameEntry
{
public:
char pad_0000[12]; //0x0000
wchar_t value[36]; //0x000C
};
class FL2MagicSkillData
{
public:
wchar_t* name; //0x0000
char pad_0004[8]; //0x0004
wchar_t* description; //0x000C
char pad_0010[8]; //0x0010
int32_t skillId; //0x0018
int32_t lvl; //0x001C
char pad_0020[4]; //0x0020
int32_t mpCost; //0x0024
char pad_0028[4]; //0x0028
int32_t range; //0x002C
char pad_0030[4]; //0x0030
float hitTime; //0x0034
char pad_0038[12]; //0x0038
int32_t wtfNameIndex; //0x0044
int32_t iconNameIndex; //0x0048
char pad_004C[52]; //0x004C
}; //Size: 0x0080
};

View File

@@ -0,0 +1,61 @@
#include "pch.h"
#include "../../../Common/apihook.h"
#include "L2GameDataWrapper.h"
#include "ProcessManipulation.h"
namespace Interlude
{
void* L2GameDataWrapper::originalInitAddress = 0;
L2GameDataWrapper::L2GameData* L2GameDataWrapper::_target = 0;
int(__thiscall* L2GameDataWrapper::__Init)(L2GameData*, int, int) = 0;
FL2ItemDataBase* (__thiscall* L2GameDataWrapper::__GetItemData)(L2GameData*, int) = 0;
FL2MagicSkillData* (__thiscall* L2GameDataWrapper::__GetMSData)(L2GameData*, int, int) = 0;
void L2GameDataWrapper::Init(HMODULE hModule)
{
void* initAddress = GetProcAddress(hModule, "?GetMSData@FL2GameData@@QAEPAUFL2MagicSkillData@@HH@Z");
originalInitAddress = splice(initAddress, __Init_hook);
(FARPROC&)__Init = (FARPROC)initAddress;
(FARPROC&)__GetItemData = GetProcAddress(hModule, "?GetItemData@FL2GameData@@QAEPAVFL2ItemDataBase@@H@Z");
(FARPROC&)__GetMSData = GetProcAddress(hModule, "?GetMSData@FL2GameData@@QAEPAUFL2MagicSkillData@@HH@Z");
}
void L2GameDataWrapper::Restore()
{
restore(originalInitAddress);
}
//todo exception(?)
FL2ItemDataBase* L2GameDataWrapper::GetItemData(int itemId) const
{
if (__GetItemData && _target) {
return (*__GetItemData)(_target, itemId);
}
return 0;
}
FL2MagicSkillData* L2GameDataWrapper::GetMSData(int skillId, int level) const
{
if (__GetMSData && _target) {
return (*__GetMSData)(_target, skillId, level);
}
return 0;
}
int __fastcall L2GameDataWrapper::__Init_hook(L2GameData* This, int, int unk, int unk1)
{
if (_target == 0) {
_target = This;
InjectLibrary::StopCurrentProcess();
restore(originalInitAddress);
InjectLibrary::StartCurrentProcess();
return (*__Init)(This, unk, unk1);
}
return 0;
}
};

View File

@@ -0,0 +1,30 @@
#pragma once
#include "pch.h"
#include "GameStructs.h"
#include "../../GameStructs/L2GameDataInterface.h"
namespace Interlude
{
class L2GameDataWrapper : public L2GameDataInterface
{
public:
class L2GameData {};
L2GameDataWrapper() = default;
virtual ~L2GameDataWrapper() = default;
FL2ItemDataBase* GetItemData(int itemId) const;
FL2MagicSkillData* GetMSData(int skillId, int level) const;
void Init(HMODULE hModule) override;
void Restore() override;
private:
static int(__thiscall* __Init)(L2GameData*, int, int);
static FL2ItemDataBase* (__thiscall* __GetItemData)(L2GameData*, int);
static FL2MagicSkillData* (__thiscall* __GetMSData)(L2GameData*, int, int);
static int __fastcall __Init_hook(L2GameData* This, int /*edx*/, int unk, int unk1);
private:
static void* originalInitAddress;
static L2GameData* _target;
};
};

View File

@@ -0,0 +1,71 @@
#include "pch.h"
#include "L2ParamStack.h"
namespace Interlude
{
void(__thiscall* L2ParamStack::__Ctor)(L2ParamStack* This, int) = 0;
void(__thiscall* L2ParamStack::__Dtor)(L2ParamStack* This) = 0;
int(__thiscall* L2ParamStack::__PushBack)(L2ParamStack* This, void*) = 0;
void* (__thiscall* L2ParamStack::__Top)(L2ParamStack* This) = 0;
void** (__thiscall* L2ParamStack::__GetBuffer)(L2ParamStack* This) = 0;
int (__thiscall* L2ParamStack::__GetBufferSize)(L2ParamStack* This) = 0;
int (__thiscall* L2ParamStack::__GetTotalBufferSize)(L2ParamStack* This) = 0;
HMODULE L2ParamStack::_hModule = 0;
L2ParamStack::L2ParamStack(int size)
{
Init();
(*__Ctor)(this, size);
}
L2ParamStack::~L2ParamStack()
{
Init();
(*__Dtor)(this);
}
int L2ParamStack::PushBack(void* val)
{
Init();
return (*__PushBack)(this, val);
}
void* L2ParamStack::Top()
{
Init();
return (*__Top)(this);
}
void** L2ParamStack::GetBuffer()
{
Init();
return (__GetBuffer)(this);
}
int L2ParamStack::GetBufferSize()
{
Init();
return (__GetBufferSize)(this);
}
int L2ParamStack::GetTotalBufferSize()
{
Init();
return (__GetTotalBufferSize)(this);
}
void L2ParamStack::Init()
{
// todo exceptions
if (_hModule == 0) {
_hModule = GetModuleHandleA("Core.dll");
(FARPROC&)__Ctor = GetProcAddress(_hModule, "??0L2ParamStack@@QAE@H@Z");
(FARPROC&)__Dtor = GetProcAddress(_hModule, "??1L2ParamStack@@QAE@XZ");
(FARPROC&)__PushBack = GetProcAddress(_hModule, "?PushBack@L2ParamStack@@QAEHPAX@Z");
(FARPROC&)__Top = GetProcAddress(_hModule, "?Top@L2ParamStack@@QAEPAXXZ");
(FARPROC&)__GetBuffer = GetProcAddress(_hModule, "?GetBuffer@L2ParamStack@@QAEPAPAXXZ");
(FARPROC&)__GetBufferSize = GetProcAddress(_hModule, "?GetBufferSize@L2ParamStack@@QAEHXZ");
(FARPROC&)__GetTotalBufferSize = GetProcAddress(_hModule, "?GetTotalBufferSize@L2ParamStack@@QAEHXZ");
}
}
}

View File

@@ -0,0 +1,63 @@
#pragma once
#include <vector>
namespace Interlude
{
class L2ParamStack
{
char padding[16] = "";
public:
L2ParamStack(int size);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
~L2ParamStack();
int PushBack(void* val);
void* Top();
void** GetBuffer();
int GetBufferSize();
int GetTotalBufferSize();
template <typename T>
std::vector<T> GetBufferAsVector()
{
std::vector<T> result;
auto buffer = GetBuffer();
for (int i = 0; i < GetBufferSize(); i++) {
result.push_back((T) buffer[i]);
}
return result;
}
template <typename T>
std::vector<T> GetBufferAsVector(uint16_t objectSize)
{
std::vector<T> result;
uint32_t* tmpBuffer = (uint32_t*)GetBuffer();
uint32_t objectsCount = tmpBuffer[0];
auto buffer = GetBuffer();
for (size_t i = 0; i < objectsCount; i++) {
for (size_t j = 0; j < objectSize; j++) {
result.push_back((T)buffer[i * objectSize + j + 1]);
}
}
return result;
}
private:
void Init();
private:
static void(__thiscall* __Ctor)(L2ParamStack* This, int);
static void(__thiscall* __Dtor)(L2ParamStack* This);
static int(__thiscall* __PushBack)(L2ParamStack* This, void*);
static void*(__thiscall* __Top)(L2ParamStack* This);
static void**(__thiscall* __GetBuffer)(L2ParamStack* This);
static int(__thiscall* __GetBufferSize)(L2ParamStack* This);
static int(__thiscall* __GetTotalBufferSize)(L2ParamStack* This);
static HMODULE _hModule;
};
}

View File

@@ -0,0 +1,126 @@
#include "pch.h"
#include "../../../Common/apihook.h"
#include "NetworkHandlerWrapper.h"
#include "../../../Events/SpoiledEvent.h"
#include "../../../Events/CreatureDiedEvent.h"
#include "../../../Events/EventDispatcher.h"
#include "ProcessManipulation.h"
namespace Interlude
{
void* NetworkHandlerWrapper::originalInitAddress = 0;
NetworkHandlerWrapper::NetworkHandler* NetworkHandlerWrapper::_target = 0;
void(__thiscall* NetworkHandlerWrapper::__Init)(NetworkHandler*, float) = 0;
Item* (__thiscall* NetworkHandlerWrapper::__GetNextItem)(NetworkHandler*, float, int) = 0;
User* (__thiscall* NetworkHandlerWrapper::__GetNextCreature)(NetworkHandler*, float, int) = 0;
float(__thiscall* NetworkHandlerWrapper::__GetMaxTickRate)(NetworkHandler*) = 0;
int(__thiscall* NetworkHandlerWrapper::__AddNetworkQueue)(NetworkHandler*, L2::NetworkPacket*) = 0;
int(__thiscall* NetworkHandlerWrapper::__OnDie)(NetworkHandler*, User*, L2ParamStack&) = 0;
//todo exception
Item* NetworkHandlerWrapper::GetNextItem(float_t radius, int prevId) const
{
if (__GetNextItem && _target) {
return (*__GetNextItem)(_target, radius, prevId);
}
return 0;
}
//todo exception
User* NetworkHandlerWrapper::GetNextCreature(float_t radius, int prevId) const
{
if (__GetNextCreature && _target) {
return (*__GetNextCreature)(_target, radius, prevId);
}
return 0;
}
User* NetworkHandlerWrapper::GetHero() const
{
const auto creatures = GetAllObjects<User*>(0.1f, [this](float_t radius, int32_t prevId) {
return GetNextCreature(radius, prevId);
});
for (const auto& kvp : creatures)
{
const auto& creature = static_cast<User*>(kvp.second);
if (creature->userType == L2::UserType::USER && creature->lvl > 0)
{
return creature;
}
}
return 0;
}
void NetworkHandlerWrapper::Init(HMODULE hModule)
{
void* initAddress = GetProcAddress(hModule, "?Tick@UNetworkHandler@@UAEXM@Z");
originalInitAddress = splice(initAddress, __Init_hook);
(FARPROC&)__Init = (FARPROC)initAddress;
(FARPROC&)__GetNextItem = GetProcAddress(hModule, "?GetNextItem@UNetworkHandler@@UAEPAUItem@@MH@Z");
(FARPROC&)__GetNextCreature = GetProcAddress(hModule, "?GetNextCreature@UNetworkHandler@@UAEPAUUser@@MH@Z");
(FARPROC&)__GetMaxTickRate = (FARPROC)splice(
GetProcAddress(hModule, "?GetMaxTickRate@UGameEngine@@UAEMXZ"), __GetMaxTickRate_hook
);
(FARPROC&)__AddNetworkQueue = (FARPROC)splice(
GetProcAddress(hModule, "?AddNetworkQueue@UNetworkHandler@@UAEHPAUNetworkPacket@@@Z"), __AddNetworkQueue_hook
);
(FARPROC&)__OnDie = (FARPROC)splice(
GetProcAddress(hModule, "?OnDie@UGameEngine@@UAEHPAUUser@@AAVL2ParamStack@@@Z"), __OnDie_hook
);
}
void NetworkHandlerWrapper::Restore()
{
restore(originalInitAddress);
restore((void*&)__GetMaxTickRate);
restore((void*&)__AddNetworkQueue);
restore((void*&)__OnDie);
}
void __fastcall NetworkHandlerWrapper::__Init_hook(NetworkHandler* This, int /*edx*/, float unk)
{
if (_target == 0) {
_target = This;
InjectLibrary::StopCurrentProcess();
restore(originalInitAddress);
InjectLibrary::StartCurrentProcess();
(*__Init)(This, unk);
}
}
// TODO ini
// 0 - <20><><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
float __fastcall NetworkHandlerWrapper::__GetMaxTickRate_hook(NetworkHandler* This, int)
{
float fps = (*__GetMaxTickRate)(This);
return 0.0f;
}
int __fastcall NetworkHandlerWrapper::__AddNetworkQueue_hook(NetworkHandler* This, int, L2::NetworkPacket* packet)
{
if (packet->id == static_cast<int>(L2::NetworkPacketId::SYSTEM_MESSAGE)) {
L2::SystemMessagePacket* p = static_cast<L2::SystemMessagePacket*>(packet);
if (
p->GetMessageId() == static_cast<int>(L2::SystemMessagePacket::Type::SPOIL_SUCCESS) ||
p->GetMessageId() == static_cast<int>(L2::SystemMessagePacket::Type::ALREADY_SPOILED)
) {
EventDispatcher::GetInstance().Dispatch(SpoiledEvent{});
}
}
return (*__AddNetworkQueue)(This, packet);
}
int __fastcall NetworkHandlerWrapper::__OnDie_hook(NetworkHandler* This, int, User* creature, L2ParamStack& stack)
{
EventDispatcher::GetInstance().Dispatch(CreatureDiedEvent{ creature->objectId });
return (*__OnDie)(This, creature, stack);
}
}

View File

@@ -0,0 +1,42 @@
#pragma once
#include <cstdint>
#include <map>
#include "../../GameStructs/NetworkHandlerInterface.h"
#include "GameStructs.h"
#include "../../GameStructs/FindObjectsTrait.h"
#include "L2ParamStack.h"
namespace Interlude
{
class NetworkHandlerWrapper : public NetworkHandlerInterface, public FindObjectsTrait
{
public:
class NetworkHandler {};
NetworkHandlerWrapper() = default;
virtual ~NetworkHandlerWrapper() = default;
void Init(HMODULE hModule) override;
void Restore() override;
Item* GetNextItem(float_t radius, int prevId) const;
User* GetNextCreature(float_t radius, int prevId) const;
User* GetHero() const;
private:
static void __fastcall __Init_hook(NetworkHandler* This, int /*edx*/, float unk);
static int __fastcall __AddNetworkQueue_hook(NetworkHandler* This, int /*edx*/, L2::NetworkPacket* packet);
static int __fastcall __OnDie_hook(NetworkHandler* This, int /*edx*/, User* creature, L2ParamStack& stack);
static float __fastcall __GetMaxTickRate_hook(NetworkHandler* This, int /*edx*/);
static void(__thiscall* __Init)(NetworkHandler*, float);
static Item* (__thiscall* __GetNextItem)(NetworkHandler*, float, int);
static User* (__thiscall* __GetNextCreature)(NetworkHandler*, float, int);
static float(__thiscall* __GetMaxTickRate)(NetworkHandler*);
static int(__thiscall* __AddNetworkQueue)(NetworkHandler*, L2::NetworkPacket*);
static int(__thiscall* __OnDie)(NetworkHandler*, User*, L2ParamStack&);
private:
static void* originalInitAddress;
static NetworkHandler* _target;
};
}

View File

@@ -0,0 +1,48 @@
#pragma once
#include <map>
#include "Domain/Repositories/DropRepositoryInterface.h"
#include "../Factories/DropFactory.h"
#include "../../GameStructs/FindObjectsTrait.h"
using namespace L2Bot::Domain;
namespace Interlude
{
class DropRepository : public Repositories::DropRepositoryInterface, public FindObjectsTrait
{
public:
const std::map<uint32_t, DTO::Drop> GetObjects() override
{
const auto items = GetAllObjects<Item*>(m_Radius, [this](float_t radius, int32_t prevId) {
return m_NetworkHandler.GetNextItem(radius, prevId);
});
std::map<uint32_t, DTO::Drop> map;
for (const auto& kvp : items)
{
const auto item = kvp.second;
map.emplace(item->objectId, m_Factory.Create(item));
}
return map;
}
DropRepository(const NetworkHandlerWrapper& networkHandler, const DropFactory& factory, const uint16_t radius) :
m_NetworkHandler(networkHandler),
m_Factory(factory),
m_Radius(radius)
{
}
DropRepository() = delete;
virtual ~DropRepository() = default;
private:
const NetworkHandlerWrapper& m_NetworkHandler;
const DropFactory& m_Factory;
const uint16_t m_Radius;
};
}

View File

@@ -0,0 +1,54 @@
#pragma once
#include "Domain/Repositories/HeroRepositoryInterface.h"
#include "../Factories/HeroFactory.h"
#include "../../../Events/EventDispatcher.h"
#include "../../../Events/HeroCreatedEvent.h"
#include "../../../Events/HeroDeletedEvent.h"
using namespace L2Bot::Domain;
namespace Interlude
{
class HeroRepository : public Repositories::HeroRepositoryInterface
{
public:
const std::map<uint32_t, DTO::Hero> GetObjects() override
{
std::map<uint32_t, DTO::Hero> map;
const auto hero = m_NetworkHandler.GetHero();
if (hero)
{
map.emplace(hero->objectId, m_Factory.Create(hero));
}
if (hero != nullptr && m_PrevHero == nullptr)
{
EventDispatcher::GetInstance().Dispatch(HeroCreatedEvent{});
}
if (hero == nullptr && m_PrevHero != nullptr)
{
EventDispatcher::GetInstance().Dispatch(HeroDeletedEvent{});
}
m_PrevHero = hero;
return map;
}
HeroRepository(const NetworkHandlerWrapper& networkHandler, const HeroFactory& factory) :
m_NetworkHandler(networkHandler),
m_Factory(factory)
{
}
HeroRepository() = delete;
virtual ~HeroRepository() = default;
private:
const HeroFactory& m_Factory;
const NetworkHandlerWrapper& m_NetworkHandler;
User* m_PrevHero = nullptr;
};
}

View File

@@ -0,0 +1,97 @@
#pragma once
#include <map>
#include "../GameStructs/NetworkHandlerWrapper.h"
#include "Domain/Repositories/NPCRepositoryInterface.h"
#include "../Factories/NPCFactory.h"
#include "../../../Events/EventDispatcher.h"
#include "../../../Events/SpoiledEvent.h"
#include "../../../Events/CreatureDiedEvent.h"
#include "../../GameStructs/FindObjectsTrait.h"
using namespace L2Bot::Domain;
namespace Interlude
{
class NPCRepository : public Repositories::NPCRepositoryInterface, public FindObjectsTrait
{
public:
const std::map<uint32_t, DTO::NPC> GetObjects() override
{
const auto creatures = GetAllObjects<User*>(m_Radius, [this](float_t radius, int32_t prevId) {
return m_NetworkHandler.GetNextCreature(radius, prevId);
});
std::map<uint32_t, DTO::NPC> map;
for (const auto& kvp : creatures)
{
const auto creature = kvp.second;
if (creature->userType == L2::UserType::NPC) {
const auto spoilState = m_Spoiled.find(creature->objectId) == m_Spoiled.end() ? Enums::SpoilStateEnum::none : m_Spoiled.at(creature->objectId);
map.emplace(creature->objectId, m_Factory.Create(creature, spoilState));
}
}
return map;
}
NPCRepository(const NetworkHandlerWrapper& networkHandler, const NPCFactory& factory, const uint16_t radius) :
m_NetworkHandler(networkHandler),
m_Factory(factory),
m_Radius(radius)
{
EventDispatcher::GetInstance().Subscribe(SpoiledEvent::name, [this](const Event& evt) {
OnSpoiled(evt);
});
EventDispatcher::GetInstance().Subscribe(CreatureDiedEvent::name, [this](const Event& evt) {
OnCreatureDied(evt);
});
}
NPCRepository() = delete;
virtual ~NPCRepository() = default;
void OnSpoiled(const Event& evt)
{
if (evt.GetName() == SpoiledEvent::name)
{
const auto casted = static_cast<const SpoiledEvent&>(evt);
const auto hero = m_NetworkHandler.GetHero();
if (hero && hero->pawn && hero->pawn->lineagePlayerController)
{
const auto targetId = hero->pawn->lineagePlayerController->targetObjectId;
if (targetId)
{
m_Spoiled[targetId] = Enums::SpoilStateEnum::spoiled;
}
}
}
}
void OnCreatureDied(const Event& evt)
{
if (evt.GetName() == CreatureDiedEvent::name)
{
const auto casted = static_cast<const CreatureDiedEvent&>(evt);
if (m_Spoiled.find(casted.GetCreatureId()) != m_Spoiled.end())
{
if (m_Spoiled[casted.GetCreatureId()] == Enums::SpoilStateEnum::spoiled)
{
m_Spoiled[casted.GetCreatureId()] = Enums::SpoilStateEnum::sweepable;
}
else
{
m_Spoiled[casted.GetCreatureId()] = Enums::SpoilStateEnum::none;
}
}
}
}
private:
const NPCFactory& m_Factory;
std::map<uint32_t, Enums::SpoilStateEnum> m_Spoiled;
const NetworkHandlerWrapper& m_NetworkHandler;
const uint16_t m_Radius = 0;
};
}

View File

@@ -0,0 +1,50 @@
#pragma once
#include <map>
#include "Domain/Repositories/PlayerRepositoryInterface.h"
#include "../Factories/PlayerFactory.h"
#include "../../GameStructs/FindObjectsTrait.h"
#include "../GameStructs/NetworkHandlerWrapper.h"
using namespace L2Bot::Domain;
namespace Interlude
{
class PlayerRepository : public Repositories::PlayerRepositoryInterface, public FindObjectsTrait
{
public:
const std::map<uint32_t, DTO::Player> GetObjects() override
{
const auto creatures = GetAllObjects<User*>(m_Radius, [this](float_t radius, int32_t prevId) {
return m_NetworkHandler.GetNextCreature(radius, prevId);
});
std::map<uint32_t, DTO::Player> map;
for (const auto& kvp : creatures)
{
const auto creature = kvp.second;
if (creature->userType == L2::UserType::USER && creature->lvl == 0) {
map.emplace(creature->objectId, m_Factory.Create(creature));
}
}
return map;
}
PlayerRepository(const NetworkHandlerWrapper& networkHandler, const PlayerFactory& factory, const uint16_t radius) :
m_NetworkHandler(networkHandler),
m_Factory(factory),
m_Radius(radius)
{
}
PlayerRepository() = delete;
virtual ~PlayerRepository() = default;
private:
const PlayerFactory& m_Factory;
const NetworkHandlerWrapper& m_NetworkHandler;
const uint16_t m_Radius;
};
}

View File

@@ -0,0 +1,214 @@
#pragma once
#include <map>
#include <chrono>
#include <shared_mutex>
#include "Domain/Repositories/SkillRepositoryInterface.h"
#include "../Factories/SkillFactory.h"
#include "../../../Events/SkillCreatedEvent.h"
#include "../../../Events/SkillUsedEvent.h"
#include "../../../Events/SkillCancelledEvent.h"
#include "../../../Events/AbnormalEffectChangedEvent.h"
#include "../../../Events/HeroDeletedEvent.h"
#include "../GameStructs/NetworkHandlerWrapper.h"
#include "../../../Common/TimerMap.h"
using namespace L2Bot::Domain;
namespace Interlude
{
class SkillRepository : public Repositories::SkillRepositoryInterface
{
public:
const std::map<uint32_t, DTO::Skill> GetObjects() override
{
std::unique_lock<std::shared_timed_mutex>(m_Mutex);
return m_Skills;
}
SkillRepository(const NetworkHandlerWrapper& networkHandler, const SkillFactory& factory) :
m_NetworkHandler(networkHandler),
m_Factory(factory)
{
EventDispatcher::GetInstance().Subscribe(SkillCreatedEvent::name, [this](const Event& evt) {
OnSkillCreated(evt);
});
EventDispatcher::GetInstance().Subscribe(SkillUsedEvent::name, [this](const Event& evt) {
OnSkillUsed(evt);
});
EventDispatcher::GetInstance().Subscribe(SkillCancelledEvent::name, [this](const Event& evt) {
OnSkillCancelled(evt);
});
EventDispatcher::GetInstance().Subscribe(AbnormalEffectChangedEvent::name, [this](const Event& evt) {
OnSkillToggled(evt);
});
EventDispatcher::GetInstance().Subscribe(HeroDeletedEvent::name, [this](const Event& evt) {
OnHeroDeleted(evt);
});
}
SkillRepository() = delete;
virtual ~SkillRepository() = default;
void OnHeroDeleted(const Event& evt)
{
std::shared_lock<std::shared_timed_mutex>(m_Mutex);
if (evt.GetName() == HeroDeletedEvent::name)
{
m_Skills.clear();
m_CastingTimers.StopAll();
m_ReloadingTimers.StopAll();
}
}
void OnSkillCreated(const Event& evt)
{
std::shared_lock<std::shared_timed_mutex>(m_Mutex);
if (evt.GetName() == SkillCreatedEvent::name)
{
const auto casted = static_cast<const SkillCreatedEvent&>(evt);
const auto skillInfo = casted.GetSkillInfo();
const auto skillId = skillInfo[2];
const auto alreadyExists = m_Skills.find(skillId) != m_Skills.end();
auto skill = m_Factory.Create(
alreadyExists ? m_Skills[skillId] : DTO::Skill(),
skillInfo[2],
skillInfo[1],
skillInfo[0]
);
UpdateSkill(skill);
}
}
void OnSkillUsed(const Event& evt)
{
std::shared_lock<std::shared_timed_mutex>(m_Mutex);
if (evt.GetName() == SkillUsedEvent::name)
{
const auto casted = static_cast<const SkillUsedEvent&>(evt);
const auto skillInfo = casted.GetSkillInfo();
const auto skillId = skillInfo[0];
if (m_Skills.find(skillId) == m_Skills.end())
{
//todo exception?
return;
}
auto skill = m_Factory.UpdateReloadingState(
m_Factory.UpdateCastingState(
m_Skills[skillId],
true
),
true
);
UpdateSkill(skill);
m_UsedSkillId = skill.skillId;
m_ReloadingTimers.StartTimer(skill.skillId, skillInfo[3], [this] (uint32_t skillId) {
std::shared_lock<std::shared_timed_mutex>(m_Mutex);
auto skill = m_Factory.UpdateReloadingState(
m_Skills[skillId],
false
);
UpdateSkill(skill);
});
m_CastingTimers.StartTimer(skill.skillId, skillInfo[2], [this] (uint32_t skillId) {
std::shared_lock<std::shared_timed_mutex>(m_Mutex);
auto skill = m_Factory.UpdateCastingState(
m_Skills[m_UsedSkillId],
false
);
UpdateSkill(skill);
});
}
}
void OnSkillCancelled(const Event& evt)
{
std::shared_lock<std::shared_timed_mutex>(m_Mutex);
if (evt.GetName() == SkillCancelledEvent::name)
{
const auto casted = static_cast<const SkillCancelledEvent&>(evt);
const auto hero = m_NetworkHandler.GetHero();
if (hero && hero->objectId == casted.GetInitiatorId())
{
if (m_Skills.find(m_UsedSkillId) == m_Skills.end())
{
//todo exception?
return;
}
auto skill = m_Factory.UpdateCastingState(
m_Skills[m_UsedSkillId],
false
);
UpdateSkill(skill);
m_UsedSkillId = 0;
m_CastingTimers.StopTimer(skill.skillId);
}
}
}
void OnSkillToggled(const Event& evt)
{
std::shared_lock<std::shared_timed_mutex>(m_Mutex);
if (evt.GetName() == AbnormalEffectChangedEvent::name)
{
const auto casted = static_cast<const AbnormalEffectChangedEvent&>(evt);
const auto skillInfo = casted.GetSkillInfo();
std::map<uint32_t, int32_t> ids;
for (size_t i = 0; i < skillInfo.size(); i += 3)
{
ids[skillInfo[i]] = skillInfo[i + 2];
}
for (auto it = m_Skills.begin(); it != m_Skills.end();)
{
const auto needToToggle = ids.find(it->second.skillId) != ids.end();
// buff time less than zero means this is a aura
const auto isAura = needToToggle ? ids[it->second.skillId] < 0 : false;
if (it->second.isToggled && !needToToggle)
{
auto skill = m_Factory.UpdateToggle(it->second, false);
it = m_Skills.erase(it);
m_Skills.emplace(skill.skillId, skill);
}
else if (!it->second.isToggled && needToToggle && isAura)
{
auto skill = m_Factory.UpdateToggle(it->second, true);
it = m_Skills.erase(it);
m_Skills.emplace(skill.skillId, skill);
}
else
{
++it;
}
}
}
}
private:
void UpdateSkill(const DTO::Skill skill)
{
m_Skills.erase(skill.skillId);
m_Skills.emplace(skill.skillId, skill);
}
private:
const SkillFactory& m_Factory;
std::map<uint32_t, DTO::Skill> m_Skills;
uint32_t m_UsedSkillId = 0;
const NetworkHandlerWrapper& m_NetworkHandler;
TimerMap m_ReloadingTimers;
TimerMap m_CastingTimers;
std::shared_timed_mutex m_Mutex;
};
}

View File

@@ -0,0 +1,15 @@
#include "pch.h"
#include "VersionAbstractFactory.h"
#include "Interlude/AbstractFactory.h"
const VersionAbstractFactory& VersionAbstractFactory::GetFactory(const Version version, const uint16_t radius)
{
switch (version)
{
case Version::interlude:
static Interlude::AbstractFactory interlude = Interlude::AbstractFactory(radius);
return interlude;
}
//todo throw exception
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include "Domain/Repositories/HeroRepositoryInterface.h"
#include "Domain/Repositories/DropRepositoryInterface.h"
#include "Domain/Repositories/NPCRepositoryInterface.h"
#include "Domain/Repositories/PlayerRepositoryInterface.h"
#include "Domain/Repositories/SkillRepositoryInterface.h"
#include "GameStructs/NetworkHandlerInterface.h"
#include "GameStructs/GameEngineInterface.h"
#include "GameStructs/L2GameDataInterface.h"
#include "GameStructs/FNameInterface.h"
using namespace L2Bot::Domain;
class VersionAbstractFactory
{
public:
enum class Version
{
interlude
};
virtual Repositories::HeroRepositoryInterface& GetHeroRepository() const = 0;
virtual Repositories::DropRepositoryInterface& GetDropRepository() const = 0;
virtual Repositories::NPCRepositoryInterface& GetNPCRepository() const = 0;
virtual Repositories::PlayerRepositoryInterface& GetPlayerRepository() const = 0;
virtual Repositories::SkillRepositoryInterface& GetSkillRepository() const = 0;
virtual NetworkHandlerInterface& GetNetworkHandler() const = 0;
virtual GameEngineInterface& GetGameEngine() const = 0;
virtual L2GameDataInterface& GetL2GameData() const = 0;
virtual FNameInterface& GetFName() const = 0;
static const VersionAbstractFactory& GetFactory(Version version, const uint16_t radius);
};