Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: Add entity_cast #6567

Draft
wants to merge 1 commit into
base: base
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 86 additions & 1 deletion src/map/entities/baseentity.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,15 @@ struct EntityID_t
// TODO: Store an incremental u64 as a UUID for the entity for disambiguation in the case of dynamic entities that might have the same targid.
};

class CBaseEntity;
class CCharEntity;
class CNpcEntity;
class CMobEntity;
class CPetEntity;
class CShipEntity;
class CTrustEntity;
class CFellowEntity;

class CAIContainer;
class CBattlefield;
class CInstance;
Expand All @@ -250,6 +259,82 @@ struct location_t
}
};

// Cast the target entity pointer to the requested entity pointer type.
// We use this because dynamic_cast will succeed for any derived class, not just the requested class.
// ie. A Trust will dynamic_cast to all of: CBattleEntity, CMobEntity, and CTrustEntity, but objtype will only be TYPE_TRUST.
template <typename TRequested, typename TBase>
constexpr auto entity_cast(TBase basePtr) -> TRequested
{
static_assert(std::is_pointer_v<TRequested>, "TRequested must be a pointer type.");
static_assert(std::is_base_of_v<CBaseEntity, std::remove_pointer_t<TRequested>>, "TRequested must be derived from CBaseEntity.");

if (basePtr == nullptr || basePtr->objtype == TYPE_NONE)
{
ShowWarning("entity_cast: Invalid entity pointer.");
return nullptr;
}

switch (basePtr->objtype)
{
case TYPE_PC:
if constexpr (std::is_same_v<std::remove_pointer_t<TRequested>, CCharEntity>)
{
return static_cast<CCharEntity*>(basePtr);
}
break;
case TYPE_NPC:
if constexpr (std::is_same_v<std::remove_pointer_t<TRequested>, CNpcEntity>)
{
return static_cast<CNpcEntity*>(basePtr);
}
break;
case TYPE_MOB:
if constexpr (std::is_same_v<std::remove_pointer_t<TRequested>, CMobEntity>)
{
return static_cast<CMobEntity*>(basePtr);
}
break;
case TYPE_PET:
if constexpr (std::is_same_v<std::remove_pointer_t<TRequested>, CPetEntity>)
{
return static_cast<CPetEntity*>(basePtr);
}
break;
case TYPE_SHIP:
if constexpr (std::is_same_v<std::remove_pointer_t<TRequested>, CShipEntity>)
{
return static_cast<CShipEntity*>(basePtr);
}
break;
case TYPE_TRUST:
if constexpr (std::is_same_v<std::remove_pointer_t<TRequested>, CTrustEntity>)
{
return static_cast<CTrustEntity*>(basePtr);
}
break;
case TYPE_FELLOW:
if constexpr (std::is_same_v<std::remove_pointer_t<TRequested>, CFellowEntity>)
{
return static_cast<CFellowEntity*>(basePtr);
}
break;
default:
// Fall through to the warning.
break;
}

// TODO: We're now in an error state. We could use this opportunity to exhaustively dynamic_cast to all possible derived classes
// and print a warning with the results.

const auto baseName = typeid(TBase).name();
const auto requestedName = typeid(TRequested).name();
const auto errString = fmt::format("entity_cast: Failed to cast entity from base type '{}' to requested type '{}'.", baseName, requestedName);

ShowWarning(errString);

return nullptr;
}

/************************************************************************
* *
* Basic class for all entities in the game *
Expand Down Expand Up @@ -299,7 +384,7 @@ class CBaseEntity
void SetModelId(uint16 modelId); // Set new modelid
uint16 GetModelId() const; // Get the modelid

virtual void HandleErrorMessage(std::unique_ptr<CBasicPacket>&){};
virtual void HandleErrorMessage(std::unique_ptr<CBasicPacket>&) {};

bool IsDynamicEntity() const;

Expand Down
10 changes: 5 additions & 5 deletions src/map/zone_entities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -727,10 +727,10 @@ void CZoneEntities::SpawnTRUSTs(CCharEntity* PChar)
TracyZoneScoped;
for (EntityList_t::const_iterator TrustItr = m_trustList.begin(); TrustItr != m_trustList.end(); ++TrustItr)
{
if (CTrustEntity* PCurrentTrust = dynamic_cast<CTrustEntity*>(TrustItr->second))
if (CTrustEntity* PCurrentTrust = entity_cast<CTrustEntity*>(TrustItr->second))
{
SpawnIDList_t::iterator SpawnTrustItr = PChar->SpawnTRUSTList.find(PCurrentTrust->id);
CCharEntity* PMaster = dynamic_cast<CCharEntity*>(PCurrentTrust->PMaster);
CCharEntity* PMaster = entity_cast<CCharEntity*>(PCurrentTrust->PMaster);

// Is this trust "visible" to the player?
if (PCurrentTrust->status == STATUS_TYPE::NORMAL && distance(PChar->loc.p, PCurrentTrust->loc.p) <= 50)
Expand Down Expand Up @@ -1471,7 +1471,7 @@ void CZoneEntities::ZoneServer(time_point tick)
EntityList_t::iterator it = m_mobList.begin();
while (it != m_mobList.end())
{
CMobEntity* PMob = dynamic_cast<CMobEntity*>(it->second);
CMobEntity* PMob = entity_cast<CMobEntity*>(it->second);
if (!PMob)
{
++it;
Expand Down Expand Up @@ -1560,7 +1560,7 @@ void CZoneEntities::ZoneServer(time_point tick)
{
for (auto PMobCurrentIter : m_mobList)
{
CMobEntity* PCurrentMob = dynamic_cast<CMobEntity*>(PMobCurrentIter.second);
CMobEntity* PCurrentMob = entity_cast<CMobEntity*>(PMobCurrentIter.second);
if (PCurrentMob != nullptr && PCurrentMob->isAlive() && PMob->allegiance != PCurrentMob->allegiance && distance(PMob->loc.p, PCurrentMob->loc.p) <= 50)
{
CMobController* PController = static_cast<CMobController*>(PCurrentMob->PAI->GetController());
Expand Down Expand Up @@ -1651,7 +1651,7 @@ void CZoneEntities::ZoneServer(time_point tick)
it = m_trustList.begin();
while (it != m_trustList.end())
{
if (CTrustEntity* PTrust = dynamic_cast<CTrustEntity*>(it->second))
if (CTrustEntity* PTrust = entity_cast<CTrustEntity*>(it->second))
{
ShowTrace(fmt::format("CZoneEntities::ZoneServer: Trust: {} ({})", PTrust->getName(), PTrust->id).c_str());

Expand Down
8 changes: 4 additions & 4 deletions src/map/zone_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ void CZoneInstance::CheckTriggerAreas()
{
for (const auto& [targid, PEntity] : PInstance->m_charList)
{
auto* PChar = dynamic_cast<CCharEntity*>(PEntity);
auto* PChar = entity_cast<CCharEntity*>(PEntity);
if (!PChar)
{
continue;
Expand Down Expand Up @@ -494,7 +494,7 @@ void CZoneInstance::ForEachChar(const std::function<void(CCharEntity*)>& func)
{
for (const auto& [targid, PEntity] : PInstance->GetCharList())
{
if (auto* PChar = dynamic_cast<CCharEntity*>(PEntity))
if (auto* PChar = entity_cast<CCharEntity*>(PEntity))
{
func(PChar);
}
Expand All @@ -507,7 +507,7 @@ void CZoneInstance::ForEachCharInstance(CBaseEntity* PEntity, const std::functio
TracyZoneScoped;
for (const auto& [_, PEntity] : PEntity->PInstance->GetCharList())
{
if (auto* PChar = dynamic_cast<CCharEntity*>(PEntity))
if (auto* PChar = entity_cast<CCharEntity*>(PEntity))
{
func(PChar);
}
Expand All @@ -519,7 +519,7 @@ void CZoneInstance::ForEachMobInstance(CBaseEntity* PEntity, const std::function
TracyZoneScoped;
for (const auto& [_, PEntity] : PEntity->PInstance->m_mobList)
{
if (auto* PMob = dynamic_cast<CMobEntity*>(PEntity))
if (auto* PMob = entity_cast<CMobEntity*>(PEntity))
{
func(PMob);
}
Expand Down
Loading