SimpleAI
 All Classes Namespaces Files Functions Variables Typedefs Macros Groups Pages
GroupMgr.h
Go to the documentation of this file.
1 
4 #pragma once
5 
6 #include "common/Thread.h"
7 #include "common/Types.h"
8 #include "common/Math.h"
9 #include "ICharacter.h"
10 #include "AI.h"
11 #include <map>
12 #include <memory>
13 #include <numeric>
14 #include <unordered_map>
15 #include <unordered_set>
16 
17 namespace ai {
18 
27 class GroupMgr {
28 private:
29  struct AveragePositionFunctor {
30  glm::vec3 operator()(const glm::vec3& result, const AIPtr& ai) {
31  return ai->getCharacter()->getPosition() + result;
32  }
33  };
34 
35  typedef std::unordered_set<AIPtr> GroupMembersSet;
36  typedef GroupMembersSet::iterator GroupMembersSetIter;
37  typedef GroupMembersSet::const_iterator GroupMembersSetConstIter;
38 
39  ReadWriteLock _groupLock = {"groupmgr-group"};
40  struct Group {
41  AIPtr leader;
42  GroupMembersSet members;
43  glm::vec3 position;
44  };
45 
46  typedef std::unordered_multimap<AIPtr, GroupId> GroupMembers;
47  typedef std::unordered_map<GroupId, Group> Groups;
48  typedef Groups::const_iterator GroupsConstIter;
49  typedef Groups::iterator GroupsIter;
50 
51  GroupMembersSet _empty;
52  ReadWriteLock _lock = {"groupmgr"};
53  Groups _groups;
54  GroupMembers _groupMembers;
55 
56 public:
57  GroupMgr () {
58  }
59  virtual ~GroupMgr () {
60  }
61 
76  bool add(GroupId id, const AIPtr& ai);
77 
78  void update(int64_t deltaTime);
79 
93  bool remove(GroupId id, const AIPtr& ai);
94 
101  bool removeFromAllGroups(const AIPtr& ai);
102 
111  glm::vec3 getPosition(GroupId id) const;
112 
118  AIPtr getLeader(GroupId id) const;
119 
125  template<typename Func>
126  void visit(GroupId id, Func& func) const {
127  ScopedReadLock scopedLock(_lock);
128  const GroupsConstIter& i = _groups.find(id);
129  if (i == _groups.end()) {
130  return;
131  }
132  for (GroupMembersSetConstIter it = i->second.members.begin(); it != i->second.members.end(); ++it) {
133  const AIPtr& chr = *it;
134  if (!func(chr))
135  break;
136  }
137  }
138 
145  int getGroupSize(GroupId id) const;
146 
150  bool isInAnyGroup(const AIPtr& ai) const;
151 
155  bool isInGroup(GroupId id, const AIPtr& ai) const;
156 
160  bool isGroupLeader(GroupId id, const AIPtr& ai) const;
161 };
162 
163 
164 inline void GroupMgr::update(int64_t) {
165  ScopedReadLock scopedLock(_lock);
166  for (auto i = _groups.begin(); i != _groups.end(); ++i) {
167  Group& group = i->second;
168  glm::vec3 averagePosition(0.0f);
169  {
170  ScopedReadLock lock(_groupLock);
171  averagePosition = std::accumulate(group.members.begin(), group.members.end(), glm::vec3(0.0f), AveragePositionFunctor());
172  averagePosition *= 1.0f / (float) group.members.size();
173  }
174  ScopedWriteLock lock(_groupLock);
175  group.position = averagePosition;
176  }
177 }
178 
179 inline bool GroupMgr::add(GroupId id, const AIPtr& ai) {
180  ScopedWriteLock scopedLock(_lock);
181  GroupsIter i = _groups.find(id);
182  if (i == _groups.end()) {
183  Group group;
184  group.leader = ai;
185  i = _groups.insert(std::pair<GroupId, Group>(id, group)).first;
186  }
187 
188  Group& group = i->second;
189  ScopedWriteLock lock(_groupLock);
190  std::pair<GroupMembersSetIter, bool> ret = group.members.insert(ai);
191  if (ret.second) {
192  _groupMembers.insert(GroupMembers::value_type(ai, id));
193  return true;
194  }
195  return false;
196 }
197 
198 inline bool GroupMgr::remove(GroupId id, const AIPtr& ai) {
199  ScopedWriteLock scopedLock(_lock);
200  const GroupsIter& i = _groups.find(id);
201  if (i == _groups.end()) {
202  return false;
203  }
204  Group& group = i->second;
205  GroupMembersSetIter si;
206  {
207  ScopedReadLock lock(_groupLock);
208  si = group.members.find(ai);
209  if (si == group.members.end()) {
210  return false;
211  }
212  }
213  {
214  ScopedWriteLock lock(_groupLock);
215  group.members.erase(si);
216  if (group.members.empty()) {
217  _groups.erase(i);
218  } else if (group.leader == ai) {
219  group.leader = *group.members.begin();
220  }
221  }
222 
223  auto range = _groupMembers.equal_range(ai);
224  for (auto it = range.first; it != range.second; ++it) {
225  if (it->second == id) {
226  _groupMembers.erase(it);
227  break;
228  }
229  }
230  return true;
231 }
232 
233 inline bool GroupMgr::removeFromAllGroups(const AIPtr& ai) {
234  std::list<GroupId> groups;
235  {
236  ScopedReadLock scopedLock(_lock);
237  auto range = _groupMembers.equal_range(ai);
238  for (auto it = range.first; it != range.second; ++it) {
239  groups.push_back(it->second);
240  }
241  }
242  for (GroupId groupId : groups) {
243  remove(groupId, ai);
244  }
245  return true;
246 }
247 
248 inline AIPtr GroupMgr::getLeader(GroupId id) const {
249  ScopedReadLock scopedLock(_lock);
250  const GroupsConstIter& i = _groups.find(id);
251  if (i == _groups.end()) {
252  return AIPtr();
253  }
254 
255  ScopedReadLock lock(_groupLock);
256  return i->second.leader;
257 }
258 
259 inline glm::vec3 GroupMgr::getPosition(GroupId id) const {
260  ScopedReadLock scopedLock(_lock);
261  const GroupsConstIter& i = _groups.find(id);
262  if (i == _groups.end()) {
263  return VEC3_INFINITE;
264  }
265 
266  ScopedReadLock lock(_groupLock);
267  return i->second.position;
268 }
269 
270 inline bool GroupMgr::isGroupLeader(GroupId id, const AIPtr& ai) const {
271  ScopedReadLock scopedLock(_lock);
272  const GroupsConstIter& i = _groups.find(id);
273  if (i == _groups.end()) {
274  return 0;
275  }
276  ScopedReadLock lock(_groupLock);
277  return i->second.leader == ai;
278 }
279 
280 inline int GroupMgr::getGroupSize(GroupId id) const {
281  ScopedReadLock scopedLock(_lock);
282  const GroupsConstIter& i = _groups.find(id);
283  if (i == _groups.end()) {
284  return 0;
285  }
286  ScopedReadLock lock(_groupLock);
287  return static_cast<int>(std::distance(i->second.members.begin(), i->second.members.end()));
288 }
289 
290 inline bool GroupMgr::isInAnyGroup(const AIPtr& ai) const {
291  ScopedReadLock scopedLock(_lock);
292  return _groupMembers.find(ai) != _groupMembers.end();
293 }
294 
295 inline bool GroupMgr::isInGroup(GroupId id, const AIPtr& ai) const {
296  ScopedReadLock scopedLock(_lock);
297  auto range = _groupMembers.equal_range(ai);
298  for (auto it = range.first; it != range.second; ++it) {
299  if (it->second == id) {
300  return true;
301  }
302  }
303  return false;
304 }
305 
306 }
bool isInGroup(GroupId id, const AIPtr &ai) const
Definition: GroupMgr.h:295
Maintains the groups a AI can be in.
Definition: GroupMgr.h:27
int getGroupSize(GroupId id) const
Definition: GroupMgr.h:280
bool add(GroupId id, const AIPtr &ai)
Adds a new group member to the given GroupId. If the group does not yet exists, it it created and the...
Definition: GroupMgr.h:179
bool removeFromAllGroups(const AIPtr &ai)
Use this method to remove a AI instance from all the group it is part of. Useful if you e...
Definition: GroupMgr.h:233
bool remove(GroupId id, const AIPtr &ai)
Removes a group member from the given GroupId. If the member is the group leader, a new leader will b...
Definition: GroupMgr.h:198
bool isGroupLeader(GroupId id, const AIPtr &ai) const
Definition: GroupMgr.h:270
glm::vec3 getPosition(GroupId id) const
Returns the average position of the group.
Definition: GroupMgr.h:259
AIPtr getLeader(GroupId id) const
Definition: GroupMgr.h:248
Definition: Thread.h:44
Definition: Thread.h:56
Definition: Thread.h:14
bool isInAnyGroup(const AIPtr &ai) const
Definition: GroupMgr.h:290
void visit(GroupId id, Func &func) const
Visit all the group members of the given group until the functor returns false.
Definition: GroupMgr.h:126