From 3d70678cc3c8d0944da8124da8e7ca347692c036 Mon Sep 17 00:00:00 2001 From: Zach Toogood Date: Thu, 12 Aug 2021 09:29:34 +0300 Subject: [PATCH] [core] Start on dummy char system --- src/map/entities/CMakeLists.txt | 2 + src/map/entities/charentity.h | 19 ++++---- src/map/entities/dummyentity.cpp | 74 ++++++++++++++++++++++++++++++++ src/map/entities/dummyentity.h | 54 +++++++++++++++++++++++ src/map/lua/lua_baseentity.cpp | 24 +++++++++++ src/map/lua/lua_baseentity.h | 2 + src/map/utils/CMakeLists.txt | 2 + src/map/utils/testutils.cpp | 69 +++++++++++++++++++++++++++++ src/map/utils/testutils.h | 14 ++++++ 9 files changed, 251 insertions(+), 9 deletions(-) create mode 100644 src/map/entities/dummyentity.cpp create mode 100644 src/map/entities/dummyentity.h create mode 100644 src/map/utils/testutils.cpp create mode 100644 src/map/utils/testutils.h diff --git a/src/map/entities/CMakeLists.txt b/src/map/entities/CMakeLists.txt index 4e56d272c3f..ba3965500c1 100644 --- a/src/map/entities/CMakeLists.txt +++ b/src/map/entities/CMakeLists.txt @@ -7,6 +7,8 @@ set(SOURCES battleentity.h charentity.cpp charentity.h + dummyentity.cpp + dummyentity.h mobentity.cpp mobentity.h npcentity.cpp diff --git a/src/map/entities/charentity.h b/src/map/entities/charentity.h index 5c40f6d05c0..d7fdfb3f309 100644 --- a/src/map/entities/charentity.h +++ b/src/map/entities/charentity.h @@ -310,15 +310,16 @@ class CCharEntity : public CBattleEntity uint8 GetGender(); // узнаем пол персонажа - void clearPacketList(); // отчистка PacketList - void pushPacket(CBasicPacket*); // добавление копии пакета в PacketList - void pushPacket(std::unique_ptr); // push packet to packet list - bool isPacketListEmpty(); // проверка размера PacketList - CBasicPacket* popPacket(); // получение первого пакета из PacketList - PacketList_t getPacketList(); // returns a COPY of packet list - size_t getPacketCount(); - void erasePackets(uint8 num); // erase num elements from front of packet list - virtual void HandleErrorMessage(std::unique_ptr&) override; + virtual void clearPacketList(); // отчистка PacketList + virtual void pushPacket(CBasicPacket*); // добавление копии пакета в PacketList + virtual void pushPacket(std::unique_ptr); // push packet to packet list + virtual bool isPacketListEmpty(); // проверка размера PacketList + virtual auto popPacket() -> CBasicPacket*; // получение первого пакета из PacketList + virtual auto getPacketList() -> PacketList_t; // returns a COPY of packet list + virtual auto getPacketCount() -> size_t; + virtual void erasePackets(uint8 num); // erase num elements from front of packet list + + virtual void HandleErrorMessage(std::unique_ptr&) override; CLinkshell* PLinkshell1; // linkshell, в которой общается персонаж CLinkshell* PLinkshell2; // linkshell 2 diff --git a/src/map/entities/dummyentity.cpp b/src/map/entities/dummyentity.cpp new file mode 100644 index 00000000000..881cbec4955 --- /dev/null +++ b/src/map/entities/dummyentity.cpp @@ -0,0 +1,74 @@ +#include "dummyentity.h" + +#include "../../common/logging.h" +#include "../../common/timer.h" +#include "../../common/utils.h" + +#include "../ai/ai_container.h" +#include "../ai/controllers/player_charm_controller.h" + +#include "../packets/char.h" +#include "../packets/char_update.h" +#include "../packets/char_health.h" + +#include + +CDummyEntity::CDummyEntity(CCharEntity* PChar) +: CCharEntity() +, PathFind(std::make_unique(this)) +{ + targetLocation = PChar->loc.p; +} + +CDummyEntity::~CDummyEntity() +{ +} + +void CDummyEntity::Tick(time_point tick) +{ + // Move + if (distance(this->loc.p, targetLocation) < 2.0f) + { + targetLocation = this->loc.zone->m_navMesh->findRandomPosition(this->loc.p, 20.0f).second; + } + else + { + if (!PathFind->IsFollowingPath()) + { + PathFind->PathTo(targetLocation, PATHFLAG_RUN, false); + } + PathFind->FollowPath(); + } + + // Build update mask + if (m_previousLocation.p.x != loc.p.x || + m_previousLocation.p.y != loc.p.y || + m_previousLocation.p.z != loc.p.z) + { + updatemask |= UPDATE_POS; + } + + // Cache info + m_previousLocation = loc; +}; + +void CDummyEntity::PostTick() +{ + if (updatemask) + { + if (loc.zone && !m_isGMHidden) + { + loc.zone->PushPacket(this, CHAR_INRANGE, new CCharPacket(this, ENTITY_UPDATE, updatemask)); + } + if (updatemask & UPDATE_HP) + { + ForAlliance([&](auto PEntity) { + if (PEntity->objtype == TYPE_PC) + { + static_cast(PEntity)->pushPacket(new CCharHealthPacket(this)); + } + }); + } + updatemask = 0; + } +} \ No newline at end of file diff --git a/src/map/entities/dummyentity.h b/src/map/entities/dummyentity.h new file mode 100644 index 00000000000..f542f8a7e70 --- /dev/null +++ b/src/map/entities/dummyentity.h @@ -0,0 +1,54 @@ +#ifndef _CHARDUMMYENTITY_H +#define _CHARDUMMYENTITY_H + +#include "../../common/cbasetypes.h" +#include "../../common/mmo.h" + +#include "charentity.h" + +#include "../ai/helpers/pathfind.h" + +#include +#include +#include +#include +#include + +class CDummyEntity : public CCharEntity +{ +public: + CDummyEntity(CCharEntity* PChar); + ~CDummyEntity(); + + void Tick(time_point tick) override; + void PostTick() override; + + position_t targetLocation; + std::unique_ptr PathFind; + + // All packet operations should be NOOP + void clearPacketList() override{}; + void pushPacket(CBasicPacket* packet) override + { + delete packet; + }; + bool isPacketListEmpty() override + { + return true; + }; + auto popPacket() -> CBasicPacket* override + { + return nullptr; + }; + auto getPacketList() -> PacketList_t override + { + return {}; + }; + auto getPacketCount() -> size_t override + { + return 0; + }; + void erasePackets(uint8 num) override{}; +}; + +#endif diff --git a/src/map/lua/lua_baseentity.cpp b/src/map/lua/lua_baseentity.cpp index 9d4d9302444..22b9f3b5bd0 100644 --- a/src/map/lua/lua_baseentity.cpp +++ b/src/map/lua/lua_baseentity.cpp @@ -158,6 +158,7 @@ #include "../utils/mobutils.h" #include "../utils/petutils.h" #include "../utils/puppetutils.h" +#include "../utils/testutils.h" #include "../utils/trustutils.h" #include "../utils/zoneutils.h" @@ -13006,6 +13007,26 @@ uint32 CLuaBaseEntity::getHistory(uint8 index) return outStat; } +/************************************************************************ + * Function: clone() + * Purpose : Create an in-game copy of the target char. + * Example : player:clone() + * Notes : This is a debug tool for simulating many player entities. + * Chars created will have a dummy AI and mocked out packet/db support. + ************************************************************************/ + +void CLuaBaseEntity::clone(uint32 num) +{ + if (m_PBaseEntity->objtype == TYPE_PC) + { + auto* PChar = static_cast(m_PBaseEntity); + for (int i = 0; i < num; ++i) + { + testutils::createDummy(PChar); + } + } +} + //==========================================================// void CLuaBaseEntity::Register() @@ -13723,6 +13744,9 @@ void CLuaBaseEntity::Register() SOL_REGISTER("updateToEntireZone", CLuaBaseEntity::updateToEntireZone); SOL_REGISTER("getHistory", CLuaBaseEntity::getHistory); + + // Debug + SOL_REGISTER("clone", CLuaBaseEntity::clone); } diff --git a/src/map/lua/lua_baseentity.h b/src/map/lua/lua_baseentity.h index 0adc4efa6b8..7be1a68c07e 100644 --- a/src/map/lua/lua_baseentity.h +++ b/src/map/lua/lua_baseentity.h @@ -770,6 +770,8 @@ class CLuaBaseEntity uint32 getHistory(uint8 index); + void clone(uint32 num); + static void Register(); }; diff --git a/src/map/utils/CMakeLists.txt b/src/map/utils/CMakeLists.txt index 5e8475db102..591a5779552 100644 --- a/src/map/utils/CMakeLists.txt +++ b/src/map/utils/CMakeLists.txt @@ -33,6 +33,8 @@ set(SOURCES puppetutils.h synthutils.cpp synthutils.h + testutils.cpp + testutils.h trustutils.cpp trustutils.h zoneutils.cpp diff --git a/src/map/utils/testutils.cpp b/src/map/utils/testutils.cpp new file mode 100644 index 00000000000..8813475f41b --- /dev/null +++ b/src/map/utils/testutils.cpp @@ -0,0 +1,69 @@ +#include "testutils.h" + +#include "../entities/charentity.h" +#include "../entities/dummyentity.h" + +#include "../utils/charutils.h" + +#include "../ai/ai_container.h" +#include "../ai/helpers/pathfind.h" + +#include "../ext/spdlog/include/spdlog/fmt/bundled/core.h" + +namespace testutils +{ + void createDummy(CCharEntity* PChar) + { + auto* PZone = PChar->loc.zone; + + auto* PDummy = new CDummyEntity(PChar); + + uint32 charsInZone = 0; + PZone->ForEachChar([&](CCharEntity*) { ++charsInZone; }); + PDummy->id = charsInZone + 1; + + PDummy->look.face = 30; // Mannequin + PDummy->look.race = xirand::GetRandomNumber(0, 8); + PDummy->look.size = xirand::GetRandomNumber(0, 3); + + PDummy->SetName((int8*)fmt::format("Dummy-{}", PDummy->id).data()); + + PZone->IncreaseZoneCounter(PDummy); + PDummy->Spawn(); + + PDummy->status = STATUS_TYPE::NORMAL; + + auto pos = PZone->m_navMesh->findRandomPosition(PChar->loc.p, 15.0f); + + PDummy->loc.p.x = pos.second.x; + PDummy->loc.p.y = pos.second.y; + PDummy->loc.p.z = pos.second.z; + + PDummy->loc.p.moving = PChar->loc.p.moving; + PDummy->loc.p.rotation = PChar->loc.p.rotation + xirand::GetRandomNumber(0, 255); + + PDummy->m_TargID = 0; + + PDummy->updatemask |= UPDATE_ALL_CHAR; + + PDummy->loc.zone->SpawnPCs(PDummy); + PDummy->loc.zone->SpawnNPCs(PDummy); + PDummy->loc.zone->SpawnMOBs(PDummy); + PDummy->loc.zone->SpawnPETs(PDummy); + PDummy->loc.zone->SpawnTRUSTs(PDummy); + + PDummy->nameflags.flags = PChar->nameflags.flags; + PDummy->animation = ANIMATION_NONE; + + PDummy->SetMJob(PChar->GetMJob()); + PDummy->SetSJob(PChar->GetSJob()); + PDummy->SetMLevel(PChar->GetMLevel()); + PDummy->SetSLevel(PChar->GetSLevel()); + + PDummy->health.maxhp = 1000; + PDummy->health.maxmp = 1000; + PDummy->health.hp = PDummy->GetMaxHP(); + PDummy->health.mp = PDummy->GetMaxMP(); + PDummy->UpdateHealth(); + } +}; // namespace testutils diff --git a/src/map/utils/testutils.h b/src/map/utils/testutils.h new file mode 100644 index 00000000000..f3327a50cf7 --- /dev/null +++ b/src/map/utils/testutils.h @@ -0,0 +1,14 @@ +#ifndef _TESTUTILS_H +#define _TESTUTILS_H + +#include "../../common/cbasetypes.h" +#include "../../common/mmo.h" + +class CCharEntity; + +namespace testutils +{ + void createDummy(CCharEntity* PChar); +}; // namespace testutils + +#endif // _TESTUTILS_H