From 0de981d0b8a6b88536fb165a136924c1cc453db0 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 27 May 2018 12:59:41 +0200 Subject: [PATCH] ai: make AICharacter reference counted This lets one drop the reference to AICharacter after adding it to a flock or AIWorld without crashes. Also replace the silly and inefficient custom-rolled linked list implementation of AICharPool with a vector, and add additional safety checks. Fixes #318 --- contrib/src/ai/aiCharacter.cxx | 3 + contrib/src/ai/aiCharacter.h | 3 +- contrib/src/ai/aiWorld.cxx | 130 ++++++++------------------------- contrib/src/ai/aiWorld.h | 24 +----- contrib/src/ai/flock.h | 2 +- 5 files changed, 37 insertions(+), 125 deletions(-) diff --git a/contrib/src/ai/aiCharacter.cxx b/contrib/src/ai/aiCharacter.cxx index 7009a353f1..240f1a4ea3 100644 --- a/contrib/src/ai/aiCharacter.cxx +++ b/contrib/src/ai/aiCharacter.cxx @@ -24,6 +24,8 @@ AICharacter::AICharacter(string model_name, NodePath model_np, double mass, doub _velocity = LVecBase3(0.0, 0.0, 0.0); _steering_force = LVecBase3(0.0, 0.0, 0.0); + _world = nullptr; + _steering = new AIBehaviors(); _steering->_ai_char = this; @@ -31,6 +33,7 @@ AICharacter::AICharacter(string model_name, NodePath model_np, double mass, doub } AICharacter::~AICharacter() { + nassertv(_world == nullptr); } /** diff --git a/contrib/src/ai/aiCharacter.h b/contrib/src/ai/aiCharacter.h index 244f9bc45e..30adf21ced 100644 --- a/contrib/src/ai/aiCharacter.h +++ b/contrib/src/ai/aiCharacter.h @@ -15,6 +15,7 @@ #define _AICHARACTER_H #include "aiBehaviors.h" +#include "referenceCount.h" /** * This class is used for creating the AI characters. It assigns both physics @@ -25,7 +26,7 @@ class AIBehaviors; class AIWorld; -class EXPCL_PANDAAI AICharacter { +class EXPCL_PANDAAI AICharacter : public ReferenceCount { public: double _mass; double _max_force; diff --git a/contrib/src/ai/aiWorld.cxx b/contrib/src/ai/aiWorld.cxx index 6abac9f990..8210046497 100644 --- a/contrib/src/ai/aiWorld.cxx +++ b/contrib/src/ai/aiWorld.cxx @@ -14,44 +14,56 @@ #include "aiWorld.h" AIWorld::AIWorld(NodePath render) { - _ai_char_pool = new AICharPool(); - _render = render; + _render = move(render); } AIWorld::~AIWorld() { } void AIWorld::add_ai_char(AICharacter *ai_char) { - _ai_char_pool->append(ai_char); + _ai_char_pool.push_back(ai_char); ai_char->_window_render = _render; ai_char->_world = this; } void AIWorld::remove_ai_char(string name) { - _ai_char_pool->del(name); - remove_ai_char_from_flock(name); + AICharPool::iterator it; + for (it = _ai_char_pool.begin(); it != _ai_char_pool.end(); ++it) { + AICharacter *ai_char = *it; + if (ai_char->_name == name) { + nassertv(ai_char->_world == this); + ai_char->_world = nullptr; + _ai_char_pool.erase(it); + break; + } + } + + remove_ai_char_from_flock(move(name)); } void AIWorld::remove_ai_char_from_flock(string name) { - AICharPool::node *ai_pool; - ai_pool = _ai_char_pool->_head; - while((ai_pool) != NULL) { - for(unsigned int i = 0; i < _flock_pool.size(); ++i) { - if(ai_pool->_ai_char->_ai_char_flock_id == _flock_pool[i]->get_id()) { - for(unsigned int j = 0; j<_flock_pool[i]->_ai_char_list.size(); ++j) { - if(_flock_pool[i]->_ai_char_list[j]->_name == name) { - _flock_pool[i]->_ai_char_list.erase(_flock_pool[i]->_ai_char_list.begin() + j); + for (AICharacter *ai_char : _ai_char_pool) { + for (Flock *flock : _flock_pool) { + if (ai_char->_ai_char_flock_id == flock->get_id()) { + for (size_t j = 0; j < flock->_ai_char_list.size(); ++j) { + if (flock->_ai_char_list[j]->_name == name) { + flock->_ai_char_list.erase(flock->_ai_char_list.begin() + j); return; } } } } - ai_pool = ai_pool->_next; } } +/** + * This function prints the names of the AI characters that have been added to + * the AIWorld. Useful for debugging purposes. + */ void AIWorld::print_list() { - _ai_char_pool->print_list(); + for (AICharacter *ai_char : _ai_char_pool) { + cout << ai_char->_name << endl; + } } /** @@ -59,12 +71,8 @@ void AIWorld::print_list() { * characters which have been added to the AIWorld. */ void AIWorld::update() { - AICharPool::node *ai_pool; - ai_pool = _ai_char_pool->_head; - - while((ai_pool)!=NULL) { - ai_pool->_ai_char->update(); - ai_pool = ai_pool->_next; + for (AICharacter *ai_char : _ai_char_pool) { + ai_char->update(); } } @@ -142,86 +150,6 @@ void AIWorld::flock_on(unsigned int flock_id) { } } -AICharPool::AICharPool() { - _head = NULL; -} - -AICharPool::~AICharPool() { -} - -void AICharPool::append(AICharacter *ai_ch) { - node *q; - node *t; - - if(_head == NULL) { - q = new node(); - q->_ai_char = ai_ch; - q->_next = NULL; - _head = q; - } - else { - q = _head; - while( q->_next != NULL) { - q = q->_next; - } - - t = new node(); - t->_ai_char = ai_ch; - t->_next = NULL; - q->_next = t; - } -} - -void AICharPool::del(string name) { - node *q; - node *r; - q = _head; - - if(_head==NULL) { - return; - } - - // Only one node in the linked list - if(q->_next == NULL) { - if(q->_ai_char->_name == name) { - _head = NULL; - delete q; - } - return; - } - - r = q; - while( q != NULL) { - if( q->_ai_char->_name == name) { - // Special case - if(q == _head) { - _head = q->_next; - delete q; - return; - } - - r->_next = q->_next; - delete q; - return; - } - r = q; - q = q->_next; - } -} - -/** - * This function prints the ai characters in the AICharPool. Used for - * debugging purposes. - */ -void AICharPool::print_list() { - node* q; - q = _head; - while(q != NULL) { - cout<_ai_char->_name<_next; - } -} - /** * This function adds the nodepath as an obstacle that is needed by the * obstacle avoidance behavior. diff --git a/contrib/src/ai/aiWorld.h b/contrib/src/ai/aiWorld.h index f85e1dc584..64cecefc2d 100644 --- a/contrib/src/ai/aiWorld.h +++ b/contrib/src/ai/aiWorld.h @@ -21,27 +21,6 @@ class AICharacter; class Flock; -/** - * This class implements a linked list of AI Characters allowing the user to - * add and delete characters from the linked list. This will be used in the - * AIWorld class. - */ -class EXPCL_PANDAAI AICharPool { - public: - struct node { - AICharacter * _ai_char; - node * _next; - } ; - - node* _head; - AICharPool(); - ~AICharPool(); - void append(AICharacter *ai_ch); - void del(string name); - void print_list(); -}; - - /** * A class that implements the virtual AI world which keeps track of the AI * characters active at any given time. It contains a linked list of AI @@ -51,7 +30,8 @@ class EXPCL_PANDAAI AICharPool { */ class EXPCL_PANDAAI AIWorld { private: - AICharPool * _ai_char_pool; + typedef std::vector AICharPool; + AICharPool _ai_char_pool; NodePath _render; public: vector _obstacles; diff --git a/contrib/src/ai/flock.h b/contrib/src/ai/flock.h index c5e508a837..c353781890 100644 --- a/contrib/src/ai/flock.h +++ b/contrib/src/ai/flock.h @@ -40,7 +40,7 @@ public: unsigned int _alignment_wt; // This vector will hold all the ai characters which belong to this flock. - typedef std::vector AICharList; + typedef std::vector AICharList; AICharList _ai_char_list; PUBLISHED: