|
ORTS
|
00001 /** @file ScriptObj.C 00002 @see ScriptObj.H 00003 00004 $Id: ScriptObj.C 5279 2007-06-23 02:49:08Z mburo $ 00005 $Source$ 00006 */ 00007 00008 // This is an ORTS file 00009 // (c) Tim Furtak 00010 // (c) Michael Buro 00011 // licensed under the GPL 00012 00013 #include "ScriptObj.H" 00014 #include "Blueprints.H" 00015 #include "PlayerInfo.H" 00016 #include "Script.H" 00017 #include "ByteData.H" 00018 00019 using namespace std; 00020 00021 #define PARANOID 00022 00023 set<ScriptObj*> ScriptObj::ptr_list; 00024 00025 //=================================================================== 00026 00027 IdObjMap ScriptObj::id2obj_map; 00028 ObjIdMap ScriptObj::obj2id_map; 00029 IdFactory ScriptObj::idf(100000); 00030 00031 Vector<ScriptObj*> ScriptObj::dead_objs; 00032 list<ScriptObj*> ScriptObj::destroyed_objs; 00033 00034 //=================================================================== 00035 00036 ScriptObj::BasePtr::BasePtr(ScriptObj *s) 00037 { 00038 check_ptr(s); 00039 00040 p = s; 00041 if (p == 0) { 00042 id = 0; 00043 return; 00044 } 00045 FIND (ScriptObj::obj2id_map, it, p); 00046 if (it == obj2id_map.end()) { 00047 ERR("bad pointer"); 00048 } 00049 id = it->second; 00050 } 00051 00052 //------------------------------------------------------------------- 00053 00054 ScriptObj::BasePtr::BasePtr(const ScriptObj::BasePtr &ptr) 00055 { 00056 p = ptr.p; 00057 id = ptr.id; 00058 check_ptr(p); 00059 } 00060 00061 //------------------------------------------------------------------- 00062 00063 void ScriptObj::BasePtr::reset() 00064 { 00065 p = 0; 00066 id = 0; 00067 } 00068 00069 //=================================================================== 00070 00071 ScriptObj::Ptr::Ptr(ScriptObj *s) : BasePtr(s) 00072 { 00073 if (!p) return; 00074 p->hard_refs.insert(this); 00075 p->add_ref(); 00076 } 00077 00078 //------------------------------------------------------------------- 00079 00080 ScriptObj::Ptr::Ptr(const ScriptObj::Ptr &ptr) : BasePtr(ptr) 00081 { 00082 if (!p) return; 00083 p->hard_refs.insert(this); 00084 p->add_ref(); 00085 } 00086 00087 //------------------------------------------------------------------- 00088 00089 ScriptObj::Ptr& ScriptObj::Ptr::operator=(const ScriptObj::Ptr &ptr) 00090 { 00091 check_ptr(p); 00092 if (p) { 00093 p->hard_refs.erase(this); 00094 p->del_ref(); 00095 } 00096 00097 p = ptr.p; 00098 id = ptr.id; 00099 00100 check_ptr(p); 00101 if (p) { 00102 p->hard_refs.insert(this); 00103 p->add_ref(); 00104 } 00105 return *this; 00106 } 00107 00108 //------------------------------------------------------------------- 00109 00110 ScriptObj::Ptr::~Ptr() 00111 { 00112 check_ptr(p); 00113 if (!p) return; 00114 p->hard_refs.erase(this); 00115 p->del_ref(); 00116 } 00117 00118 //------------------------------------------------------------------- 00119 00120 void ScriptObj::Ptr::save(ostream &os) const 00121 { 00122 ObjId id = ScriptObj::obj2id_map[p]; 00123 OS_WRITE(id); 00124 } 00125 00126 //------------------------------------------------------------------- 00127 00128 void ScriptObj::Ptr::load(istream &is) 00129 { 00130 ObjId id; 00131 IS_READ(id); 00132 p = ScriptObj::id2obj_map[id]; 00133 } 00134 00135 //=================================================================== 00136 00137 ScriptObj::WPtr::WPtr(ScriptObj *s) : BasePtr(s) 00138 { 00139 if (!p) return; 00140 p->soft_refs.insert(this); 00141 } 00142 00143 //------------------------------------------------------------------- 00144 00145 ScriptObj::WPtr::WPtr(const ScriptObj::WPtr &ptr) : BasePtr(ptr) 00146 { 00147 if (!p) return; 00148 p->soft_refs.insert(this); 00149 } 00150 00151 //------------------------------------------------------------------- 00152 00153 ScriptObj::WPtr& ScriptObj::WPtr::operator=(const ScriptObj::WPtr &ptr) 00154 { 00155 check_ptr(p); 00156 if (p) { 00157 p->soft_refs.erase(this); 00158 } 00159 00160 p = ptr.p; 00161 id = ptr.id; 00162 00163 check_ptr(p); 00164 if (p) { 00165 p->soft_refs.insert(this); 00166 } 00167 return *this; 00168 } 00169 00170 //------------------------------------------------------------------- 00171 00172 ScriptObj::WPtr::~WPtr() 00173 { 00174 if (!p) return; 00175 p->soft_refs.erase(this); 00176 } 00177 00178 //------------------------------------------------------------------- 00179 00180 void ScriptObj::WPtr::save(ostream &os) const 00181 { 00182 ObjId id = ScriptObj::obj2id_map[p]; 00183 OS_WRITE(id); 00184 } 00185 00186 //------------------------------------------------------------------- 00187 00188 void ScriptObj::WPtr::load(istream &is) 00189 { 00190 ObjId id; 00191 IS_READ(id); 00192 p = ScriptObj::id2obj_map[id]; 00193 } 00194 00195 //=================================================================== 00196 00197 ScriptObj::ScriptObj() 00198 { 00199 num_refs = 0; 00200 dead = false; 00201 enabled = true; 00202 parent = this; 00203 #ifdef PARANOID 00204 //The relevant types cannot be registered due to some unknown reason: FIND(ptr_list, i, this); 00205 set<ScriptObj*>::iterator i = ptr_list.find(this); 00206 if (i != ptr_list.end()) ERR("already in set?"); 00207 ptr_list.insert(this); 00208 #endif 00209 00210 id = idf.next(); 00211 assert(id2obj_map[id] == 0); 00212 id2obj_map[id] = this; 00213 obj2id_map[this] = id; 00214 } 00215 00216 //------------------------------------------------------------------- 00217 00218 ScriptObj::~ScriptObj() 00219 { 00220 FORALL (soft_refs, it) { 00221 (*it)->reset(); 00222 } 00223 FORALL (hard_refs, it) { 00224 (*it)->reset(); 00225 } 00226 00227 idf.free(id); 00228 id2obj_map.erase(id2obj_map.find(id)); 00229 obj2id_map.erase(obj2id_map.find(this)); 00230 #ifdef PARANOID 00231 //The relevant types cannot be registered due to some unknown reason: FIND(ptr_list, i, this); 00232 set<ScriptObj*>::iterator it = ptr_list.find(this); 00233 if (it != ptr_list.end()) ptr_list.erase(it); 00234 #endif 00235 } 00236 00237 //------------------------------------------------------------------- 00238 00239 void ScriptObj::save(ostream &os) const 00240 { 00241 string s; 00242 ERR("need PlayerInfo data here"); 00243 gen_diff(true, true, s, 0); 00244 os << s; 00245 } 00246 00247 //------------------------------------------------------------------- 00248 00249 void ScriptObj::load(istream &is) 00250 { 00251 string s; 00252 is >> s; 00253 ByteStream bs(s); 00254 ERR ("need PlayerInfo data here"); 00255 apply_diff(bs, 0); 00256 } 00257 00258 //------------------------------------------------------------------- 00259 00260 /** Intended for use in saving/loading the game state in combination with set_ids. */ 00261 00262 void ScriptObj::get_ids(Vector<ScriptObj*> &objs, Vector<ObjId> &ids) 00263 { 00264 ids.clear(); 00265 objs.clear(); 00266 00267 FORALL (id2obj_map, it) { 00268 ids.push_back(it->first); 00269 objs.push_back(it->second); 00270 } 00271 } 00272 00273 //------------------------------------------------------------------- 00274 00275 /** Intended for use in saving/loading the game state in combination with get_ids. */ 00276 00277 void ScriptObj::set_ids(const Vector<ScriptObj*> &objs, const Vector<ObjId> &ids) 00278 { 00279 if (objs.size() != ids.size()) ERR("size mismatch"); 00280 id2obj_map.clear(); 00281 obj2id_map.clear(); 00282 idf.reserve(ids); 00283 FORU (i, objs.size()) { 00284 id2obj_map[ids[i]] = objs[i]; 00285 obj2id_map[objs[i]] = ids[i]; 00286 } 00287 } 00288 00289 //------------------------------------------------------------------- 00290 00291 ObjId ScriptObj::get_obj_id(ScriptObj *s) 00292 { 00293 FIND(obj2id_map, it, s); 00294 if (it == obj2id_map.end()) return 0; 00295 return it->second; 00296 } 00297 00298 //------------------------------------------------------------------- 00299 00300 void ScriptObj::kill() 00301 { 00302 if (!dead) dead_objs.push_back(this); 00303 dead = true; 00304 } 00305 00306 //------------------------------------------------------------------- 00307 00308 /** Call script destructors for dead objects. 00309 Delete them if they're not being referenced. 00310 NOTE: it's possible for new objects to be added to dead_objs when the destructors are called. 00311 */ 00312 00313 void ScriptObj::collect_dead(std::set<ScriptObj*> &dead) 00314 { 00315 dead.clear(); 00316 // note: if new objects are added to dead_objs when the destructors are called 00317 // then the iterator will be invalidated, so do it this way. 00318 FORU_DYN (i, dead_objs.size()) { 00319 ScriptObj *g = dead_objs[i]; 00320 dead.insert(g); 00321 g->destruct(); 00322 if (g->get_refs() == 0) { 00323 delete g; 00324 } else { 00325 destroyed_objs.push_back(g); 00326 } 00327 } 00328 dead_objs.clear(); 00329 } 00330 00331 //------------------------------------------------------------------- 00332 00333 /** Delete dead objects that aren't being referenced. */ 00334 00335 void ScriptObj::collect_destroyed() 00336 { 00337 list<ScriptObj*>::iterator it; 00338 for (it = destroyed_objs.begin(); it != destroyed_objs.end();) { 00339 if ((*it)->get_refs() == 0) { 00340 delete *it; 00341 it = destroyed_objs.erase(it); 00342 continue; 00343 } 00344 ++it; 00345 } 00346 } 00347 00348 //------------------------------------------------------------------- 00349 00350 void ScriptObj::check_ptr(ScriptObj *ptr) { 00351 #ifdef PARANOID 00352 if (ptr == 0) return; 00353 if (ptr_list.find(ptr) != ptr_list.end()) return; 00354 cerr << ptr << endl; 00355 volatile int foo = 0; 00356 foo /= foo; 00357 ERR("no such scriptobj"); 00358 #endif 00359 } 00360 00361 //------------------------------------------------------------------- 00362 00363 bool ScriptObj::has_attr(const string &a) const { 00364 return get_val_ptr(a) != 0; 00365 } 00366 00367 //------------------------------------------------------------------- 00368 00369 stype ScriptObj::get_val(const string &a) const { 00370 const stype *p = get_val_ptr(a); 00371 if (p == 0) { 00372 cerr << "object type = " << bp_name() << endl; 00373 ERR2("unknown attribute ", a.c_str()); 00374 return stype(); 00375 } 00376 return *p; 00377 } 00378 00379 //------------------------------------------------------------------- 00380 00381 void ScriptObj::set_val(const string &a, stype v, bool warn) { 00382 stype *p = get_val_ptr(a); 00383 if (p == 0) { 00384 if (warn) ERR2("unknown attribute", a.c_str()); 00385 return; 00386 } 00387 *p = v; 00388 } 00389 00390 //------------------------------------------------------------------- 00391 00392 sint4 ScriptObj::get_int(const string &a) const { 00393 const stype *p = get_val_ptr(a); 00394 if (!p) ERR2("unknown attribute", a.c_str()); 00395 return p->to_int(); 00396 } 00397 00398 //------------------------------------------------------------------- 00399 00400 sint4 ScriptObj::get_int_prev(const string &a) const { 00401 stype p = get_val_prev(a); 00402 return p.to_int(); 00403 } 00404 00405 //------------------------------------------------------------------- 00406 00407 sintptr* ScriptObj::get_int_ptr(const string &a) { 00408 stype *p = get_val_ptr(a); 00409 if (!p) return 0; 00410 if (p->type == stype::NONE) return 0; 00411 if (p->type != stype::INT) ERR2("not integer", a.c_str()); 00412 return &p->val.i; 00413 } 00414 00415 //------------------------------------------------------------------- 00416 00417 const sintptr* ScriptObj::get_int_ptr(const string &a) const { 00418 const stype *p = get_val_ptr(a); 00419 if (!p) return 0; 00420 if (p->type != stype::INT) ERR2("not integer", a.c_str()); 00421 return &p->val.i; 00422 } 00423 00424 //------------------------------------------------------------------- 00425 00426 void ScriptObj::set_int(const string &a, sint4 v, bool warn) { 00427 sintptr *p = get_int_ptr(a); 00428 if (!p) { 00429 if (warn) ERR2("unknown attribute", a.c_str()); 00430 return; 00431 } 00432 *p = v; 00433 } 00434 00435 //=================================================================== 00436