AI: extracted into cpp files
parent
b3e9737e20
commit
e10a72f8e6
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#include "AI.h"
|
||||
|
||||
namespace ai {
|
||||
|
||||
TreeNodePtr AI::setBehaviour(const TreeNodePtr& newBehaviour) {
|
||||
TreeNodePtr current = _behaviour;
|
||||
_behaviour = newBehaviour;
|
||||
_reset = true;
|
||||
return current;
|
||||
}
|
||||
|
||||
void AI::update(int64_t dt, bool debuggingActive) {
|
||||
if (isPause()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_character) {
|
||||
_character->update(dt, debuggingActive);
|
||||
}
|
||||
|
||||
if (_reset) {
|
||||
// safe to do it like this, because update is not called from multiple threads
|
||||
_reset = false;
|
||||
_lastStatus.clear();
|
||||
_lastExecMillis.clear();
|
||||
_filteredEntities.clear();
|
||||
_selectorStates.clear();
|
||||
}
|
||||
|
||||
_debuggingActive = debuggingActive;
|
||||
_time += dt;
|
||||
_aggroMgr.update(dt);
|
||||
}
|
||||
|
||||
}
|
|
@ -201,13 +201,6 @@ inline TreeNodePtr AI::getBehaviour() const {
|
|||
return _behaviour;
|
||||
}
|
||||
|
||||
inline TreeNodePtr AI::setBehaviour(const TreeNodePtr& newBehaviour) {
|
||||
TreeNodePtr current = _behaviour;
|
||||
_behaviour = newBehaviour;
|
||||
_reset = true;
|
||||
return current;
|
||||
}
|
||||
|
||||
inline void AI::setPause(bool pause) {
|
||||
_pause = pause;
|
||||
}
|
||||
|
@ -272,29 +265,6 @@ inline CharacterId AI::getId() const {
|
|||
return _character->getId();
|
||||
}
|
||||
|
||||
inline void AI::update(int64_t dt, bool debuggingActive) {
|
||||
if (isPause()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_character) {
|
||||
_character->update(dt, debuggingActive);
|
||||
}
|
||||
|
||||
if (_reset) {
|
||||
// safe to do it like this, because update is not called from multiple threads
|
||||
_reset = false;
|
||||
_lastStatus.clear();
|
||||
_lastExecMillis.clear();
|
||||
_filteredEntities.clear();
|
||||
_selectorStates.clear();
|
||||
}
|
||||
|
||||
_debuggingActive = debuggingActive;
|
||||
_time += dt;
|
||||
_aggroMgr.update(dt);
|
||||
}
|
||||
|
||||
typedef std::shared_ptr<AI> AIPtr;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
set(SRCS
|
||||
aggro/AggroMgr.h
|
||||
aggro/AggroMgr.h aggro/AggroMgr.cpp
|
||||
aggro/Entry.h
|
||||
AI.h
|
||||
AI.h AI.cpp
|
||||
AIFactories.h
|
||||
AIRegistry.h AIRegistry.cpp
|
||||
common/IFactoryRegistry.h
|
||||
|
@ -44,7 +44,7 @@ set(SRCS
|
|||
IAIFactory.h
|
||||
ICharacter.h
|
||||
group/GroupId.h
|
||||
group/GroupMgr.h
|
||||
group/GroupMgr.h group/GroupMgr.cpp
|
||||
movement/SelectionSeek.h
|
||||
movement/GroupFlee.h
|
||||
movement/GroupSeek.h
|
||||
|
@ -79,7 +79,7 @@ set(SRCS
|
|||
server/Server.h server/Server.cpp
|
||||
server/StepHandler.h
|
||||
server/UpdateNodeHandler.h
|
||||
zone/Zone.h
|
||||
zone/Zone.h zone/Zone.cpp
|
||||
SimpleAI.h
|
||||
tree/Fail.h
|
||||
tree/Limit.h
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#include "AggroMgr.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace ai {
|
||||
|
||||
class CharacterIdPredicate {
|
||||
private:
|
||||
const CharacterId& _id;
|
||||
public:
|
||||
explicit CharacterIdPredicate(const CharacterId& id) :
|
||||
_id(id) {
|
||||
}
|
||||
|
||||
inline bool operator()(const Entry &n1) {
|
||||
return n1.getCharacterId() == _id;
|
||||
}
|
||||
};
|
||||
|
||||
static bool EntrySorter(const Entry& a, const Entry& b) {
|
||||
if (a.getAggro() > b.getAggro()) {
|
||||
return false;
|
||||
}
|
||||
if (::fabs(a.getAggro() - b.getAggro()) < 0.0000001f) {
|
||||
return a.getCharacterId() < b.getCharacterId();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove the entries from the list that have no aggro left.
|
||||
* This list is ordered, so we will only remove the first X elements.
|
||||
*/
|
||||
void AggroMgr::cleanupList() {
|
||||
EntriesIter::difference_type remove = 0;
|
||||
for (EntriesIter i = _entries.begin(); i != _entries.end(); ++i) {
|
||||
const float aggroValue = i->getAggro();
|
||||
if (aggroValue > 0.0f) {
|
||||
break;
|
||||
}
|
||||
|
||||
++remove;
|
||||
}
|
||||
|
||||
if (remove == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int size = static_cast<int>(_entries.size());
|
||||
if (size == remove) {
|
||||
_entries.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
EntriesIter i = _entries.begin();
|
||||
std::advance(i, remove);
|
||||
_entries.erase(_entries.begin(), i);
|
||||
}
|
||||
|
||||
void AggroMgr::sort() const {
|
||||
if (!_dirty) {
|
||||
return;
|
||||
}
|
||||
std::sort(_entries.begin(), _entries.end(), EntrySorter);
|
||||
_dirty = false;
|
||||
}
|
||||
|
||||
void AggroMgr::setReduceByRatio(float reduceRatioSecond, float minAggro) {
|
||||
_reduceType = RATIO;
|
||||
_reduceValueSecond = 0.0f;
|
||||
_reduceRatioSecond = reduceRatioSecond;
|
||||
_minAggro = minAggro;
|
||||
}
|
||||
|
||||
void AggroMgr::setReduceByValue(float reduceValueSecond) {
|
||||
_reduceType = VALUE;
|
||||
_reduceValueSecond = reduceValueSecond;
|
||||
_reduceRatioSecond = 0.0f;
|
||||
_minAggro = 0.0f;
|
||||
}
|
||||
|
||||
void AggroMgr::resetReduceValue() {
|
||||
_reduceType = DISABLED;
|
||||
_reduceValueSecond = 0.0f;
|
||||
_reduceRatioSecond = 0.0f;
|
||||
_minAggro = 0.0f;
|
||||
}
|
||||
|
||||
void AggroMgr::update(int64_t deltaMillis) {
|
||||
for (EntriesIter i = _entries.begin(); i != _entries.end(); ++i) {
|
||||
_dirty |= i->reduceByTime(deltaMillis);
|
||||
}
|
||||
|
||||
if (_dirty) {
|
||||
sort();
|
||||
cleanupList();
|
||||
}
|
||||
}
|
||||
|
||||
EntryPtr AggroMgr::addAggro(CharacterId id, float amount) {
|
||||
const CharacterIdPredicate p(id);
|
||||
EntriesIter i = std::find_if(_entries.begin(), _entries.end(), p);
|
||||
if (i == _entries.end()) {
|
||||
Entry newEntry(id, amount);
|
||||
switch (_reduceType) {
|
||||
case RATIO:
|
||||
newEntry.setReduceByRatio(_reduceRatioSecond, _minAggro);
|
||||
break;
|
||||
case VALUE:
|
||||
newEntry.setReduceByValue(_reduceValueSecond);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_entries.push_back(newEntry);
|
||||
_dirty = true;
|
||||
return &_entries.back();
|
||||
}
|
||||
|
||||
i->addAggro(amount);
|
||||
_dirty = true;
|
||||
return &*i;
|
||||
}
|
||||
|
||||
EntryPtr AggroMgr::getHighestEntry() const {
|
||||
if (_entries.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sort();
|
||||
|
||||
return &_entries.back();
|
||||
}
|
||||
|
||||
}
|
|
@ -10,7 +10,6 @@
|
|||
#include <vector>
|
||||
#include <memory>
|
||||
#include "ICharacter.h"
|
||||
#include <algorithm>
|
||||
#include "aggro/Entry.h"
|
||||
|
||||
namespace ai {
|
||||
|
@ -32,66 +31,13 @@ protected:
|
|||
float _reduceValueSecond = 0.0f;
|
||||
ReductionType _reduceType = DISABLED;
|
||||
|
||||
class CharacterIdPredicate {
|
||||
private:
|
||||
const CharacterId& _id;
|
||||
public:
|
||||
explicit CharacterIdPredicate(const CharacterId& id) :
|
||||
_id(id) {
|
||||
}
|
||||
|
||||
inline bool operator()(const Entry &n1) {
|
||||
return n1.getCharacterId() == _id;
|
||||
}
|
||||
};
|
||||
|
||||
static bool EntrySorter(const Entry& a, const Entry& b) {
|
||||
if (a.getAggro() > b.getAggro()) {
|
||||
return false;
|
||||
}
|
||||
if (::fabs(a.getAggro() - b.getAggro()) < 0.0000001f) {
|
||||
return a.getCharacterId() < b.getCharacterId();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove the entries from the list that have no aggro left.
|
||||
* This list is ordered, so we will only remove the first X elements.
|
||||
*/
|
||||
void cleanupList() {
|
||||
EntriesIter::difference_type remove = 0;
|
||||
for (EntriesIter i = _entries.begin(); i != _entries.end(); ++i) {
|
||||
const float aggroValue = i->getAggro();
|
||||
if (aggroValue > 0.0f) {
|
||||
break;
|
||||
}
|
||||
void cleanupList();
|
||||
|
||||
++remove;
|
||||
}
|
||||
|
||||
if (remove == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int size = static_cast<int>(_entries.size());
|
||||
if (size == remove) {
|
||||
_entries.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
EntriesIter i = _entries.begin();
|
||||
std::advance(i, remove);
|
||||
_entries.erase(_entries.begin(), i);
|
||||
}
|
||||
|
||||
inline void sort() const {
|
||||
if (!_dirty) {
|
||||
return;
|
||||
}
|
||||
std::sort(_entries.begin(), _entries.end(), EntrySorter);
|
||||
_dirty = false;
|
||||
}
|
||||
inline void sort() const;
|
||||
public:
|
||||
explicit AggroMgr(std::size_t expectedEntrySize = 0u) :
|
||||
_dirty(false) {
|
||||
|
@ -103,41 +49,17 @@ public:
|
|||
virtual ~AggroMgr() {
|
||||
}
|
||||
|
||||
inline void setReduceByRatio(float reduceRatioSecond, float minAggro) {
|
||||
_reduceType = RATIO;
|
||||
_reduceValueSecond = 0.0f;
|
||||
_reduceRatioSecond = reduceRatioSecond;
|
||||
_minAggro = minAggro;
|
||||
}
|
||||
void setReduceByRatio(float reduceRatioSecond, float minAggro);
|
||||
|
||||
inline void setReduceByValue(float reduceValueSecond) {
|
||||
_reduceType = VALUE;
|
||||
_reduceValueSecond = reduceValueSecond;
|
||||
_reduceRatioSecond = 0.0f;
|
||||
_minAggro = 0.0f;
|
||||
}
|
||||
void setReduceByValue(float reduceValueSecond);
|
||||
|
||||
inline void resetReduceValue() {
|
||||
_reduceType = DISABLED;
|
||||
_reduceValueSecond = 0.0f;
|
||||
_reduceRatioSecond = 0.0f;
|
||||
_minAggro = 0.0f;
|
||||
}
|
||||
void resetReduceValue();
|
||||
|
||||
/**
|
||||
* @brief this will update the aggro list according to the reduction type of an entry.
|
||||
* @param[in] deltaMillis The current milliseconds to use to update the aggro value of the entries.
|
||||
*/
|
||||
void update(int64_t deltaMillis) {
|
||||
for (EntriesIter i = _entries.begin(); i != _entries.end(); ++i) {
|
||||
_dirty |= i->reduceByTime(deltaMillis);
|
||||
}
|
||||
|
||||
if (_dirty) {
|
||||
sort();
|
||||
cleanupList();
|
||||
}
|
||||
}
|
||||
void update(int64_t deltaMillis);
|
||||
|
||||
/**
|
||||
* @brief will increase the aggro
|
||||
|
@ -145,30 +67,7 @@ public:
|
|||
* @param[in] amount The amount to increase the aggro for
|
||||
* @return The aggro @c Entry that was added or updated. Useful for changing the reduce type or amount.
|
||||
*/
|
||||
EntryPtr addAggro(CharacterId id, float amount) {
|
||||
const CharacterIdPredicate p(id);
|
||||
EntriesIter i = std::find_if(_entries.begin(), _entries.end(), p);
|
||||
if (i == _entries.end()) {
|
||||
Entry newEntry(id, amount);
|
||||
switch (_reduceType) {
|
||||
case RATIO:
|
||||
newEntry.setReduceByRatio(_reduceRatioSecond, _minAggro);
|
||||
break;
|
||||
case VALUE:
|
||||
newEntry.setReduceByValue(_reduceValueSecond);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_entries.push_back(newEntry);
|
||||
_dirty = true;
|
||||
return &_entries.back();
|
||||
}
|
||||
|
||||
i->addAggro(amount);
|
||||
_dirty = true;
|
||||
return &*i;
|
||||
}
|
||||
EntryPtr addAggro(CharacterId id, float amount);
|
||||
|
||||
/**
|
||||
* @return All the aggro entries
|
||||
|
@ -182,15 +81,7 @@ public:
|
|||
*
|
||||
* @note Might execute a sort on the list if its dirty
|
||||
*/
|
||||
EntryPtr getHighestEntry() const {
|
||||
if (_entries.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sort();
|
||||
|
||||
return &_entries.back();
|
||||
}
|
||||
EntryPtr getHighestEntry() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#include "GroupMgr.h"
|
||||
|
||||
namespace ai {
|
||||
|
||||
struct AveragePositionFunctor {
|
||||
glm::vec3 operator()(const glm::vec3& result, const AIPtr& ai) {
|
||||
return ai->getCharacter()->getPosition() + result;
|
||||
}
|
||||
};
|
||||
|
||||
void GroupMgr::update(int64_t) {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
for (auto i = _groups.begin(); i != _groups.end(); ++i) {
|
||||
Group& group = i->second;
|
||||
glm::vec3 averagePosition(0.0f);
|
||||
{
|
||||
ScopedReadLock lock(_groupLock);
|
||||
averagePosition = std::accumulate(group.members.begin(), group.members.end(), glm::vec3(0.0f), AveragePositionFunctor());
|
||||
averagePosition *= 1.0f / (float) group.members.size();
|
||||
}
|
||||
ScopedWriteLock lock(_groupLock);
|
||||
group.position = averagePosition;
|
||||
}
|
||||
}
|
||||
|
||||
bool GroupMgr::add(GroupId id, const AIPtr& ai) {
|
||||
ScopedWriteLock scopedLock(_lock);
|
||||
GroupsIter i = _groups.find(id);
|
||||
if (i == _groups.end()) {
|
||||
Group group;
|
||||
group.leader = ai;
|
||||
i = _groups.insert(std::pair<GroupId, Group>(id, group)).first;
|
||||
}
|
||||
|
||||
Group& group = i->second;
|
||||
ScopedWriteLock lock(_groupLock);
|
||||
std::pair<GroupMembersSetIter, bool> ret = group.members.insert(ai);
|
||||
if (ret.second) {
|
||||
_groupMembers.insert(GroupMembers::value_type(ai, id));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GroupMgr::remove(GroupId id, const AIPtr& ai) {
|
||||
ScopedWriteLock scopedLock(_lock);
|
||||
const GroupsIter& i = _groups.find(id);
|
||||
if (i == _groups.end()) {
|
||||
return false;
|
||||
}
|
||||
Group& group = i->second;
|
||||
GroupMembersSetIter si;
|
||||
{
|
||||
ScopedReadLock lock(_groupLock);
|
||||
si = group.members.find(ai);
|
||||
if (si == group.members.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
{
|
||||
ScopedWriteLock lock(_groupLock);
|
||||
group.members.erase(si);
|
||||
if (group.members.empty()) {
|
||||
_groups.erase(i);
|
||||
} else if (group.leader == ai) {
|
||||
group.leader = *group.members.begin();
|
||||
}
|
||||
}
|
||||
|
||||
auto range = _groupMembers.equal_range(ai);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
if (it->second == id) {
|
||||
_groupMembers.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GroupMgr::removeFromAllGroups(const AIPtr& ai) {
|
||||
std::list<GroupId> groups;
|
||||
{
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
auto range = _groupMembers.equal_range(ai);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
groups.push_back(it->second);
|
||||
}
|
||||
}
|
||||
for (GroupId groupId : groups) {
|
||||
remove(groupId, ai);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AIPtr GroupMgr::getLeader(GroupId id) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
const GroupsConstIter& i = _groups.find(id);
|
||||
if (i == _groups.end()) {
|
||||
return AIPtr();
|
||||
}
|
||||
|
||||
ScopedReadLock lock(_groupLock);
|
||||
return i->second.leader;
|
||||
}
|
||||
|
||||
glm::vec3 GroupMgr::getPosition(GroupId id) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
const GroupsConstIter& i = _groups.find(id);
|
||||
if (i == _groups.end()) {
|
||||
return VEC3_INFINITE;
|
||||
}
|
||||
|
||||
ScopedReadLock lock(_groupLock);
|
||||
return i->second.position;
|
||||
}
|
||||
|
||||
bool GroupMgr::isGroupLeader(GroupId id, const AIPtr& ai) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
const GroupsConstIter& i = _groups.find(id);
|
||||
if (i == _groups.end()) {
|
||||
return 0;
|
||||
}
|
||||
ScopedReadLock lock(_groupLock);
|
||||
return i->second.leader == ai;
|
||||
}
|
||||
|
||||
int GroupMgr::getGroupSize(GroupId id) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
const GroupsConstIter& i = _groups.find(id);
|
||||
if (i == _groups.end()) {
|
||||
return 0;
|
||||
}
|
||||
ScopedReadLock lock(_groupLock);
|
||||
return static_cast<int>(std::distance(i->second.members.begin(), i->second.members.end()));
|
||||
}
|
||||
|
||||
bool GroupMgr::isInAnyGroup(const AIPtr& ai) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
return _groupMembers.find(ai) != _groupMembers.end();
|
||||
}
|
||||
|
||||
bool GroupMgr::isInGroup(GroupId id, const AIPtr& ai) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
auto range = _groupMembers.equal_range(ai);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
if (it->second == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/Thread.h"
|
||||
|
@ -26,12 +27,6 @@ namespace ai {
|
|||
*/
|
||||
class GroupMgr {
|
||||
private:
|
||||
struct AveragePositionFunctor {
|
||||
glm::vec3 operator()(const glm::vec3& result, const AIPtr& ai) {
|
||||
return ai->getCharacter()->getPosition() + result;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::unordered_set<AIPtr> GroupMembersSet;
|
||||
typedef GroupMembersSet::iterator GroupMembersSetIter;
|
||||
typedef GroupMembersSet::const_iterator GroupMembersSetConstIter;
|
||||
|
@ -160,147 +155,4 @@ public:
|
|||
bool isGroupLeader(GroupId id, const AIPtr& ai) const;
|
||||
};
|
||||
|
||||
|
||||
inline void GroupMgr::update(int64_t) {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
for (auto i = _groups.begin(); i != _groups.end(); ++i) {
|
||||
Group& group = i->second;
|
||||
glm::vec3 averagePosition(0.0f);
|
||||
{
|
||||
ScopedReadLock lock(_groupLock);
|
||||
averagePosition = std::accumulate(group.members.begin(), group.members.end(), glm::vec3(0.0f), AveragePositionFunctor());
|
||||
averagePosition *= 1.0f / (float) group.members.size();
|
||||
}
|
||||
ScopedWriteLock lock(_groupLock);
|
||||
group.position = averagePosition;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool GroupMgr::add(GroupId id, const AIPtr& ai) {
|
||||
ScopedWriteLock scopedLock(_lock);
|
||||
GroupsIter i = _groups.find(id);
|
||||
if (i == _groups.end()) {
|
||||
Group group;
|
||||
group.leader = ai;
|
||||
i = _groups.insert(std::pair<GroupId, Group>(id, group)).first;
|
||||
}
|
||||
|
||||
Group& group = i->second;
|
||||
ScopedWriteLock lock(_groupLock);
|
||||
std::pair<GroupMembersSetIter, bool> ret = group.members.insert(ai);
|
||||
if (ret.second) {
|
||||
_groupMembers.insert(GroupMembers::value_type(ai, id));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool GroupMgr::remove(GroupId id, const AIPtr& ai) {
|
||||
ScopedWriteLock scopedLock(_lock);
|
||||
const GroupsIter& i = _groups.find(id);
|
||||
if (i == _groups.end()) {
|
||||
return false;
|
||||
}
|
||||
Group& group = i->second;
|
||||
GroupMembersSetIter si;
|
||||
{
|
||||
ScopedReadLock lock(_groupLock);
|
||||
si = group.members.find(ai);
|
||||
if (si == group.members.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
{
|
||||
ScopedWriteLock lock(_groupLock);
|
||||
group.members.erase(si);
|
||||
if (group.members.empty()) {
|
||||
_groups.erase(i);
|
||||
} else if (group.leader == ai) {
|
||||
group.leader = *group.members.begin();
|
||||
}
|
||||
}
|
||||
|
||||
auto range = _groupMembers.equal_range(ai);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
if (it->second == id) {
|
||||
_groupMembers.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool GroupMgr::removeFromAllGroups(const AIPtr& ai) {
|
||||
std::list<GroupId> groups;
|
||||
{
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
auto range = _groupMembers.equal_range(ai);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
groups.push_back(it->second);
|
||||
}
|
||||
}
|
||||
for (GroupId groupId : groups) {
|
||||
remove(groupId, ai);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline AIPtr GroupMgr::getLeader(GroupId id) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
const GroupsConstIter& i = _groups.find(id);
|
||||
if (i == _groups.end()) {
|
||||
return AIPtr();
|
||||
}
|
||||
|
||||
ScopedReadLock lock(_groupLock);
|
||||
return i->second.leader;
|
||||
}
|
||||
|
||||
inline glm::vec3 GroupMgr::getPosition(GroupId id) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
const GroupsConstIter& i = _groups.find(id);
|
||||
if (i == _groups.end()) {
|
||||
return VEC3_INFINITE;
|
||||
}
|
||||
|
||||
ScopedReadLock lock(_groupLock);
|
||||
return i->second.position;
|
||||
}
|
||||
|
||||
inline bool GroupMgr::isGroupLeader(GroupId id, const AIPtr& ai) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
const GroupsConstIter& i = _groups.find(id);
|
||||
if (i == _groups.end()) {
|
||||
return 0;
|
||||
}
|
||||
ScopedReadLock lock(_groupLock);
|
||||
return i->second.leader == ai;
|
||||
}
|
||||
|
||||
inline int GroupMgr::getGroupSize(GroupId id) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
const GroupsConstIter& i = _groups.find(id);
|
||||
if (i == _groups.end()) {
|
||||
return 0;
|
||||
}
|
||||
ScopedReadLock lock(_groupLock);
|
||||
return static_cast<int>(std::distance(i->second.members.begin(), i->second.members.end()));
|
||||
}
|
||||
|
||||
inline bool GroupMgr::isInAnyGroup(const AIPtr& ai) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
return _groupMembers.find(ai) != _groupMembers.end();
|
||||
}
|
||||
|
||||
inline bool GroupMgr::isInGroup(GroupId id, const AIPtr& ai) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
auto range = _groupMembers.equal_range(ai);
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
if (it->second == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#include "Zone.h"
|
||||
|
||||
namespace ai {
|
||||
|
||||
AIPtr Zone::getAI(CharacterId id) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
auto i = _ais.find(id);
|
||||
if (i == _ais.end()) {
|
||||
return AIPtr();
|
||||
}
|
||||
const AIPtr& ai = i->second;
|
||||
return ai;
|
||||
}
|
||||
|
||||
std::size_t Zone::size() const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
return _ais.size();
|
||||
}
|
||||
|
||||
bool Zone::doAddAI(const AIPtr& ai) {
|
||||
if (ai == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const CharacterId& id = ai->getCharacter()->getId();
|
||||
if (_ais.find(id) != _ais.end()) {
|
||||
return false;
|
||||
}
|
||||
_ais.insert(std::make_pair(id, ai));
|
||||
ai->setZone(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Zone::doRemoveAI(const AIPtr& ai) {
|
||||
if (!ai) {
|
||||
return false;
|
||||
}
|
||||
const CharacterId& id = ai->getCharacter()->getId();
|
||||
AIMapIter i = _ais.find(id);
|
||||
if (i == _ais.end()) {
|
||||
return false;
|
||||
}
|
||||
i->second->setZone(nullptr);
|
||||
_groupManager.removeFromAllGroups(i->second);
|
||||
_ais.erase(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Zone::doDestroyAI(const CharacterId& id) {
|
||||
AIMapIter i = _ais.find(id);
|
||||
if (i == _ais.end()) {
|
||||
return false;
|
||||
}
|
||||
_ais.erase(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Zone::addAI(const AIPtr& ai) {
|
||||
if (!ai) {
|
||||
return false;
|
||||
}
|
||||
ScopedWriteLock scopedLock(_scheduleLock);
|
||||
_scheduledAdd.push_back(ai);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Zone::destroyAI(const CharacterId& id) {
|
||||
ScopedWriteLock scopedLock(_scheduleLock);
|
||||
_scheduledDestroy.push_back(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Zone::removeAI(const AIPtr& ai) {
|
||||
if (!ai) {
|
||||
return false;
|
||||
}
|
||||
ScopedWriteLock scopedLock(_scheduleLock);
|
||||
_scheduledRemove.push_back(ai);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Zone::update(int64_t dt) {
|
||||
{
|
||||
AIScheduleList scheduledRemove;
|
||||
AIScheduleList scheduledAdd;
|
||||
CharacterIdList scheduledDestroy;
|
||||
{
|
||||
ScopedWriteLock scopedLock(_scheduleLock);
|
||||
scheduledAdd.swap(_scheduledAdd);
|
||||
scheduledRemove.swap(_scheduledRemove);
|
||||
scheduledDestroy.swap(_scheduledDestroy);
|
||||
}
|
||||
ScopedWriteLock scopedLock(_lock);
|
||||
for (const AIPtr& ai : scheduledAdd) {
|
||||
doAddAI(ai);
|
||||
}
|
||||
scheduledAdd.clear();
|
||||
for (const AIPtr& ai : scheduledRemove) {
|
||||
doRemoveAI(ai);
|
||||
}
|
||||
scheduledRemove.clear();
|
||||
for (auto id : scheduledDestroy) {
|
||||
doDestroyAI(id);
|
||||
}
|
||||
scheduledDestroy.clear();
|
||||
}
|
||||
|
||||
auto func = [&] (const AIPtr& ai) {
|
||||
if (ai->isPause()) {
|
||||
return;
|
||||
}
|
||||
ai->update(dt, _debug);
|
||||
ai->getBehaviour()->execute(ai, dt);
|
||||
};
|
||||
executeParallel(func);
|
||||
_groupManager.update(dt);
|
||||
}
|
||||
|
||||
}
|
|
@ -171,15 +171,7 @@ public:
|
|||
*
|
||||
* @note This locks the zone for reading to perform the CharacterId lookup
|
||||
*/
|
||||
inline AIPtr getAI(CharacterId id) const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
auto i = _ais.find(id);
|
||||
if (i == _ais.end()) {
|
||||
return AIPtr();
|
||||
}
|
||||
const AIPtr& ai = i->second;
|
||||
return ai;
|
||||
}
|
||||
AIPtr getAI(CharacterId id) const;
|
||||
|
||||
/**
|
||||
* @brief Executes a lambda or functor for the given character
|
||||
|
@ -328,10 +320,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
inline std::size_t size() const {
|
||||
ScopedReadLock scopedLock(_lock);
|
||||
return _ais.size();
|
||||
}
|
||||
std::size_t size() const;
|
||||
};
|
||||
|
||||
inline void Zone::setDebug (bool debug) {
|
||||
|
@ -354,102 +343,4 @@ inline const GroupMgr& Zone::getGroupMgr() const {
|
|||
return _groupManager;
|
||||
}
|
||||
|
||||
inline bool Zone::doAddAI(const AIPtr& ai) {
|
||||
if (ai == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const CharacterId& id = ai->getCharacter()->getId();
|
||||
if (_ais.find(id) != _ais.end()) {
|
||||
return false;
|
||||
}
|
||||
_ais.insert(std::make_pair(id, ai));
|
||||
ai->setZone(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Zone::doRemoveAI(const AIPtr& ai) {
|
||||
if (!ai) {
|
||||
return false;
|
||||
}
|
||||
const CharacterId& id = ai->getCharacter()->getId();
|
||||
AIMapIter i = _ais.find(id);
|
||||
if (i == _ais.end()) {
|
||||
return false;
|
||||
}
|
||||
i->second->setZone(nullptr);
|
||||
_groupManager.removeFromAllGroups(i->second);
|
||||
_ais.erase(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Zone::doDestroyAI(const CharacterId& id) {
|
||||
AIMapIter i = _ais.find(id);
|
||||
if (i == _ais.end()) {
|
||||
return false;
|
||||
}
|
||||
_ais.erase(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Zone::addAI(const AIPtr& ai) {
|
||||
if (!ai) {
|
||||
return false;
|
||||
}
|
||||
ScopedWriteLock scopedLock(_scheduleLock);
|
||||
_scheduledAdd.push_back(ai);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Zone::destroyAI(const CharacterId& id) {
|
||||
ScopedWriteLock scopedLock(_scheduleLock);
|
||||
_scheduledDestroy.push_back(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Zone::removeAI(const AIPtr& ai) {
|
||||
if (!ai) {
|
||||
return false;
|
||||
}
|
||||
ScopedWriteLock scopedLock(_scheduleLock);
|
||||
_scheduledRemove.push_back(ai);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void Zone::update(int64_t dt) {
|
||||
{
|
||||
AIScheduleList scheduledRemove;
|
||||
AIScheduleList scheduledAdd;
|
||||
CharacterIdList scheduledDestroy;
|
||||
{
|
||||
ScopedWriteLock scopedLock(_scheduleLock);
|
||||
scheduledAdd.swap(_scheduledAdd);
|
||||
scheduledRemove.swap(_scheduledRemove);
|
||||
scheduledDestroy.swap(_scheduledDestroy);
|
||||
}
|
||||
ScopedWriteLock scopedLock(_lock);
|
||||
for (const AIPtr& ai : scheduledAdd) {
|
||||
doAddAI(ai);
|
||||
}
|
||||
scheduledAdd.clear();
|
||||
for (const AIPtr& ai : scheduledRemove) {
|
||||
doRemoveAI(ai);
|
||||
}
|
||||
scheduledRemove.clear();
|
||||
for (auto id : scheduledDestroy) {
|
||||
doDestroyAI(id);
|
||||
}
|
||||
scheduledDestroy.clear();
|
||||
}
|
||||
|
||||
auto func = [&] (const AIPtr& ai) {
|
||||
if (ai->isPause()) {
|
||||
return;
|
||||
}
|
||||
ai->update(dt, _debug);
|
||||
ai->getBehaviour()->execute(ai, dt);
|
||||
};
|
||||
executeParallel(func);
|
||||
_groupManager.update(dt);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue