From 43f38c7a57cef7498a636325a5b4c19f4e76e538 Mon Sep 17 00:00:00 2001 From: k0t9i Date: Tue, 24 Jan 2023 02:49:35 +0400 Subject: [PATCH] feat: add base item --- .../{ValueObjects => Entities}/BaseItem.h | 65 +++++---- L2BotCore/Domain/Entities/Skill.h | 2 +- L2BotCore/L2BotCore.vcxproj | 2 +- L2BotCore/L2BotCore.vcxproj.filters | 2 +- L2BotDll/Application.h | 1 + L2BotDll/DTO/ItemData.h | 12 ++ L2BotDll/Events/ItemCreatedEvent.h | 34 +++++ L2BotDll/Events/ItemDeletedEvent.h | 34 +++++ L2BotDll/Events/ItemUpdatedEvent.h | 34 +++++ L2BotDll/L2BotDll.vcxproj | 6 + L2BotDll/L2BotDll.vcxproj.filters | 18 +++ L2BotDll/Services/WorldHandler.h | 9 +- L2BotDll/Versions/Interlude/AbstractFactory.h | 13 ++ .../Interlude/Factories/ItemFactory.h | 53 +++++++ .../Interlude/Factories/SkillFactory.h | 4 +- .../GameStructs/GameEngineWrapper.cpp | 58 ++++++++ .../Interlude/GameStructs/GameEngineWrapper.h | 5 + .../Interlude/GameStructs/GameStructs.h | 7 + .../Interlude/Repositories/ItemRepository.h | 134 ++++++++++++++++++ L2BotDll/Versions/VersionAbstractFactory.h | 1 + 20 files changed, 461 insertions(+), 33 deletions(-) rename L2BotCore/Domain/{ValueObjects => Entities}/BaseItem.h (63%) create mode 100644 L2BotDll/DTO/ItemData.h create mode 100644 L2BotDll/Events/ItemCreatedEvent.h create mode 100644 L2BotDll/Events/ItemDeletedEvent.h create mode 100644 L2BotDll/Events/ItemUpdatedEvent.h create mode 100644 L2BotDll/Versions/Interlude/Factories/ItemFactory.h create mode 100644 L2BotDll/Versions/Interlude/Repositories/ItemRepository.h diff --git a/L2BotCore/Domain/ValueObjects/BaseItem.h b/L2BotCore/Domain/Entities/BaseItem.h similarity index 63% rename from L2BotCore/Domain/ValueObjects/BaseItem.h rename to L2BotCore/Domain/Entities/BaseItem.h index cc25dc9..e17ee20 100644 --- a/L2BotCore/Domain/ValueObjects/BaseItem.h +++ b/L2BotCore/Domain/Entities/BaseItem.h @@ -2,34 +2,33 @@ #include #include #include -#include "../DTO/BaseItem.h" -#include "../Serializers/Serializable.h" -#include "../Serializers/Node.h" +#include "EntityInterface.h" -namespace L2Bot::Domain::ValueObjects +namespace L2Bot::Domain::Entities { - class BaseItem : public Serializers::Serializable + class BaseItem : public EntityInterface { public: const uint32_t GetId() const { return m_ItemId; } - void Update(const BaseItem* other) + void Update(const EntityInterface* other) override { + const BaseItem* casted = static_cast(other); SaveState(); - m_ItemId = other->m_ItemId; - m_Amount = other->m_Amount; - m_IsEquipped = other->m_IsEquipped; - m_EnchantLevel = other->m_EnchantLevel; - m_Mana = other->m_Mana; - m_Name = other->m_Name; - m_IconName = other->m_IconName; - m_Description = other->m_Description; - m_Weight = other->m_Weight; + m_ItemId = casted->m_ItemId; + m_Amount = casted->m_Amount; + m_IsEquipped = casted->m_IsEquipped; + m_EnchantLevel = casted->m_EnchantLevel; + m_Mana = casted->m_Mana; + m_Name = casted->m_Name; + m_IconName = casted->m_IconName; + m_Description = casted->m_Description; + m_Weight = casted->m_Weight; } - void SaveState() + void SaveState() override { m_PrevState = { @@ -41,17 +40,18 @@ namespace L2Bot::Domain::ValueObjects false }; } - const bool IsEqual(const BaseItem* other) const + const bool IsEqual(const EntityInterface* other) const override { - return m_ItemId == other->m_ItemId && - m_Amount == other->m_Amount && - m_IsEquipped == other->m_IsEquipped && - m_EnchantLevel == other->m_EnchantLevel && - m_Mana == other->m_Mana && - m_Name == other->m_Name && - m_IconName == other->m_IconName && - m_Description == other->m_Description && - m_Weight == other->m_Weight; + const BaseItem* casted = static_cast(other); + return m_ItemId == casted->m_ItemId && + m_Amount == casted->m_Amount && + m_IsEquipped == casted->m_IsEquipped && + m_EnchantLevel == casted->m_EnchantLevel && + m_Mana == casted->m_Mana && + m_Name == casted->m_Name && + m_IconName == casted->m_IconName && + m_Description == casted->m_Description && + m_Weight == casted->m_Weight; } const std::vector BuildSerializationNodes() const override @@ -114,6 +114,19 @@ namespace L2Bot::Domain::ValueObjects { } + BaseItem(const BaseItem* other) : + m_ItemId(other->m_ItemId), + m_Amount(other->m_Amount), + m_IsEquipped(other->m_IsEquipped), + m_EnchantLevel(other->m_EnchantLevel), + m_Mana(other->m_Mana), + m_Name(other->m_Name), + m_IconName(other->m_IconName), + m_Description(other->m_Description), + m_Weight(other->m_Weight) + { + } + BaseItem() = default; virtual ~BaseItem() = default; diff --git a/L2BotCore/Domain/Entities/Skill.h b/L2BotCore/Domain/Entities/Skill.h index d268d13..6fe5d7d 100644 --- a/L2BotCore/Domain/Entities/Skill.h +++ b/L2BotCore/Domain/Entities/Skill.h @@ -2,7 +2,7 @@ #include #include #include -#include "WorldObject.h" +#include "EntityInterface.h" namespace L2Bot::Domain::Entities { diff --git a/L2BotCore/L2BotCore.vcxproj b/L2BotCore/L2BotCore.vcxproj index 6934955..b82719a 100644 --- a/L2BotCore/L2BotCore.vcxproj +++ b/L2BotCore/L2BotCore.vcxproj @@ -161,7 +161,7 @@ - + diff --git a/L2BotCore/L2BotCore.vcxproj.filters b/L2BotCore/L2BotCore.vcxproj.filters index 1f5b15d..04977fa 100644 --- a/L2BotCore/L2BotCore.vcxproj.filters +++ b/L2BotCore/L2BotCore.vcxproj.filters @@ -102,7 +102,7 @@ Header Files - + Header Files diff --git a/L2BotDll/Application.h b/L2BotDll/Application.h index 43e6aee..1e655fe 100644 --- a/L2BotDll/Application.h +++ b/L2BotDll/Application.h @@ -24,6 +24,7 @@ public: m_AbstractFactory.GetNPCRepository(), m_AbstractFactory.GetPlayerRepository(), m_AbstractFactory.GetSkillRepository(), + m_AbstractFactory.GetItemRepository(), m_Serializer, m_Transport ) diff --git a/L2BotDll/DTO/ItemData.h b/L2BotDll/DTO/ItemData.h new file mode 100644 index 0000000..0839051 --- /dev/null +++ b/L2BotDll/DTO/ItemData.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +struct ItemData +{ + const uint32_t itemId = 0; + const uint32_t amount = 0; + const uint16_t isEquipped = 0; + const uint16_t enchantLevel = 0; + const int32_t mana = -1; +}; \ No newline at end of file diff --git a/L2BotDll/Events/ItemCreatedEvent.h b/L2BotDll/Events/ItemCreatedEvent.h new file mode 100644 index 0000000..c6833d1 --- /dev/null +++ b/L2BotDll/Events/ItemCreatedEvent.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include "Event.h" +#include "../DTO/ItemData.h" + +class ItemCreatedEvent : public Event +{ +public: + static constexpr const char* name = "itemCreated"; + + const std::string GetName() const + { + return std::string(name); + } + + const ItemData& GetItemData() const + { + return m_ItemData; + } + + ItemCreatedEvent(const ItemData& itemData) : + m_ItemData(itemData) + { + + } + + ItemCreatedEvent() = delete; + virtual ~ItemCreatedEvent() = default; + +private: + const ItemData m_ItemData; +}; \ No newline at end of file diff --git a/L2BotDll/Events/ItemDeletedEvent.h b/L2BotDll/Events/ItemDeletedEvent.h new file mode 100644 index 0000000..2c19db0 --- /dev/null +++ b/L2BotDll/Events/ItemDeletedEvent.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include "Event.h" +#include "../DTO/ItemData.h" + +class ItemDeletedEvent : public Event +{ +public: + static constexpr const char* name = "itemDeleted"; + + const std::string GetName() const + { + return std::string(name); + } + + const uint32_t GetItemId() const + { + return m_Id; + } + + ItemDeletedEvent(const uint32_t id) : + m_Id(id) + { + + } + + ItemDeletedEvent() = delete; + virtual ~ItemDeletedEvent() = default; + +private: + const uint32_t m_Id; +}; \ No newline at end of file diff --git a/L2BotDll/Events/ItemUpdatedEvent.h b/L2BotDll/Events/ItemUpdatedEvent.h new file mode 100644 index 0000000..a4fa7df --- /dev/null +++ b/L2BotDll/Events/ItemUpdatedEvent.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include "Event.h" +#include "../DTO/ItemData.h" + +class ItemUpdatedEvent : public Event +{ +public: + static constexpr const char* name = "itemUpdated"; + + const std::string GetName() const + { + return std::string(name); + } + + const ItemData& GetItemData() const + { + return m_ItemData; + } + + ItemUpdatedEvent(const ItemData& itemData) : + m_ItemData(itemData) + { + + } + + ItemUpdatedEvent() = delete; + virtual ~ItemUpdatedEvent() = default; + +private: + const ItemData m_ItemData; +}; \ No newline at end of file diff --git a/L2BotDll/L2BotDll.vcxproj b/L2BotDll/L2BotDll.vcxproj index c2c4f74..88ef23b 100644 --- a/L2BotDll/L2BotDll.vcxproj +++ b/L2BotDll/L2BotDll.vcxproj @@ -164,11 +164,15 @@ + + + + @@ -182,6 +186,7 @@ + @@ -203,6 +208,7 @@ + diff --git a/L2BotDll/L2BotDll.vcxproj.filters b/L2BotDll/L2BotDll.vcxproj.filters index 84d3089..e236d77 100644 --- a/L2BotDll/L2BotDll.vcxproj.filters +++ b/L2BotDll/L2BotDll.vcxproj.filters @@ -153,6 +153,24 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + diff --git a/L2BotDll/Services/WorldHandler.h b/L2BotDll/Services/WorldHandler.h index 6f35e33..d37a63a 100644 --- a/L2BotDll/Services/WorldHandler.h +++ b/L2BotDll/Services/WorldHandler.h @@ -21,6 +21,7 @@ public: Repositories::EntityRepositoryInterface& npcRepository, Repositories::EntityRepositoryInterface& playerRepository, Repositories::EntityRepositoryInterface& skillRepository, + Repositories::EntityRepositoryInterface& itemRepository, const Serializers::SerializerInterface& serializer, Transports::TransportInterface& transport ) : @@ -29,6 +30,7 @@ public: m_NPCService(Services::EntityService(npcRepository)), m_PlayerService(Services::EntityService(playerRepository)), m_SkillService(Services::EntityService(skillRepository)), + m_ItemService(Services::EntityService(itemRepository)), m_Serializer(serializer), m_Transport(transport) { @@ -117,11 +119,12 @@ private: { std::vector items { - Serializers::SerializableStateContainer{m_HeroService.GetEntities(), "hero"}, + /*Serializers::SerializableStateContainer{m_HeroService.GetEntities(), "hero"}, Serializers::SerializableStateContainer{m_DropService.GetEntities(), "drop"}, Serializers::SerializableStateContainer{m_NPCService.GetEntities(), "npc"}, Serializers::SerializableStateContainer{m_PlayerService.GetEntities(), "player"}, - Serializers::SerializableStateContainer{m_SkillService.GetEntities(), "skill"}, + Serializers::SerializableStateContainer{m_SkillService.GetEntities(), "skill"},*/ + Serializers::SerializableStateContainer{m_ItemService.GetEntities(), "item"}, }; std::vector result; @@ -143,6 +146,7 @@ private: m_NPCService.Invalidate(); m_PlayerService.Invalidate(); m_SkillService.Invalidate(); + m_ItemService.Invalidate(); } private: @@ -151,6 +155,7 @@ private: Services::EntityService m_NPCService; Services::EntityService m_PlayerService; Services::EntityService m_SkillService; + Services::EntityService m_ItemService; const Serializers::SerializerInterface& m_Serializer; Transports::TransportInterface& m_Transport; bool m_Stopped = false; diff --git a/L2BotDll/Versions/Interlude/AbstractFactory.h b/L2BotDll/Versions/Interlude/AbstractFactory.h index 496ad72..dd9c7b1 100644 --- a/L2BotDll/Versions/Interlude/AbstractFactory.h +++ b/L2BotDll/Versions/Interlude/AbstractFactory.h @@ -6,11 +6,13 @@ #include "Factories/NPCFactory.h" #include "Factories/PlayerFactory.h" #include "Factories/SkillFactory.h" +#include "Factories/ItemFactory.h" #include "Repositories/DropRepository.h" #include "Repositories/HeroRepository.h" #include "Repositories/NPCRepository.h" #include "Repositories/PlayerRepository.h" #include "Repositories/SkillRepository.h" +#include "Repositories/ItemRepository.h" #include "GameStructs/NetworkHandlerWrapper.h" #include "GameStructs/GameEngineWrapper.h" #include "GameStructs/L2GameDataWrapper.h" @@ -88,6 +90,17 @@ namespace Interlude ); return result; } + ItemRepository& GetItemRepository() const override + { + static auto factory = ItemFactory(GetL2GameData(), GetFName()); + static EntityHandler handler; + static auto result = ItemRepository( + GetNetworkHandler(), + factory, + handler + ); + return result; + } NetworkHandlerWrapper& GetNetworkHandler() const override { static NetworkHandlerWrapper result; diff --git a/L2BotDll/Versions/Interlude/Factories/ItemFactory.h b/L2BotDll/Versions/Interlude/Factories/ItemFactory.h new file mode 100644 index 0000000..a6221ea --- /dev/null +++ b/L2BotDll/Versions/Interlude/Factories/ItemFactory.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include +#include "../GameStructs/L2GameDataWrapper.h" +#include "../GameStructs/FName.h" +#include "../../../Common/Common.h" +#include "Domain/Entities/BaseItem.h" +#include "../../../DTO/ItemData.h" + +using namespace L2Bot::Domain; + +namespace Interlude +{ + class ItemFactory + { + public: + ItemFactory(const L2GameDataWrapper& l2GameData, const FName& fName) : + m_L2GameData(l2GameData), + m_FName(fName) + { + } + + ItemFactory() = delete; + virtual ~ItemFactory() = default; + + std::unique_ptr Create(const ItemData& itemInfo) const + { + const auto data = m_L2GameData.GetItemData(itemInfo.itemId); + + const auto nameEntry = data ? m_FName.GetEntry(data->nameIndex) : nullptr; + const auto iconEntry = data ? m_FName.GetEntry(data->iconNameIndex) : nullptr; + const auto description = data && data->description ? data->description : L""; + + return std::make_unique( + itemInfo.itemId, + itemInfo.amount, + itemInfo.isEquipped > 0, + itemInfo.enchantLevel, + itemInfo.mana, + nameEntry ? ConvertFromWideChar(nameEntry->value) : "", + iconEntry ? ConvertFromWideChar(iconEntry->value) : "", + ConvertFromWideChar(description), + data ? data->weight : 0 + ); + } + + private: + const L2GameDataWrapper& m_L2GameData; + const FName& m_FName; + }; +} \ No newline at end of file diff --git a/L2BotDll/Versions/Interlude/Factories/SkillFactory.h b/L2BotDll/Versions/Interlude/Factories/SkillFactory.h index 7d76bdf..d93805d 100644 --- a/L2BotDll/Versions/Interlude/Factories/SkillFactory.h +++ b/L2BotDll/Versions/Interlude/Factories/SkillFactory.h @@ -30,8 +30,8 @@ namespace Interlude 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 name = data && data->name ? data->name : L""; + const auto description = data && data->description ? data->description : L""; const auto iconEntry = data ? m_FName.GetEntry(data->iconNameIndex) : nullptr; return std::make_unique( diff --git a/L2BotDll/Versions/Interlude/GameStructs/GameEngineWrapper.cpp b/L2BotDll/Versions/Interlude/GameStructs/GameEngineWrapper.cpp index 0b40151..442430d 100644 --- a/L2BotDll/Versions/Interlude/GameStructs/GameEngineWrapper.cpp +++ b/L2BotDll/Versions/Interlude/GameStructs/GameEngineWrapper.cpp @@ -7,6 +7,10 @@ #include "../../../Events/SkillCancelledEvent.h" #include "../../../Events/AbnormalEffectChangedEvent.h" #include "../../../Events/EventDispatcher.h" +#include "../../../Events/ItemCreatedEvent.h" +#include "../../../Events/ItemUpdatedEvent.h" +#include "../../../Events/ItemDeletedEvent.h" +#include "../../../DTO/ItemData.h" namespace Interlude { @@ -18,6 +22,8 @@ namespace Interlude int(__thiscall* GameEngineWrapper::__OnReceiveMagicSkillUse)(GameEngine*, User*, User*, L2ParamStack&) = 0; void(__thiscall* GameEngineWrapper::__OnReceiveMagicSkillCanceled)(GameEngine*, User*) = 0; void(__thiscall* GameEngineWrapper::__AddAbnormalStatus)(GameEngine*, L2ParamStack&) = 0; + void(__thiscall* GameEngineWrapper::__AddInventoryItem)(GameEngine*, ItemInfo&) = 0; + void(__thiscall* GameEngineWrapper::__OnReceiveUpdateItemList)(GameEngine*, UpdateItemListActionType, ItemInfo&) = 0; void GameEngineWrapper::Init(HMODULE hModule) @@ -38,6 +44,12 @@ namespace Interlude (FARPROC&)__AddAbnormalStatus = (FARPROC)splice( GetProcAddress(hModule, "?AddAbnormalStatus@UGameEngine@@UAEXAAVL2ParamStack@@@Z"), __AddAbnormalStatus_hook ); + (FARPROC&)__AddInventoryItem = (FARPROC)splice( + GetProcAddress(hModule, "?AddInventoryItem@UGameEngine@@UAEXAAUItemInfo@@@Z"), __AddInventoryItem_hook + ); + (FARPROC&)__OnReceiveUpdateItemList = (FARPROC)splice( + GetProcAddress(hModule, "?OnReceiveUpdateItemList@UGameEngine@@UAEXHAAUItemInfo@@@Z"), __OnReceiveUpdateItemList_hook + ); } void GameEngineWrapper::Restore() @@ -47,6 +59,8 @@ namespace Interlude restore((void*&)__OnReceiveMagicSkillUse); restore((void*&)__OnReceiveMagicSkillCanceled); restore((void*&)__AddAbnormalStatus); + restore((void*&)__AddInventoryItem); + restore((void*&)__OnReceiveUpdateItemList); } void __fastcall GameEngineWrapper::__Init_hook(GameEngine* This, uint32_t /*edx*/, float_t unk) @@ -85,4 +99,48 @@ namespace Interlude EventDispatcher::GetInstance().Dispatch(AbnormalEffectChangedEvent{ stack.GetBufferAsVector(3) }); (*__AddAbnormalStatus)(This, stack); } + + void __fastcall GameEngineWrapper::__AddInventoryItem_hook(GameEngine* This, int, ItemInfo& itemInfo) + { + EventDispatcher::GetInstance().Dispatch( + ItemCreatedEvent + { + ItemData + { + itemInfo.itemId, + itemInfo.amount, + itemInfo.isEquipped, + itemInfo.enchantLevel, + itemInfo.mana, + } + } + ); + (*__AddInventoryItem)(This, itemInfo); + } + + void __fastcall GameEngineWrapper::__OnReceiveUpdateItemList_hook(GameEngine* This, int, UpdateItemListActionType actionType, ItemInfo& itemInfo) + { + const ItemData itemData + { + itemInfo.itemId, + itemInfo.amount, + itemInfo.isEquipped, + itemInfo.enchantLevel, + itemInfo.mana, + }; + + switch (actionType) + { + case UpdateItemListActionType::created: + EventDispatcher::GetInstance().Dispatch(ItemCreatedEvent{ itemData }); + break; + case UpdateItemListActionType::updated: + EventDispatcher::GetInstance().Dispatch(ItemUpdatedEvent{ itemData }); + break; + case UpdateItemListActionType::deleted: + EventDispatcher::GetInstance().Dispatch(ItemDeletedEvent{ itemInfo.itemId }); + break; + } + (*__OnReceiveUpdateItemList)(This, actionType, itemInfo); + } } \ No newline at end of file diff --git a/L2BotDll/Versions/Interlude/GameStructs/GameEngineWrapper.h b/L2BotDll/Versions/Interlude/GameStructs/GameEngineWrapper.h index 8572159..63d0774 100644 --- a/L2BotDll/Versions/Interlude/GameStructs/GameEngineWrapper.h +++ b/L2BotDll/Versions/Interlude/GameStructs/GameEngineWrapper.h @@ -24,12 +24,17 @@ namespace Interlude static int(__thiscall* __OnReceiveMagicSkillUse)(GameEngine*, User*, User*, L2ParamStack&); static void(__thiscall* __OnReceiveMagicSkillCanceled)(GameEngine*, User*); static void(__thiscall* __AddAbnormalStatus)(GameEngine*, L2ParamStack&); + static void(__thiscall* __AddInventoryItem)(GameEngine*, ItemInfo&); + static void(__thiscall* __OnReceiveUpdateItemList)(GameEngine*, UpdateItemListActionType, ItemInfo&); 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); + static void __fastcall __AddInventoryItem_hook(GameEngine* This, int /*edx*/, ItemInfo& itemInfo); + static void __fastcall __OnReceiveUpdateItemList_hook(GameEngine* This, int /*edx*/, UpdateItemListActionType actionType, ItemInfo& itemInfo); + private: static void* originalInitAddress; static GameEngine* _target; diff --git a/L2BotDll/Versions/Interlude/GameStructs/GameStructs.h b/L2BotDll/Versions/Interlude/GameStructs/GameStructs.h index e74f17a..1b6b0a7 100644 --- a/L2BotDll/Versions/Interlude/GameStructs/GameStructs.h +++ b/L2BotDll/Versions/Interlude/GameStructs/GameStructs.h @@ -255,4 +255,11 @@ namespace Interlude int32_t iconNameIndex; //0x0048 char pad_004C[52]; //0x004C }; //Size: 0x0080 + + enum class UpdateItemListActionType : uint32_t + { + created = 1, + updated, + deleted + }; }; diff --git a/L2BotDll/Versions/Interlude/Repositories/ItemRepository.h b/L2BotDll/Versions/Interlude/Repositories/ItemRepository.h new file mode 100644 index 0000000..0b77ca2 --- /dev/null +++ b/L2BotDll/Versions/Interlude/Repositories/ItemRepository.h @@ -0,0 +1,134 @@ +#pragma once + +#include +#include +#include +#include "Domain/Repositories/EntityRepositoryInterface.h" +#include "../Factories/ItemFactory.h" +#include "../GameStructs/NetworkHandlerWrapper.h" +#include "../../../Services/EntityHandler.h" +#include "../../../Events/ItemCreatedEvent.h" +#include "../../../Events/ItemUpdatedEvent.h" +#include "../../../Events/ItemDeletedEvent.h" +#include "../../../Events/EventDispatcher.h" + +using namespace L2Bot::Domain; + +namespace Interlude +{ + class ItemRepository : public Repositories::EntityRepositoryInterface + { + public: + const std::vector> GetEntities() override + { + std::unique_lock(m_Mutex); + + std::map itemPtrs; + for (const auto& kvp : m_Items) + { + itemPtrs[kvp.first] = kvp.second.get(); + } + + const auto objects = m_EntityHandler.GetEntities(itemPtrs, [this](Entities::BaseItem* item) { + return std::make_unique(item); + }); + + auto result = std::vector>(); + + for (const auto kvp : objects) + { + result.push_back(kvp.second); + } + + return result; + } + + ItemRepository(const NetworkHandlerWrapper& networkHandler, const ItemFactory& factory, EntityHandler& handler) : + m_NetworkHandler(networkHandler), + m_Factory(factory), + m_EntityHandler(handler) + { + EventDispatcher::GetInstance().Subscribe(ItemCreatedEvent::name, [this](const Event& evt) { + OnItemCreated(evt); + }); + EventDispatcher::GetInstance().Subscribe(ItemUpdatedEvent::name, [this](const Event& evt) { + OnItemUpdated(evt); + }); + EventDispatcher::GetInstance().Subscribe(ItemDeletedEvent::name, [this](const Event& evt) { + OnItemDeleted(evt); + }); + } + + void OnItemCreated(const Event& evt) + { + std::shared_lock(m_Mutex); + if (evt.GetName() == ItemCreatedEvent::name) + { + const auto casted = static_cast(evt); + const auto& data = casted.GetItemData(); + + auto item = m_Factory.Create(data); + if (m_Items.find(data.itemId) == m_Items.end()) + { + m_Items.emplace(data.itemId, std::move(item)); + } + else + { + // When equip/unequip accessories + m_Items[data.itemId]->Update(item.get()); + } + } + } + + void OnItemUpdated(const Event& evt) + { + std::shared_lock(m_Mutex); + if (evt.GetName() == ItemUpdatedEvent::name) + { + const auto casted = static_cast(evt); + const auto& data = casted.GetItemData(); + + //todo exception? + if (m_Items.find(data.itemId) == m_Items.end()) + { + return; + } + + auto item = m_Factory.Create(data); + m_Items[data.itemId]->Update(item.get()); + } + } + + void OnItemDeleted(const Event& evt) + { + //fixme may be a race condition + std::shared_lock(m_Mutex); + if (evt.GetName() == ItemDeletedEvent::name) + { + const auto casted = static_cast(evt); + + m_Items.erase(casted.GetItemId()); + } + } + + ItemRepository() = delete; + virtual ~ItemRepository() + { + Reset(); + } + + void Reset() override + { + std::shared_lock(m_Mutex); + m_Items.clear(); + } + + private: + const ItemFactory& m_Factory; + std::map> m_Items; + uint32_t m_UsedSkillId = 0; + const NetworkHandlerWrapper& m_NetworkHandler; + std::shared_timed_mutex m_Mutex; + EntityHandler& m_EntityHandler; + }; +} \ No newline at end of file diff --git a/L2BotDll/Versions/VersionAbstractFactory.h b/L2BotDll/Versions/VersionAbstractFactory.h index da94b11..6bd7bd4 100644 --- a/L2BotDll/Versions/VersionAbstractFactory.h +++ b/L2BotDll/Versions/VersionAbstractFactory.h @@ -21,6 +21,7 @@ public: virtual Repositories::EntityRepositoryInterface& GetNPCRepository() const = 0; virtual Repositories::EntityRepositoryInterface& GetPlayerRepository() const = 0; virtual Repositories::EntityRepositoryInterface& GetSkillRepository() const = 0; + virtual Repositories::EntityRepositoryInterface& GetItemRepository() const = 0; virtual NetworkHandlerInterface& GetNetworkHandler() const = 0; virtual GameEngineInterface& GetGameEngine() const = 0; virtual L2GameDataInterface& GetL2GameData() const = 0;