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

refactor: Rewrite Entity Component System #1110

Draft
wants to merge 122 commits into
base: main
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
c168f6c
Break out the model component
aronwk-aaron Feb 11, 2023
5097862
Merge branch 'main' into item-component
aronwk-aaron Feb 11, 2023
2ae9a92
fix cmake
aronwk-aaron Feb 11, 2023
c2d5be0
include
aronwk-aaron Mar 21, 2023
5e9a956
Merge branch 'main' into item-component
aronwk-aaron Mar 21, 2023
15988af
hey it compiles
aronwk-aaron Mar 21, 2023
716a5fc
Rename some variables in Component
EmosewaMC Jun 7, 2023
ea9d0d8
I hope this works
EmosewaMC Jun 7, 2023
9e9e4dc
Move to shared pointer
EmosewaMC Jun 7, 2023
d11e2db
update component names, document heirarchy
aronwk-aaron Jun 8, 2023
ec00f5f
holy mother of const
EmosewaMC Jun 9, 2023
62aa863
Remove shared pointer, ODR of componentType variable
EmosewaMC Jun 9, 2023
e2dfa18
Replace all auto with auto*
EmosewaMC Jun 9, 2023
f555ba8
Rename from GetOwningEntity to GetParentEntity
EmosewaMC Jun 9, 2023
6f05720
Rename some variables
EmosewaMC Jun 9, 2023
5da776a
Add blank classes for some Components
EmosewaMC Jun 9, 2023
f2d28cc
Update CMakeLists.txt
EmosewaMC Jun 9, 2023
0b37dc1
Update includes for propertyEnteranceComponent
EmosewaMC Jun 9, 2023
e3a716a
Further re-implement Entity::Initialize
EmosewaMC Jun 9, 2023
ddc5f0e
Merge branch 'main' into components-wheeeee
EmosewaMC Jun 9, 2023
a68fa69
Rename RebuildComponent to QuickbuildComponent
aronwk-aaron Jun 9, 2023
1c23f3c
Add test for component Whitelists
EmosewaMC Jun 10, 2023
2a27997
More robust tests
EmosewaMC Jun 10, 2023
5714ac5
Use std algorithms
EmosewaMC Jun 10, 2023
cebe3c7
Update to actually work with component list
EmosewaMC Jun 10, 2023
b91f84d
Collectible, Item, further re-implement initialize
EmosewaMC Jun 10, 2023
0b5df9f
Destroyable
EmosewaMC Jun 10, 2023
77dc6ff
Continued re-integration of Entity::Initialize
EmosewaMC Jun 11, 2023
5f139c7
Quickbuild and Destroyable reintegration
EmosewaMC Jun 11, 2023
b43e5c2
doesnt have a component
EmosewaMC Jun 11, 2023
f78ea1b
whitespace and comments in quickbuild
EmosewaMC Jun 11, 2023
fc719cb
Comment out done code
EmosewaMC Jun 11, 2023
36c44ec
Fully re-implemented initialize
EmosewaMC Jun 12, 2023
6f38a15
Minor formatting change
EmosewaMC Jun 12, 2023
262b6eb
Remove old Entity Initialize
EmosewaMC Jun 12, 2023
5be9146
Specify auto ptr
EmosewaMC Jun 12, 2023
3f38105
Extra * on one auto
EmosewaMC Jun 12, 2023
f9ac0a9
few more pointer specifiers
EmosewaMC Jun 12, 2023
d224a86
Use only 1 script component per Entity
EmosewaMC Jun 12, 2023
326c495
Use more clear control paths
EmosewaMC Jun 12, 2023
b2fee29
Better log and comment
EmosewaMC Jun 12, 2023
45bcc80
doesnt compile
EmosewaMC Jun 12, 2023
e389a61
update heirarchy
aronwk-aaron Jun 13, 2023
d8e2e92
use get
EmosewaMC Jun 14, 2023
31be1fb
remove script stuff
EmosewaMC Jun 14, 2023
fdd98ab
fix other script calls
aronwk-aaron Jun 14, 2023
83065df
I havent checked if this compiled
EmosewaMC Jun 15, 2023
451f7e7
switch to unique_ptrs for callback timers
EmosewaMC Jun 15, 2023
355f4f4
Update Entity.cpp
EmosewaMC Jun 15, 2023
2a8f40f
Finish file
EmosewaMC Jun 15, 2023
4d57eff
Update includes
EmosewaMC Jun 15, 2023
35e5d84
Remove empty destructors
EmosewaMC Jun 15, 2023
ea97596
Fix typo
EmosewaMC Jun 16, 2023
9a9b9aa
Merge branch 'components-wheeeee' of https://github.com/DarkflameUniv…
EmosewaMC Jun 16, 2023
9200612
Another consistency pass
EmosewaMC Jun 16, 2023
8916482
Organize Entity header
EmosewaMC Jun 16, 2023
a992a28
Merge from upstream
EmosewaMC Jun 16, 2023
be17d1a
Update DestroyableComponent.cpp
EmosewaMC Jun 16, 2023
68a5cc1
Use better API terminology for radii
EmosewaMC Jun 17, 2023
1bdec00
More organization of header
EmosewaMC Jun 17, 2023
e180430
Finish header re-ordering
EmosewaMC Jun 18, 2023
dc96fcb
Vendor cleanup and start Donation Vendor impl
aronwk-aaron Jun 23, 2023
907e045
some tweaks
aronwk-aaron Jun 23, 2023
c78760d
make inheritence clearer
aronwk-aaron Jun 23, 2023
f27e040
scaffold activity based components
aronwk-aaron Jun 23, 2023
bcbc588
Merge branch 'main' into components-wheeeee
aronwk-aaron Jun 23, 2023
34d22d2
AchievementVendor scaffold
aronwk-aaron Jun 23, 2023
d153d66
Merge branch 'item-component' into components-wheeeee
aronwk-aaron Jun 23, 2023
d44b18e
rough logic around loading physics
aronwk-aaron Jun 23, 2023
c237c16
group physicstogether in heirarchy
aronwk-aaron Jun 23, 2023
485a88d
move vars to be local
aronwk-aaron Jun 24, 2023
3f328a1
Merge upstream ghosting candidate changes
EmosewaMC Jun 26, 2023
fee1025
Remove commented out logic, add ghosting exclusion
EmosewaMC Jun 26, 2023
9121bf4
Entity work
EmosewaMC Jun 26, 2023
ec92782
Use better naming
EmosewaMC Jun 26, 2023
34cfd45
CombatAI and Vendor
EmosewaMC Jun 26, 2023
a5611e9
Bouncer cleanup
EmosewaMC Jun 26, 2023
06acd23
Use of final
EmosewaMC Jun 26, 2023
d29287f
Buff Component fixes
EmosewaMC Jun 26, 2023
68f90b7
rename possessor to possession
aronwk-aaron Jun 26, 2023
fd182d2
Update activing and racing components
aronwk-aaron Jun 26, 2023
fdcfbde
BuildBorderCleanup
EmosewaMC Jun 27, 2023
d9a3bea
Merge branch 'components-wheeeee' of https://github.com/DarkflameUniv…
EmosewaMC Jun 27, 2023
2abcb14
Character fixes - get it compiling again
EmosewaMC Jun 27, 2023
c6063aa
Component serialization updates
EmosewaMC Jun 27, 2023
7c12659
move ctor to header for collectible
EmosewaMC Jun 27, 2023
478b6ff
Move empty definitions to header
EmosewaMC Jun 27, 2023
f55bec0
Donation Component serialization
EmosewaMC Jun 27, 2023
c2fe7f6
HavokVehicleComponent improvements
EmosewaMC Jun 27, 2023
0544eeb
Add default constructor for EquipmentItem
EmosewaMC Jun 27, 2023
81404d9
InventoryComponent pass
EmosewaMC Jun 28, 2023
6fb1786
Add component order array
aronwk-aaron Jun 29, 2023
c22040c
ItemComponent Pass
EmosewaMC Jul 5, 2023
8ede5b8
Fix compilation error; add final specifiers
EmosewaMC Jul 5, 2023
cfec980
LevelProgressionComponent cleanup
EmosewaMC Jul 5, 2023
68a2a04
LUPExhibitComponent cleanup
EmosewaMC Jul 5, 2023
197d1bc
Merge branch 'main' into components-wheeeee
aronwk-aaron Jul 5, 2023
950a1fe
MissionComponent pass
EmosewaMC Jul 6, 2023
001f6a7
MissionOfferComponent pass
EmosewaMC Jul 6, 2023
5301346
ModelBehaviorComponent pass
EmosewaMC Jul 6, 2023
cf53e35
SwitchComponent pass
EmosewaMC Jul 7, 2023
28fbe20
ModuleAssemblyComponent pass
EmosewaMC Jul 8, 2023
790bd6c
Merge branch 'components-wheeeee' of https://github.com/DarkflameUniv…
EmosewaMC Jul 8, 2023
1b7be5d
Merge branch 'components-wheeeee' of https://github.com/DarkflameUniv…
EmosewaMC Jul 10, 2023
2528e02
add final
EmosewaMC Jul 10, 2023
8a512e5
MovementAiComponent pass
EmosewaMC Jul 10, 2023
d2a7e14
I am throwing this one out later.
EmosewaMC Jul 10, 2023
7ca9e59
MultiZoneEntranceComponent pass
EmosewaMC Jul 10, 2023
83780af
MutableModelBehaviorComponent pass
EmosewaMC Jul 10, 2023
87675aa
PetComponent pass
EmosewaMC Jul 10, 2023
28637a2
PhantomPhysicsComponent pass
EmosewaMC Jul 10, 2023
598d88b
PlayerForcedMovementComponent pass
EmosewaMC Jul 10, 2023
fe6b279
PossessableComponent pass
EmosewaMC Jul 10, 2023
59831fc
PhantomPhysicsComponent pass
EmosewaMC Jul 10, 2023
4d88f63
PossessionComponent pass
EmosewaMC Jul 10, 2023
37bcc81
PropertyComponent pass
EmosewaMC Jul 10, 2023
8678ed0
push no pass
EmosewaMC Jul 11, 2023
a37ec32
idek if ill keep this but yeah
EmosewaMC Jul 11, 2023
c204ea4
PropertyVendorComponent pass
EmosewaMC Jul 11, 2023
49f3d75
ProximityMonitorComponent re-pass
EmosewaMC Jul 11, 2023
949a6db
RailActivatorComponent pass
EmosewaMC Jul 11, 2023
6240eef
local work
EmosewaMC Jul 11, 2023
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
Prev Previous commit
Next Next commit
I havent checked if this compiled
EmosewaMC committed Jun 15, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 83065dfb6f7cfb6c0ae40038b81794f5d8abe37f
266 changes: 111 additions & 155 deletions dGame/Entity.cpp
Original file line number Diff line number Diff line change
@@ -541,6 +541,8 @@ void Entity::Initialize() {
if (!m_Character && EntityManager::Instance()->GetGhostingEnabled()) IsGhosted();
}

// Invert this check and build it into the component initialization. The ghosting property is an intrinsic property of which components the Entity has.
// Keep the first check since that is a special case for large scene elements like Brig Rock as a whole.
void Entity::IsGhosted() {
// Don't ghost what is likely large scene elements
if (HasComponent(eReplicaComponentType::SIMPLE_PHYSICS) && HasComponent(eReplicaComponentType::RENDER) && (m_Components.size() == 2 || (HasComponent(eReplicaComponentType::TRIGGER) && m_Components.size() == 3))) {
@@ -571,37 +573,27 @@ void Entity::IsGhosted() {
}
}

// Move to header
bool Entity::operator==(const Entity& other) const {
return other.m_ObjectID == m_ObjectID;
}

// Move to header
bool Entity::operator!=(const Entity& other) const {
return !(other.m_ObjectID == m_ObjectID);
}

// Move to header
User* Entity::GetParentUser() const {
if (!IsPlayer()) {
return nullptr;
}

return static_cast<const Player*>(this)->GetParentUser();
return IsPlayer() ? static_cast<const Player*>(this)->GetParentUser() : nullptr;
}

// Move to header
bool Entity::HasComponent(const eReplicaComponentType componentId) const {
return m_Components.find(componentId) != m_Components.end();
}

std::vector<ScriptComponent*> Entity::GetScriptComponents() {
std::vector<ScriptComponent*> comps;
for (const auto& [componentType, component] : m_Components) {
if (componentType == eReplicaComponentType::SCRIPT) {
comps.push_back(dynamic_cast<ScriptComponent*>(component.get()));
}
}

return comps;
}

// Fine
void Entity::Subscribe(const LWOOBJID& scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName) {
if (notificationName == "HitOrHealResult" || notificationName == "Hit") {
auto* destroyableComponent = GetComponent<DestroyableComponent>();
@@ -610,6 +602,7 @@ void Entity::Subscribe(const LWOOBJID& scriptObjId, CppScripts::Script* scriptTo
}
}

// Fine
void Entity::Unsubscribe(const LWOOBJID& scriptObjId, const std::string& notificationName) {
if (notificationName == "HitOrHealResult" || notificationName == "Hit") {
auto* destroyableComponent = GetComponent<DestroyableComponent>();
@@ -618,18 +611,21 @@ void Entity::Unsubscribe(const LWOOBJID& scriptObjId, const std::string& notific
}
}

// Fine
void Entity::SetProximityRadius(const float proxRadius, const std::string& name) {
auto* proximityMonitorComponent = AddComponent<ProximityMonitorComponent>();
if (proximityMonitorComponent) proximityMonitorComponent->SetProximityRadius(proxRadius, name);
}

// Remove in favor of a square constructor
void Entity::SetProximityRadius(dpEntity* entity, const std::string& name) {
auto* proximityMonitorComponent = AddComponent<ProximityMonitorComponent>();
if (proximityMonitorComponent) proximityMonitorComponent->SetProximityRadius(entity, name);
}

void Entity::SetGMLevel(eGameMasterLevel value) {
m_GMLevel = value;
// User m_Character?
if (GetParentUser()) {
Character* character = GetParentUser()->GetLastUsedChar();

@@ -670,6 +666,7 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, const eReplic
const auto& syncLDF = GetVar<std::vector<std::u16string>>(u"syncLDF");

// Only sync for models.
// PetComponent check un-needed since we should be removing the component during construction.
if (m_Settings.size() > 0 && (GetComponent<ModelBehaviorComponent>() && !GetComponent<PetComponent>())) {
outBitStream->Write1(); //ldf data

@@ -719,31 +716,27 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, const eReplic
outBitStream->Write0();
}


outBitStream->Write<bool>(m_ParentEntity != nullptr || m_SpawnerID != 0);
if (m_ParentEntity != nullptr || m_SpawnerID != 0) {
outBitStream->Write1();
if (m_ParentEntity != nullptr) outBitStream->Write(GeneralUtils::SetBit(m_ParentEntity->GetObjectID(), static_cast<uint32_t>(eObjectBits::CLIENT)));
else if (m_Spawner != nullptr && m_Spawner->m_Info.isNetwork) outBitStream->Write(m_SpawnerID);
else outBitStream->Write(GeneralUtils::SetBit(m_SpawnerID, static_cast<uint32_t>(eObjectBits::CLIENT)));
} else outBitStream->Write0();
}

outBitStream->Write(m_HasSpawnerNodeID);
if (m_HasSpawnerNodeID) outBitStream->Write(m_SpawnerNodeID);

//outBitStream->Write0(); //Spawner node id

if (m_Scale == 1.0f || m_Scale == 0.0f) outBitStream->Write0();
else {
outBitStream->Write1();
outBitStream->Write(m_Scale);
}
outBitStream->Write<bool>(m_Scale != 1.0f || m_Scale != 0.0f);
if (m_Scale != 1.0f || m_Scale != 0.0f) outBitStream->Write(m_Scale);

outBitStream->Write0(); //ObjectWorldState

outBitStream->Write(m_GMLevel != eGameMasterLevel::CIVILIAN);
if (m_GMLevel != eGameMasterLevel::CIVILIAN) {
outBitStream->Write1();
outBitStream->Write(m_GMLevel);
} else outBitStream->Write0(); //No GM Level
}
}

// Only serialize parent / child info should the info be dirty (changed) or if this is the construction of the entity.
@@ -757,26 +750,27 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, const eReplic
}
outBitStream->Write(m_ChildEntities.size() > 0);
if (m_ChildEntities.size() > 0) {
outBitStream->Write((uint16_t)m_ChildEntities.size());
outBitStream->Write<uint16_t>(m_ChildEntities.size());
for (Entity* child : m_ChildEntities) {
outBitStream->Write((uint64_t)child->GetObjectID());
outBitStream->Write<LWOOBJID>(child->GetObjectID());
}
}
}
}

// uh
void Entity::WriteComponents(RakNet::BitStream* outBitStream, const eReplicaPacketType packetType) {

}

// We should be able to use this at some point
void Entity::ResetFlags() {
// Unused
}

// std::for_each
void Entity::UpdateXMLDoc(tinyxml2::XMLDocument* doc) {
//This function should only ever be called from within Character, meaning doc should always exist when this is called.
//Naturally, we don't include any non-player components in this update function.

DluAssert(doc != nullptr);
for (const auto& pair : m_Components) {
if (pair.second == nullptr) continue;

@@ -808,7 +802,7 @@ void Entity::Update(const float deltaTime) {
auto callbackTimerItr = std::remove_if(m_CallbackTimers.begin(), m_CallbackTimers.end(), [this, &deltaTime](EntityCallbackTimer* timer) {
timer->Update(deltaTime);
if (timer->GetTime() <= 0) {
timer->GetCallback()();
timer->ExecuteCallback();
delete timer;
return true;
}
@@ -818,43 +812,36 @@ void Entity::Update(const float deltaTime) {

// Add pending timers to the list of timers so they start next tick.
if (m_PendingTimers.size() > 0) {
for (auto namedTimer : m_PendingTimers) {
m_Timers.push_back(namedTimer);
}
m_Timers.insert(m_Timers.end(), m_PendingTimers.begin(), m_PendingTimers.end());
m_PendingTimers.clear();
}

if (IsSleeping()) {
Sleep();

return;
} else {
Wake();
}
Wake();

GetScript()->OnUpdate(this);

for (const auto& pair : m_Components) {
if (pair.second == nullptr) continue;

pair.second->Update(deltaTime);
for (const auto& [componentId, component] : m_Components) {
if (component) component->Update(deltaTime);
}

if (m_ShouldDestroyAfterUpdate) {
EntityManager::Instance()->DestroyEntity(this->GetObjectID());
}
if (m_ShouldDestroyAfterUpdate) EntityManager::Instance()->DestroyEntity(this);
}

void Entity::OnCollisionProximity(LWOOBJID otherEntity, const std::string& proxName, const std::string& status) {
Entity* other = EntityManager::Instance()->GetEntity(otherEntity);
auto* other = EntityManager::Instance()->GetEntity(otherEntity);
if (!other) return;

GetScript()->OnProximityUpdate(this, other, proxName, status);

auto* rocketComp = GetComponent<RocketLaunchpadControlComponent>();
if (!rocketComp) return;
auto* rocketLaunchpadControlComponent = GetComponent<RocketLaunchpadControlComponent>();
if (!rocketLaunchpadControlComponent) return;

rocketComp->OnProximityUpdate(other, proxName, status);
rocketLaunchpadControlComponent->OnProximityUpdate(other, proxName, status);
}

void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) {
@@ -863,14 +850,12 @@ void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) {

GetScript()->OnCollisionPhantom(this, other);

for (const auto& callback : m_PhantomCollisionCallbacks) {
std::for_each(m_PhantomCollisionCallbacks.begin(), m_PhantomCollisionCallbacks.end(), [other](const auto& callback) {
callback(other);
}
});

auto* switchComp = GetComponent<SwitchComponent>();
if (switchComp) {
switchComp->EntityEnter(other);
}
auto* switchComponent = GetComponent<SwitchComponent>();
if (switchComponent) switchComponent->EntityEnter(other);

TriggerEvent(eTriggerEventType::ENTER, other);

@@ -910,10 +895,8 @@ void Entity::OnCollisionLeavePhantom(const LWOOBJID otherEntity) {

TriggerEvent(eTriggerEventType::EXIT, other);

auto* switchComp = GetComponent<SwitchComponent>();
if (switchComp) {
switchComp->EntityLeave(other);
}
auto* switchComponent = GetComponent<SwitchComponent>();
if (switchComponent) switchComponent->EntityLeave(other);

const auto index = std::find(m_TargetsInPhantom.begin(), m_TargetsInPhantom.end(), otherEntity);

@@ -950,12 +933,8 @@ void Entity::OnUse(Entity* originator) {

GetScript()->OnUse(this, originator);

// component base class when

for (const auto& pair : m_Components) {
if (pair.second == nullptr) continue;

pair.second->OnUse(originator);
for (const auto& [componentId, component] : m_Components) {
if (component) component->OnUse(originator);
}
}

@@ -1016,7 +995,7 @@ void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u
if (!m_PlayerIsReadyForUpdates) return;

auto* destroyableComponent = GetComponent<DestroyableComponent>();
if (destroyableComponent == nullptr) {
if (!destroyableComponent) {
Kill(EntityManager::Instance()->GetEntity(source));
return;
}
@@ -1034,23 +1013,17 @@ void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u
void Entity::Kill(Entity* murderer) {
if (!m_PlayerIsReadyForUpdates) return;

for (const auto& cb : m_DieCallbacks) {
cb();
}
for (const auto& cb : m_DieCallbacks) cb();

m_DieCallbacks.clear();

//OMAI WA MOU, SHINDERIU

GetScript()->OnDie(this, murderer);

if (m_Spawner != nullptr) {
m_Spawner->NotifyOfEntityDeath(m_ObjectID);
}
if (m_Spawner) m_Spawner->NotifyOfEntityDeath(m_ObjectID);

if (!IsPlayer()) {
EntityManager::Instance()->DestroyEntity(this);
}
if (!IsPlayer()) EntityManager::Instance()->DestroyEntity(this);

const auto& grpNameQBShowBricks = GetVar<std::string>(u"grpNameQBShowBricks");

@@ -1060,30 +1033,26 @@ void Entity::Kill(Entity* murderer) {
Spawner* spawner = nullptr;

if (!spawners.empty()) {
spawner = spawners[0];
spawner = spawners.front();
} else {
spawners = dZoneManager::Instance()->GetSpawnersInGroup(grpNameQBShowBricks);

if (!spawners.empty()) {
spawner = spawners[0];
}
if (!spawners.empty()) spawner = spawners.front();
}

if (spawner != nullptr) {
spawner->Spawn();
}
if (spawner) spawner->Spawn();
}

// Track a player being smashed
auto* characterComponent = GetComponent<CharacterComponent>();
if (characterComponent != nullptr) {
if (characterComponent) {
characterComponent->UpdatePlayerStatistic(TimesSmashed);
}

// Track a player smashing something else
if (murderer != nullptr) {
if (murderer) {
auto* murdererCharacterComponent = murderer->GetComponent<CharacterComponent>();
if (murdererCharacterComponent != nullptr) {
if (murdererCharacterComponent) {
murdererCharacterComponent->UpdatePlayerStatistic(SmashablesSmashed);
}
}
@@ -1099,65 +1068,62 @@ void Entity::AddCollisionPhantomCallback(const std::function<void(Entity* target

void Entity::AddRebuildCompleteCallback(const std::function<void(Entity* user)>& callback) const {
auto* quickBuildComponent = GetComponent<QuickBuildComponent>();
if (quickBuildComponent != nullptr) {
quickBuildComponent->AddRebuildCompleteCallback(callback);
}
if (quickBuildComponent) quickBuildComponent->AddRebuildCompleteCallback(callback);
}

bool Entity::GetIsDead() const {
auto* dest = GetComponent<DestroyableComponent>();
if (dest && dest->GetArmor() == 0 && dest->GetHealth() == 0) return true;

return false;
return dest && dest->GetArmor() == 0 && dest->GetHealth() == 0;
}

// Replace static_cast with dynamic_cast
void Entity::AddLootItem(const Loot::Info& info) {
if (!IsPlayer()) return;
auto& droppedLoot = static_cast<Player*>(this)->GetDroppedLoot();
droppedLoot.insert(std::make_pair(info.id, info));
}

// Replace static_cast with dynamic_cast
void Entity::PickupItem(const LWOOBJID& objectID) {
if (!IsPlayer()) return;
auto* inv = GetComponent<InventoryComponent>();
if (!inv) return;
auto* inventoryComponent = GetComponent<InventoryComponent>();
if (!inventoryComponent) return;

CDObjectsTable* objectsTable = CDClientManager::Instance().GetTable<CDObjectsTable>();
auto* objectsTable = CDClientManager::Instance().GetTable<CDObjectsTable>();
auto* skillsTable = CDClientManager::Instance().GetTable<CDObjectSkillsTable>();

auto& droppedLoot = static_cast<Player*>(this)->GetDroppedLoot();

for (const auto& p : droppedLoot) {
if (p.first == objectID) {
auto* characterComponent = GetComponent<CharacterComponent>();
if (characterComponent != nullptr) {
characterComponent->TrackLOTCollection(p.second.lot);
}

const CDObjects& object = objectsTable->GetByID(p.second.lot);
if (object.id != 0 && object.type == "Powerup") {
CDObjectSkillsTable* skillsTable = CDClientManager::Instance().GetTable<CDObjectSkillsTable>();
std::vector<CDObjectSkills> skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == p.second.lot); });
for (CDObjectSkills skill : skills) {
CDSkillBehaviorTable* skillBehTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>();
CDSkillBehavior behaviorData = skillBehTable->GetSkillByID(skill.skillID);

SkillComponent::HandleUnmanaged(behaviorData.behaviorID, GetObjectID());

auto* missionComponent = GetComponent<MissionComponent>();

if (missionComponent != nullptr) {
missionComponent->Progress(eMissionTaskType::POWERUP, skill.skillID);
}
}
} else {
inv->AddItem(p.second.lot, p.second.count, eLootSourceType::PICKUP, eInventoryType::INVALID, {}, LWOOBJID_EMPTY, true, false, LWOOBJID_EMPTY, eInventoryType::INVALID, 1);
// See if there is some faster way to do this.
for (const auto& [lootObjId, loot] : droppedLoot) {
if (lootObjId != objectID) continue;
auto* characterComponent = GetComponent<CharacterComponent>();
if (characterComponent) characterComponent->TrackLOTCollection(loot.lot);

const CDObjects& object = objectsTable->GetByID(loot.lot);
if (object.id != 0 && object.type == "Powerup") {
const auto lootLot = loot.lot;
auto skills = skillsTable->Query([lootLot](CDObjectSkills entry) {return (entry.objectTemplate == lootLot); });
for (const auto& skill : skills) {
auto* skillBehaviorTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>();
auto behaviorData = skillBehaviorTable->GetSkillByID(skill.skillID);
// This should take a skillID, not a behaviorID.
SkillComponent::HandleUnmanaged(behaviorData.behaviorID, GetObjectID());

auto* missionComponent = GetComponent<MissionComponent>();

if (missionComponent) missionComponent->Progress(eMissionTaskType::POWERUP, skill.skillID);
}
} else {
inventoryComponent->AddItem(loot.lot, loot.count, eLootSourceType::PICKUP, eInventoryType::INVALID, {}, LWOOBJID_EMPTY, true, false, LWOOBJID_EMPTY, eInventoryType::INVALID, 1);
}
}

droppedLoot.erase(objectID);
}

// This functions name is misleading and should not modify the number of dropped coins.
// A separate function, PickupCoins should modify that.
// Replace static_cast with dynamic_cast
bool Entity::CanPickupCoins(const uint64_t& count) {
if (!IsPlayer()) return false;
auto* player = static_cast<Player*>(this);
@@ -1170,81 +1136,71 @@ bool Entity::CanPickupCoins(const uint64_t& count) {
}
}

void Entity::RegisterCoinDrop(const uint64_t& count) {
// Replace static_cast with dynamic_cast
void Entity::RegisterCoinDrop(const uint64_t& coinsDropped) {
if (!IsPlayer()) return;
auto* player = static_cast<Player*>(this);
auto droppedCoins = player->GetDroppedCoins();
droppedCoins += count;
player->SetDroppedCoins(droppedCoins);
player->SetDroppedCoins(player->GetDroppedCoins() + coinsDropped);
}

void Entity::AddChild(Entity* child) {
m_IsParentChildDirty = true;
m_ChildEntities.push_back(child);
if (std::find(m_ChildEntities.begin(), m_ChildEntities.end(), child) == m_ChildEntities.end()) m_ChildEntities.push_back(child);
}

void Entity::RemoveChild(Entity* child) {
if (!child) return;
uint32_t entityPosition = 0;
while (entityPosition < m_ChildEntities.size()) {
if (!m_ChildEntities[entityPosition] || (m_ChildEntities[entityPosition])->GetObjectID() == child->GetObjectID()) {
m_IsParentChildDirty = true;
m_ChildEntities.erase(m_ChildEntities.begin() + entityPosition);
} else {
entityPosition++;
}
}
auto toRemove = std::remove(m_ChildEntities.begin(), m_ChildEntities.end(), child);
if (toRemove != m_ChildEntities.end()) m_IsParentChildDirty = true;
m_ChildEntities.erase(toRemove, m_ChildEntities.end());
}

void Entity::RemoveParent() {
if (m_ParentEntity) m_IsParentChildDirty = true;
else Game::logger->Log("Entity", "Attempted to remove parent from(objid:lot) (%llu:%i) when no parent existed", GetObjectID(), GetLOT());
this->m_ParentEntity = nullptr;
}

void Entity::AddTimer(const std::string& name, float time) {
EntityTimer* timer = new EntityTimer(name, time);
m_PendingTimers.push_back(timer);
m_PendingTimers.push_back(new EntityTimer(name, time));
}

void Entity::AddCallbackTimer(const float time, const std::function<void()>& callback) {
EntityCallbackTimer* timer = new EntityCallbackTimer(time, callback);
m_CallbackTimers.push_back(timer);
m_CallbackTimers.push_back(new EntityCallbackTimer(time, callback));
}

bool Entity::HasTimer(const std::string& name) {
for (auto* timer : m_Timers) {
if (timer->GetName() == name) {
return true;
}
}

return false;
auto possibleTimer = std::find_if(m_Timers.begin(), m_Timers.end(), [name](EntityTimer* timer) {
return timer->GetName() == name;
});
return possibleTimer != m_Timers.end();
}

void Entity::CancelCallbackTimers() {
for (auto* callback : m_CallbackTimers) {
delete callback;
}

std::for_each(m_CallbackTimers.begin(), m_CallbackTimers.end(), [](EntityCallbackTimer* timer) {
delete timer;
});
m_CallbackTimers.clear();
}

void Entity::ScheduleKillAfterUpdate(Entity* murderer) {
//if (m_Info.spawner) m_Info.spawner->ScheduleKill(this);
EntityManager::Instance()->ScheduleForKill(this);

if (murderer) m_ScheduleKiller = murderer;
}

void Entity::CancelTimer(const std::string& name) {
for (int i = 0; i < m_Timers.size(); i++) {
if (m_Timers[i]->GetName() == name) {
delete m_Timers[i];
m_Timers.erase(m_Timers.begin() + i);
return;
auto toErase = std::remove_if(m_Timers.begin(), m_Timers.end(), [&name](EntityTimer* timer) {
if (timer->GetName() == name) {
delete timer;
return true;
}
}
return false;
});
m_Timers.erase(m_Timers.begin(), toErase);
}

// ### LEFT OFF HERE ###
void Entity::CancelAllTimers() {
for (auto* timer : m_Timers) {
delete timer;
2 changes: 0 additions & 2 deletions dGame/Entity.h
Original file line number Diff line number Diff line change
@@ -145,8 +145,6 @@ class Entity {
*/
bool HasComponent(const eReplicaComponentType componentId) const;

std::vector<ScriptComponent*> GetScriptComponents();

void Subscribe(const LWOOBJID& scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName);
void Unsubscribe(const LWOOBJID& scriptObjId, const std::string& notificationName);

4 changes: 4 additions & 0 deletions dGame/dEntity/EntityCallbackTimer.cpp
Original file line number Diff line number Diff line change
@@ -9,6 +9,10 @@ EntityCallbackTimer::~EntityCallbackTimer() {

}

void EntityCallbackTimer::ExecuteCallback() {
m_Callback();
}

std::function<void()> EntityCallbackTimer::GetCallback() {
return m_Callback;
}
1 change: 1 addition & 0 deletions dGame/dEntity/EntityCallbackTimer.h
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ class EntityCallbackTimer {
EntityCallbackTimer(float time, std::function<void()> callback);
~EntityCallbackTimer();

void ExecuteCallback();
std::function<void()> GetCallback();
float GetTime();