|
ORTS
|
00001 #ifndef TerrainBasicImp_H 00002 #define TerrainBasicImp_H 00003 00004 // $Id: TerrainBasicImp.H 5279 2007-06-23 02:49:08Z mburo $ 00005 // This is an ORTS file (c) Michael Buro, David Deutscher, licensed under the GPL 00006 00007 00008 #include "TerrainBase.H" 00009 #include "GameObj.H" 00010 00011 /// \brief Implementation of common Task bookkeeping for TerrainBase implementations. 00012 /** 00013 TerrainBasicImp is templated on a TaskWrapper type, which should include 00014 a "Task task" member, a TaskWrapper(const Task&) constructor, and any 00015 other data that the derived implementation needs. 00016 00017 It maintains a "tasks" container for all TaskWrapper objects, and a queue of 00018 TaskWrapper iterators pointing on pending (requested but not planned yet) tasks. 00019 Also maintained are maps from TaskId to a TaskWrapper, from an Object* to the 00020 task for moving it, and a multimap from an Object* to all tasks in which it is 00021 the target of movement. 00022 Derived classes are responsible to remove a TaskWrapper from the pending list, 00023 and for applying some logic to cases where the target object of a task is removed 00024 (dies or vanishes). 00025 00026 TerrainBasicImp implements: 00027 add_task, remove_task, cancel_task - as expected. 00028 remove_obj - delete relevant tasks and mappings, if any. 00029 Derived classes that implement these methods should call these ancestor 00030 versions (of course, call remove/cancal after any code that depends on 00031 the respective data..). 00032 00033 REGISTER_TYPEOF issue: since this is a template, no REGISTER_TYPEOF's are 00034 done. Users of the class must explicitly use relevant REGISTER_TYPEOF, and 00035 avoid conflicts if using the same TaskWrapper more than once. 00036 The 'REGISTER_TYPEOFS_TerrainBasicImp' macro might be useful. 00037 */ 00038 template<class TaskWrapper> 00039 class TerrainBasicImp : public TerrainBase 00040 { 00041 public: 00042 00043 //--------------------------------------------------------------------- 00044 /// \name Internal typedefs 00045 /// public to allow REGISTER_TYPEOF definitions 00046 //--------------------------------------------------------------------- 00047 //@{ 00048 /* Using a std::list: 00049 1. allows storing iterators, as these are valid even when changing the list. 00050 2. allows fast push_back, fast erase in the middle 00051 */ 00052 typedef std::list<TaskWrapper> Tasks; 00053 typedef typename Tasks::iterator TIter; 00054 /* Using a deque allows FIFO handling of incoming tasks. 00055 The linear find-to-erase operation is tolerable since the queue 00056 is expected to remain relatively small. */ 00057 typedef std::deque<TIter> TaskQueue; 00058 typedef std::map<TerrainBase::TaskId,TIter> TaskId2Task; 00059 typedef std::map<const Object*,TerrainBase::TaskId> Obj2TaskId; 00060 typedef std::multimap<const Object*,TerrainBase::TaskId> ObjIsGoalInTaskId; 00061 //@} 00062 //--------------------------------------------------------------------- 00063 00064 00065 TerrainBasicImp() {}; 00066 TerrainBasicImp(const TerrainBasicImp &other) 00067 : TerrainBase(other), tasks(other.tasks), pendingTasks(other.pendingTasks), 00068 taskId2task(other.taskId2task), obj2taskId(other.obj2taskId), 00069 objIsGoalInTaskId(other.objIsGoalInTaskId) {}; 00070 virtual ~TerrainBasicImp() {}; 00071 00072 00073 //--------------------------------------------------------------------- 00074 /// \name Implementations for abstract TerrainBase Task-handling methods. 00075 /** Some of the method implementations are empty stubs, allowing derived 00076 classes to call TerrainBasicImp::X() as the first action in each method. 00077 Since this call is needed in remove_obj() (to remove tasks associated with 00078 this object), completeness calls for creating these stubs. 00079 */ 00080 //--------------------------------------------------------------------- 00081 //@{ 00082 virtual TaskId add_task(const TerrainBase::Task &task); 00083 virtual void remove_task(TerrainBase::TaskId tid); 00084 virtual void cancel_task(const Object *obj); 00085 00086 virtual void add_obj(const Object *obj); 00087 virtual void remove_obj(const Object *obj); 00088 virtual void update_obj(const Object *obj); 00089 virtual void add_segments(const Vector<Segment> &segs); 00090 //@} 00091 //--------------------------------------------------------------------- 00092 00093 00094 protected: 00095 //--------------------------------------------------------------------- 00096 /// \name Internal removal of tasks 00097 /** These methods should be called internally (including by derived classes) 00098 to remove tasks, to differentiate requests by the outside world from internal 00099 bookkeeping. For example, add_task() first removes any existing tasks for 00100 the same objects, but this should not create stop-actions for them, etc. 00101 */ 00102 //--------------------------------------------------------------------- 00103 //@{ 00104 virtual void clean_task_for_obj(const Object *obj); 00105 virtual void clean_task(TerrainBase::TaskId task_id); 00106 //@} 00107 //--------------------------------------------------------------------- 00108 00109 void eraseFromFailed(const TIter& it); 00110 void eraseFromPending(const TIter& it); 00111 void eraseObjIsGoalFor(const typename TaskId2Task::iterator& ti2tIt); 00112 00113 //--------------------------------------------------------------------- 00114 /// \name Internal book-keeping of tasks 00115 //--------------------------------------------------------------------- 00116 //@{ 00117 Tasks tasks; 00118 TaskQueue pendingTasks; 00119 TaskQueue failedTasks; //not necessarily used in every pathfinder, so probably doesn't belong here, but it was the easiest for now -Nick W. 00120 TaskId2Task taskId2task; 00121 Obj2TaskId obj2taskId; 00122 ObjIsGoalInTaskId objIsGoalInTaskId; 00123 //@} 00124 //--------------------------------------------------------------------- 00125 00126 private: 00127 TerrainBasicImp operator=(const TerrainBasicImp&); // don't need it 00128 }; 00129 00130 //--------------------------------------------------------------------- 00131 //--------------------------------------------------------------------- 00132 00133 #define REGISTER_TYPEOFS_TerrainBasicImp_OneTime(N,template_arg) \ 00134 REGISTER_TYPEOF(N+0, TerrainBasicImp<template_arg>::Obj2TaskId::iterator); \ 00135 REGISTER_TYPEOF(N+1, TerrainBasicImp<template_arg>::Obj2TaskId::const_iterator); 00136 // REGISTER_TYPEOF(N+2, TerrainBasicImp<template_arg>::ObjIsGoalInTaskId::iterator); 00137 // REGISTER_TYPEOF(N+3, TerrainBasicImp<template_arg>::ObjIsGoalInTaskId::const_iterator); 00138 00139 #define REGISTER_TYPEOFS_TerrainBasicImp_ForEach(N,template_arg) \ 00140 REGISTER_TYPEOF(N+0, TerrainBasicImp<template_arg>::Tasks::iterator); \ 00141 REGISTER_TYPEOF(N+1, TerrainBasicImp<template_arg>::Tasks::const_iterator); \ 00142 REGISTER_TYPEOF(N+2, TerrainBasicImp<template_arg>::TaskId2Task::iterator); \ 00143 REGISTER_TYPEOF(N+3, TerrainBasicImp<template_arg>::TaskId2Task::const_iterator); \ 00144 REGISTER_TYPEOF(N+4, TerrainBasicImp<template_arg>::TaskQueue::iterator); \ 00145 REGISTER_TYPEOF(N+5, TerrainBasicImp<template_arg>::TaskQueue::const_iterator); \ 00146 REGISTER_TYPEOF(N+6, Vector<TerrainBasicImp<template_arg>::TIter>::iterator); \ 00147 REGISTER_TYPEOF(N+7, Vector<TerrainBasicImp<template_arg>::TIter>::const_iterator); 00148 00149 //--------------------------------------------------------------------- 00150 template<class TaskWrapper> 00151 TerrainBase::TaskId TerrainBasicImp<TaskWrapper>::add_task(const TerrainBase::Task &task) 00152 { 00153 // These loops of asserts are used to ensure that no module is sending 00154 // a pathfinding request with a vector containing anything other than 00155 // valid GameObj instances. Since this check occurs before the task is 00156 // queued, a failure will occur in the same stack trace that contains 00157 // the faulty code which originally fired the pathfind request Event. 00158 00159 #ifndef NDEBUG 00160 FORALL(task.objs, o) { 00161 const GameObj * obj = dynamic_cast<const GameObj*>( (*o) ); 00162 assert( obj != NULL ); 00163 } 00164 #endif 00165 00166 TaskWrapper tw(task); 00167 00168 #ifndef NDEBUG 00169 // These loops of asserts simply guarantee that our TaskWrapper, when 00170 // initialized with a valid Task, in turn has a vector containing 00171 // nothing but valid GameObj instances. 00172 FORALL(tw.task.objs, o) { 00173 const GameObj * obj = dynamic_cast<const GameObj*>( (*o) ); 00174 assert( obj != NULL ); 00175 } 00176 #endif 00177 00178 tw.isPending = true; 00179 00180 //tasks.push_back(tw); 00181 //TIter pos = tasks.back(); 00182 TIter pos = tasks.insert(tasks.end(),tw); 00183 // currently, the taskID is just the address of the allocated taskwrapper in the list. 00184 TerrainBase::TaskId id = (TerrainBase::TaskId)&(*pos); 00185 // insert to the maps 00186 taskId2task[id] = pos; 00187 FORALL(task.objs, objIt) { 00188 clean_task_for_obj(*objIt); 00189 obj2taskId[*objIt] = id; 00190 } 00191 if( task.goal.target == TerrainBase::Goal::OBJ ) { 00192 objIsGoalInTaskId.insert(ObjIsGoalInTaskId::value_type(task.goal.obj, id)); 00193 } 00194 00195 // mark the new task as pending 00196 pendingTasks.push_back(pos); 00197 return id; 00198 } 00199 00200 //--------------------------------------------------------------------- 00201 template<class TaskWrapper> 00202 void TerrainBasicImp<TaskWrapper>::remove_task(TerrainBase::TaskId tid) 00203 { 00204 clean_task(tid); 00205 } 00206 00207 //--------------------------------------------------------------------- 00208 template<class TaskWrapper> 00209 void TerrainBasicImp<TaskWrapper>::cancel_task(const Object *obj) 00210 { 00211 clean_task_for_obj(obj); 00212 } 00213 00214 //--------------------------------------------------------------------- 00215 template<class TaskWrapper> 00216 void TerrainBasicImp<TaskWrapper>::remove_obj(const Object *obj) 00217 { 00218 // remove a task (if any) associated with this object 00219 clean_task_for_obj(obj); 00220 // remove objIsGoalInTaskId associations 00221 objIsGoalInTaskId.erase(obj); 00222 } 00223 00224 //--------------------------------------------------------------------- 00225 template<class TaskWrapper> 00226 void TerrainBasicImp<TaskWrapper>::add_obj(const Object * /*obj*/) 00227 { 00228 } 00229 00230 //--------------------------------------------------------------------- 00231 template<class TaskWrapper> 00232 void TerrainBasicImp<TaskWrapper>::update_obj(const Object * /*obj*/) 00233 { 00234 } 00235 00236 //--------------------------------------------------------------------- 00237 template<class TaskWrapper> 00238 void TerrainBasicImp<TaskWrapper>::add_segments(const Vector<TerrainBase::Segment> &/*segments*/) 00239 { 00240 } 00241 00242 //--------------------------------------------------------------------- 00243 template<class TaskWrapper> 00244 void TerrainBasicImp<TaskWrapper>::clean_task_for_obj(const Object *obj) 00245 { 00246 Obj2TaskId::iterator o2tiIt = obj2taskId.find(obj); 00247 if( o2tiIt == obj2taskId.end() ) 00248 return; 00249 00250 TerrainBase::TaskId taskId = o2tiIt->second; 00251 00252 typename TaskId2Task::iterator ti2tIt = taskId2task.find(taskId); 00253 00254 assert(ti2tIt != taskId2task.end()); 00255 00256 // if this is the only object of the task, erase the entire task 00257 if( ti2tIt->second->task.objs.size() <= 1 ) { 00258 eraseObjIsGoalFor(ti2tIt); 00259 eraseFromPending(ti2tIt->second); 00260 eraseFromFailed(ti2tIt->second); 00261 tasks.erase(ti2tIt->second); 00262 taskId2task.erase(ti2tIt); 00263 00264 // else, remove the object from the task's list of objects 00265 } else { 00266 ti2tIt->second->task.objs.erase(obj); 00267 } 00268 00269 // remove the obj2TaskId association 00270 obj2taskId.erase(o2tiIt); 00271 } 00272 00273 //--------------------------------------------------------------------- 00274 template<class TaskWrapper> 00275 void TerrainBasicImp<TaskWrapper>::clean_task(TerrainBase::TaskId task_id) 00276 { 00277 typename TaskId2Task::iterator ti2tIt = taskId2task.find(task_id); 00278 00279 if( ti2tIt == taskId2task.end() ){ 00280 std::cerr << "Tried to clean a task that we don't know about\n"; 00281 return; 00282 } 00283 00284 // TaskQueue::iterator it = pendingTasks.begin(), end = pendingTasks.end(); 00285 // for (; it != end; ++it); 00286 //#endif 00287 00288 // remove obj2TaskId associations 00289 std::set<const Object*>::iterator objIt = ti2tIt->second->task.objs.begin(); 00290 std::set<const Object*>::iterator end = ti2tIt->second->task.objs.end(); 00291 // FORALL (ti2tIt->second->task.objs, objIt) { 00292 for (; objIt != end; ++objIt) { 00293 obj2taskId.erase(*objIt); 00294 } 00295 00296 // remove objIsGoalInTaskId associations 00297 eraseObjIsGoalFor(ti2tIt); 00298 00299 // remove the task from the pending queue, if it's there 00300 eraseFromPending(ti2tIt->second); 00301 00302 eraseFromFailed(ti2tIt->second); 00303 00304 // (find and) remove the task 00305 tasks.erase(ti2tIt->second); 00306 00307 // remove the taskId2task association 00308 taskId2task.erase(ti2tIt); 00309 } 00310 00311 //--------------------------------------------------------------------- 00312 template<class TaskWrapper> 00313 void TerrainBasicImp<TaskWrapper>::eraseFromPending(const TIter& iter) 00314 { 00315 #if GCC 00316 FORALL (pendingTasks, it) { 00317 #else 00318 typename TaskQueue::iterator it = pendingTasks.begin(), end = pendingTasks.end(); 00319 for (; it != end; ++it) { 00320 #endif 00321 if(*it == iter) { 00322 pendingTasks.erase(it); 00323 break; 00324 } 00325 } 00326 } 00327 00328 //--------------------------------------------------------------------- 00329 template<class TaskWrapper> 00330 void TerrainBasicImp<TaskWrapper>::eraseFromFailed(const TIter& iter) 00331 { 00332 #if GCC 00333 FORALL (failedTasks, it) { 00334 #else 00335 typename TaskQueue::iterator it = failedTasks.begin(), end = failedTasks.end(); 00336 for (; it != end; ++it) { 00337 #endif 00338 if(*it == iter) { 00339 failedTasks.erase(it); 00340 break; 00341 } 00342 } 00343 } 00344 00345 00346 00347 template<class TaskWrapper> 00348 void TerrainBasicImp<TaskWrapper>::eraseObjIsGoalFor(const typename TaskId2Task::iterator& ti2tIt) 00349 { 00350 // shorthand 00351 typedef ObjIsGoalInTaskId::iterator OGIT; 00352 00353 // If this task has an object as goal 00354 if( ti2tIt->second->task.goal.target == TerrainBase::Goal::OBJ ) { 00355 // find all associations from the goal_obj to tasks 00356 std::pair<OGIT,OGIT> range = objIsGoalInTaskId.equal_range(ti2tIt->second->task.goal.obj); 00357 // remove the one association that refers to the task we're cleaning 00358 for(OGIT i = range.first ; i != range.second ; i++ ) { 00359 if( i->second == ti2tIt->first ) { 00360 objIsGoalInTaskId.erase(i); 00361 break; 00362 } 00363 } 00364 } 00365 } 00366 00367 #endif