Skip to content

Commit

Permalink
refactor: re-write AOE, add FilterTargets, Update TacArc Reading (#1035)
Browse files Browse the repository at this point in the history
* Re-write AOE behavior for new filter targets
Update Tacarc to use new filter targets
Added dev commands for skill and attack debugging

* Get all entities by detroyable
rather than controllable physics
Since destroyables are what can be hit

* Re-work filter targets to be 100% live accurate
reduce memory usage by only using one vector and removing invalid entries
get entities in the proximity rather than all entities with des comps in the instance, as was done in live

* remove debuging longs and remove oopsie

* address feedback

* make log more useful

* make filter more flat

* Add some more checks to filter targets
add pvp checks to isenemy

* fix typing

* Add filter target to TacArc and update filter target

* fix double declaration

* Some debugging logs

* Update TacArc reading

* make log clearer

* logs

* Update TacArcBehavior.cpp

* banana

* fix max targets

* remove extreanous parenthesesuuesdsds

* make behavior slot use a real type

---------

Co-authored-by: David Markowitz <[email protected]>
  • Loading branch information
aronwk-aaron and EmosewaMC authored Oct 9, 2023
1 parent 471d657 commit d8ac148
Show file tree
Hide file tree
Showing 18 changed files with 465 additions and 357 deletions.
10 changes: 10 additions & 0 deletions dGame/EntityManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,16 @@ std::vector<Entity*> EntityManager::GetEntitiesByLOT(const LOT& lot) const {
return entities;
}

std::vector<Entity*> EntityManager::GetEntitiesByProximity(NiPoint3 reference, float radius) const{
std::vector<Entity*> entities = {};
if (radius > 1000.0f) return entities;
for (const auto& entity : m_Entities) {
if (NiPoint3::Distance(reference, entity.second->GetPosition()) <= radius) entities.push_back(entity.second);
}
return entities;
}


Entity* EntityManager::GetZoneControlEntity() const {
return m_ZoneControlEntity;
}
Expand Down
1 change: 1 addition & 0 deletions dGame/EntityManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class EntityManager {
std::vector<Entity*> GetEntitiesInGroup(const std::string& group);
std::vector<Entity*> GetEntitiesByComponent(eReplicaComponentType componentType) const;
std::vector<Entity*> GetEntitiesByLOT(const LOT& lot) const;
std::vector<Entity*> GetEntitiesByProximity(NiPoint3 reference, float radius) const;
Entity* GetZoneControlEntity() const;

// Get spawn point entity by spawn name
Expand Down
166 changes: 73 additions & 93 deletions dGame/dBehaviors/AreaOfEffectBehavior.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,134 +20,114 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b
return;
}

if (this->m_useTargetPosition && branch.target == LWOOBJID_EMPTY) return;

if (targetCount == 0){
PlayFx(u"miss", context->originator);
return;
}

if (targetCount > this->m_maxTargets) {
Game::logger->Log("AreaOfEffectBehavior", "Serialized size is greater than max targets! Size: %i, Max: %i", targetCount, this->m_maxTargets);
return;
}

std::vector<LWOOBJID> targets;
auto caster = context->caster;
if (this->m_useTargetAsCaster) context->caster = branch.target;

std::vector<LWOOBJID> targets;
targets.reserve(targetCount);

for (auto i = 0u; i < targetCount; ++i) {
LWOOBJID target{};

if (!bitStream->Read(target)) {
Game::logger->Log("AreaOfEffectBehavior", "failed to read in target %i from bitStream, aborting target Handle!", i);
return;
};

targets.push_back(target);
}

for (auto target : targets) {
branch.target = target;

this->m_action->Handle(context, bitStream, branch);
}
context->caster = caster;
PlayFx(u"cast", context->originator);
}

void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* self = Game::entityManager->GetEntity(context->caster);
if (self == nullptr) {
Game::logger->Log("AreaOfEffectBehavior", "Invalid self for (%llu)!", context->originator);

return;
auto* caster = Game::entityManager->GetEntity(context->caster);
if (!caster) return;

// determine the position we are casting the AOE from
auto reference = branch.isProjectile ? branch.referencePosition : caster->GetPosition();
if (this->m_useTargetPosition) {
if (branch.target == LWOOBJID_EMPTY) return;
auto branchTarget = Game::entityManager->GetEntity(branch.target);
if (branchTarget) reference = branchTarget->GetPosition();
}

auto reference = branch.isProjectile ? branch.referencePosition : self->GetPosition();

std::vector<Entity*> targets;
reference += this->m_offset;

auto* presetTarget = Game::entityManager->GetEntity(branch.target);
std::vector<Entity*> targets {};
targets = Game::entityManager->GetEntitiesByProximity(reference, this->m_radius);
context->FilterTargets(targets, this->m_ignoreFactionList, this->m_includeFactionList, this->m_targetSelf, this->m_targetEnemy, this->m_targetFriend, this->m_targetTeam);

if (presetTarget != nullptr) {
if (this->m_radius * this->m_radius >= Vector3::DistanceSquared(reference, presetTarget->GetPosition())) {
targets.push_back(presetTarget);
}
}

int32_t includeFaction = m_includeFaction;

if (self->GetLOT() == 14466) // TODO: Fix edge case
{
includeFaction = 1;
}

// Gets all of the valid targets, passing in if should target enemies and friends
for (auto validTarget : context->GetValidTargets(m_ignoreFaction, includeFaction, m_TargetSelf == 1, m_targetEnemy == 1, m_targetFriend == 1)) {
auto* entity = Game::entityManager->GetEntity(validTarget);

if (entity == nullptr) {
Game::logger->Log("AreaOfEffectBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator);

continue;
}

if (std::find(targets.begin(), targets.end(), entity) != targets.end()) {
continue;
// sort by distance
std::sort(targets.begin(), targets.end(), [reference](Entity* a, Entity* b) {
const auto aDistance = NiPoint3::Distance(a->GetPosition(), reference);
const auto bDistance = NiPoint3::Distance(b->GetPosition(), reference);
return aDistance < bDistance;
}
);

auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
// resize if we have more than max targets allows
if (targets.size() > this->m_maxTargets) targets.resize(this->m_maxTargets);

if (destroyableComponent == nullptr) {
continue;
}
bitStream->Write<uint32_t>(targets.size());

if (destroyableComponent->HasFaction(m_ignoreFaction)) {
continue;
if (targets.size() == 0) {
PlayFx(u"miss", context->originator);
return;
} else {
context->foundTarget = true;
// write all the targets to the bitstream
for (auto* target : targets) {
bitStream->Write(target->GetObjectID());
}

const auto distance = Vector3::DistanceSquared(reference, entity->GetPosition());

if (this->m_radius * this->m_radius >= distance && (this->m_maxTargets == 0 || targets.size() < this->m_maxTargets)) {
targets.push_back(entity);
// then cast all the actions
for (auto* target : targets) {
branch.target = target->GetObjectID();
this->m_action->Calculate(context, bitStream, branch);
}
}

std::sort(targets.begin(), targets.end(), [reference](Entity* a, Entity* b) {
const auto aDistance = Vector3::DistanceSquared(a->GetPosition(), reference);
const auto bDistance = Vector3::DistanceSquared(b->GetPosition(), reference);

return aDistance > bDistance;
});

const uint32_t size = targets.size();

bitStream->Write(size);

if (size == 0) {
return;
}

context->foundTarget = true;

for (auto* target : targets) {
bitStream->Write(target->GetObjectID());

PlayFx(u"cast", context->originator, target->GetObjectID());
}

for (auto* target : targets) {
branch.target = target->GetObjectID();

this->m_action->Calculate(context, bitStream, branch);
PlayFx(u"cast", context->originator);
}
}

void AreaOfEffectBehavior::Load() {
this->m_action = GetAction("action");

this->m_radius = GetFloat("radius");

this->m_maxTargets = GetInt("max targets");

this->m_ignoreFaction = GetInt("ignore_faction");

this->m_includeFaction = GetInt("include_faction");

this->m_TargetSelf = GetInt("target_self");

this->m_targetEnemy = GetInt("target_enemy");

this->m_targetFriend = GetInt("target_friend");
this->m_action = GetAction("action"); // required
this->m_radius = GetFloat("radius", 0.0f); // required
this->m_maxTargets = GetInt("max targets", 100);
if (this->m_maxTargets == 0) this->m_maxTargets = 100;
this->m_useTargetPosition = GetBoolean("use_target_position", false);
this->m_useTargetAsCaster = GetBoolean("use_target_as_caster", false);
this->m_offset = NiPoint3(
GetFloat("offset_x", 0.0f),
GetFloat("offset_y", 0.0f),
GetFloat("offset_z", 0.0f)
);

// params after this are needed for filter targets
const auto parameters = GetParameterNames();
for (const auto& parameter : parameters) {
if (parameter.first.rfind("include_faction", 0) == 0) {
this->m_includeFactionList.push_front(parameter.second);
} else if (parameter.first.rfind("ignore_faction", 0) == 0) {
this->m_ignoreFactionList.push_front(parameter.second);
}
}
this->m_targetSelf = GetBoolean("target_self", false);
this->m_targetEnemy = GetBoolean("target_enemy", false);
this->m_targetFriend = GetBoolean("target_friend", false);
this->m_targetTeam = GetBoolean("target_team", false);
}
40 changes: 16 additions & 24 deletions dGame/dBehaviors/AreaOfEffectBehavior.h
Original file line number Diff line number Diff line change
@@ -1,34 +1,26 @@
#pragma once
#include "Behavior.h"
#include <forward_list>

class AreaOfEffectBehavior final : public Behavior
{
public:
Behavior* m_action;

uint32_t m_maxTargets;

float m_radius;

int32_t m_ignoreFaction;

int32_t m_includeFaction;

int32_t m_TargetSelf;

int32_t m_targetEnemy;

int32_t m_targetFriend;

/*
* Inherited
*/
explicit AreaOfEffectBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {
}

explicit AreaOfEffectBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {}
void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;

void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;

void Load() override;
private:
Behavior* m_action;
uint32_t m_maxTargets;
float m_radius;
bool m_useTargetPosition;
bool m_useTargetAsCaster;
NiPoint3 m_offset;

std::forward_list<int32_t> m_ignoreFactionList {};
std::forward_list<int32_t> m_includeFactionList {};
bool m_targetSelf;
bool m_targetEnemy;
bool m_targetFriend;
bool m_targetTeam;
};
2 changes: 1 addition & 1 deletion dGame/dBehaviors/Behavior.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) {
case BehaviorTemplates::BEHAVIOR_SPEED:
behavior = new SpeedBehavior(behaviorId);
break;
case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION:
case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION:
behavior = new DarkInspirationBehavior(behaviorId);
break;
case BehaviorTemplates::BEHAVIOR_LOOT_BUFF:
Expand Down
Loading

0 comments on commit d8ac148

Please sign in to comment.