refactor: re-write AOE, add FilterTargets, Update TacArc Reading (#1035)

* 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 <EmosewaMC@gmail.com>
This commit is contained in:
Aaron Kimbrell
2023-10-09 15:18:51 -05:00
committed by GitHub
parent 471d65707c
commit d8ac148cee
18 changed files with 474 additions and 366 deletions

View File

@@ -15,6 +15,7 @@
#include "PhantomPhysicsComponent.h"
#include "RebuildComponent.h"
#include "eReplicaComponentType.h"
#include "TeamManager.h"
#include "eConnectionType.h"
BehaviorSyncEntry::BehaviorSyncEntry() {
@@ -307,46 +308,123 @@ void BehaviorContext::Reset() {
this->scheduledUpdates.clear();
}
std::vector<LWOOBJID> BehaviorContext::GetValidTargets(int32_t ignoreFaction, int32_t includeFaction, bool targetSelf, bool targetEnemy, bool targetFriend) const {
auto* entity = Game::entityManager->GetEntity(this->caster);
void BehaviorContext::FilterTargets(std::vector<Entity*>& targets, std::forward_list<int32_t>& ignoreFactionList, std::forward_list<int32_t>& includeFactionList, bool targetSelf, bool targetEnemy, bool targetFriend, bool targetTeam) const {
std::vector<LWOOBJID> targets;
if (entity == nullptr) {
Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator);
return targets;
// if we aren't targeting anything, then clear the targets vector
if (!targetSelf && !targetEnemy && !targetFriend && !targetTeam && ignoreFactionList.empty() && includeFactionList.empty()) {
targets.clear();
return;
}
if (!ignoreFaction && !includeFaction) {
for (auto entry : entity->GetTargetsInPhantom()) {
auto* instance = Game::entityManager->GetEntity(entry);
if (instance == nullptr) {
continue;
}
targets.push_back(entry);
}
// if the caster is not there, return empty targets list
auto* caster = Game::entityManager->GetEntity(this->caster);
if (!caster) {
Game::logger->LogDebug("BehaviorContext", "Invalid caster for (%llu)!", this->originator);
targets.clear();
return;
}
if (ignoreFaction || includeFaction || (!entity->HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) && targets.empty())) {
DestroyableComponent* destroyableComponent;
if (!entity->TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent)) {
return targets;
auto index = targets.begin();
while (index != targets.end()) {
auto candidate = *index;
// make sure we don't have a nullptr
if (!candidate) {
index = targets.erase(index);
continue;
}
auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS);
for (auto* candidate : entities) {
const auto id = candidate->GetObjectID();
// handle targeting the caster
if (candidate == caster){
// if we aren't targeting self, erase, otherise increment and continue
if (!targetSelf) index = targets.erase(index);
else index++;
continue;
}
if ((id != entity->GetObjectID() || targetSelf) && destroyableComponent->CheckValidity(id, ignoreFaction || includeFaction, targetEnemy, targetFriend)) {
targets.push_back(id);
// make sure that the entity is targetable
if (!CheckTargetingRequirements(candidate)) {
index = targets.erase(index);
continue;
}
// get factions to check against
// CheckTargetingRequirements checks for a destroyable component
// but we check again because bounds check are necessary
auto candidateDestroyableComponent = candidate->GetComponent<DestroyableComponent>();
if (!candidateDestroyableComponent) {
index = targets.erase(index);
continue;
}
// if they are dead, then earse and continue
if (candidateDestroyableComponent->GetIsDead()){
index = targets.erase(index);
continue;
}
// if their faction is explicitly included, increment and continue
auto candidateFactions = candidateDestroyableComponent->GetFactionIDs();
if (CheckFactionList(includeFactionList, candidateFactions)){
index++;
continue;
}
// check if they are a team member
if (targetTeam){
auto* team = TeamManager::Instance()->GetTeam(this->caster);
if (team){
// if we find a team member keep it and continue to skip enemy checks
if(std::find(team->members.begin(), team->members.end(), candidate->GetObjectID()) != team->members.end()){
index++;
continue;
}
}
}
}
return targets;
// if the caster doesn't have a destroyable component, return an empty targets list
auto* casterDestroyableComponent = caster->GetComponent<DestroyableComponent>();
if (!casterDestroyableComponent) {
targets.clear();
return;
}
// if we arent targeting a friend, and they are a friend OR
// if we are not targeting enemies and they are an enemy OR.
// if we are ignoring their faction is explicitly ignored
// erase and continue
auto isEnemy = casterDestroyableComponent->IsEnemy(candidate);
if ((!targetFriend && !isEnemy) ||
(!targetEnemy && isEnemy) ||
CheckFactionList(ignoreFactionList, candidateFactions)) {
index = targets.erase(index);
continue;
}
index++;
}
return;
}
// some basic checks as well as the check that matters for this: if the quickbuild is complete
bool BehaviorContext::CheckTargetingRequirements(const Entity* target) const {
// if the target is a nullptr, then it's not valid
if (!target) return false;
// ignore quickbuilds that aren't completed
auto* targetQuickbuildComponent = target->GetComponent<RebuildComponent>();
if (targetQuickbuildComponent && targetQuickbuildComponent->GetState() != eRebuildState::COMPLETED) return false;
return true;
}
// returns true if any of the object factions are in the faction list
bool BehaviorContext::CheckFactionList(std::forward_list<int32_t>& factionList, std::vector<int32_t>& objectsFactions) const {
if (factionList.empty() || objectsFactions.empty()) return false;
for (auto faction : factionList){
if(std::find(objectsFactions.begin(), objectsFactions.end(), faction) != objectsFactions.end()) return true;
}
return false;
}