World.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace Game{
  5. #if 0
  6. #define LOG(x) LogN(x)
  7. #else
  8. #define LOG(x)
  9. #endif
  10. /******************************************************************************
  11. on start the areas have state AREA_UNLOADED
  12. during update:
  13. -nearest areas are instantly loaded to AREA_ACTIVE and AREA_INACTIVE
  14. -neighbor areas are collected to list, and in secondary thread they are loaded into memory, at the moment of loading their state is changed into AREA_CACHE
  15. /******************************************************************************/
  16. Bool WorldManager::update_objects_after_physics=true, WorldManager::use_background_loading=true, WorldManager::use_early_z_for_terrain=false, WorldManager::low_memory_usage=false;
  17. WorldManager World;
  18. /******************************************************************************/
  19. // WORLD SETTINGS
  20. /******************************************************************************/
  21. WorldSettings& WorldSettings:: areaSize(Flt size) {T._area_size = Max(size, EPS ) ; return T;}
  22. WorldSettings& WorldSettings:: hmRes (Int res ) {T._hm_res =NearestPow2(Mid(res , 1, MAX_HM_RES ))+1; return T;}
  23. WorldSettings& WorldSettings::path2DRes (Int res ) {T._path2d_res= Mid(res , 1, MAX_PATH_RES) ; return T;}
  24. Bool WorldSettings::compatible(C WorldSettings &settings)C
  25. {
  26. return Equal(areaSize(), settings. areaSize())
  27. && hmRes ()==settings. hmRes ()
  28. && path2DRes ()==settings.path2DRes ();
  29. }
  30. Bool WorldSettings::operator==(C WorldSettings &settings)C
  31. {
  32. return Equal(areaSize(), settings. areaSize())
  33. && hmRes ()==settings. hmRes ()
  34. && path2DRes ()==settings.path2DRes ();
  35. }
  36. Str WorldSettings::asText()C
  37. {
  38. return S
  39. +"Area Size: "+areaSize()+'\n'
  40. +"Heightmap Resolution: "+(hmRes()-1)+'\n'
  41. +"2D Path Resolution: "+path2DRes();
  42. }
  43. WorldSettings& WorldSettings::reset()
  44. {
  45. environment=null;
  46. _area_size =32;
  47. _hm_res =65;
  48. _path2d_res =32;
  49. return T;
  50. }
  51. WorldSettings& WorldSettings::shr()
  52. {
  53. areaSize( areaSize() /2);
  54. hmRes (( hmRes ()-1)/2);
  55. path2DRes (path2DRes () /2);
  56. return T;
  57. }
  58. WorldSettings& WorldSettings::shl()
  59. {
  60. areaSize( areaSize() *2);
  61. hmRes (( hmRes ()-1)*2);
  62. path2DRes (path2DRes () *2);
  63. return T;
  64. }
  65. Bool WorldSettings::save(File &f, CChar *path)C
  66. {
  67. f.cmpUIntV(1); // version
  68. f<<_area_size<<_hm_res<<_path2d_res;
  69. f._putStr(environment.name(path));
  70. return f.ok();
  71. }
  72. Bool WorldSettings::load(File &f, CChar *path)
  73. {
  74. switch(f.decUIntV())
  75. {
  76. case 1:
  77. {
  78. f>>_area_size>>_hm_res>>_path2d_res; environment.require(f._getStr(), path);
  79. if(f.ok())return true;
  80. }break;
  81. case 0:
  82. {
  83. f>>_area_size>>_hm_res>>_path2d_res; environment=null;
  84. if(f.ok())return true;
  85. }break;
  86. }
  87. reset(); return false;
  88. }
  89. Bool WorldSettings::save(C Str &name)C
  90. {
  91. File f; if(f.writeTry(name)){if(save(f, _GetPath(name)) && f.flush())return true; f.del(); FDelFile(name);}
  92. return false;
  93. }
  94. Bool WorldSettings::load(C Str &name)
  95. {
  96. File f; if(f.readTry(name))return load(f, _GetPath(name));
  97. reset(); return false;
  98. }
  99. /******************************************************************************/
  100. // RESOURCES
  101. /******************************************************************************/
  102. static void DelayRemoveInc()
  103. {
  104. Environments.delayRemoveInc();
  105. Objects .delayRemoveInc();
  106. Meshes .delayRemoveInc();
  107. PhysBodies .delayRemoveInc();
  108. WaterMtrls .delayRemoveInc();
  109. Materials .delayRemoveInc();
  110. ImageAtlases.delayRemoveInc();
  111. Images .delayRemoveInc();
  112. }
  113. static void DelayRemoveDec()
  114. {
  115. Environments.delayRemoveDec();
  116. Objects .delayRemoveDec();
  117. Meshes .delayRemoveDec();
  118. PhysBodies .delayRemoveDec();
  119. WaterMtrls .delayRemoveDec();
  120. Materials .delayRemoveDec();
  121. ImageAtlases.delayRemoveDec();
  122. Images .delayRemoveDec();
  123. }
  124. /******************************************************************************/
  125. // WORLD MANAGER
  126. /******************************************************************************/
  127. static Bool WorldThread(Thread &thread) {((WorldManager*)thread.user)->threadFunc(); return true;}
  128. void WorldManager::threadFunc()
  129. {
  130. _thread_event.wait(); // load data only on demand
  131. if(_area_background.elms()) // if want some areas to be loaded
  132. {
  133. // important: do not create new grid objects, but use already created in the main thread, and now access them using 'area_background' array (creating grid objects on secondary thread would require 'SyncLocker' for every operation on grid)
  134. File f; // declare the file outside the loop, to make use of performance optimization when using the same file loading files from 1 pak
  135. ThreadMayUseGPUData();
  136. again:
  137. SyncLocker locker(_lock);
  138. if(_area_background.elms())
  139. {
  140. Area &area=*_area_background.pop();
  141. areaCache(area, false, f);
  142. if(_area_background.elms())goto again;
  143. }
  144. ThreadFinishedUsingGPUData();
  145. }
  146. }
  147. /******************************************************************************/
  148. WorldManager& WorldManager::mode(WORLD_MODE mode)
  149. {
  150. if(T.mode()!=mode)
  151. {
  152. del();
  153. T._mode=mode;
  154. }
  155. return T;
  156. }
  157. void WorldManager::setRanges()
  158. {
  159. Int rangei_prev=T._rangei;
  160. T._rangei =Trunc ( T._range/areaSize()+2.2f);
  161. T._rangei2 =RoundPos(Sqr(T._rangei+0.5f )); // + 0.5
  162. T._rangei2_inactive=RoundPos(Sqr(T._rangei+0.5f+SQRT2 )); // + ~1.9
  163. T._rangei2_cache =RoundPos(Sqr(T._rangei+1.5f+SQRT2 )); // + ~2.9
  164. if(_mode==WORLD_STREAM && _updated && rangei_prev!=T._rangei)areaUpdateState();
  165. }
  166. WorldManager& WorldManager::activeRange(Flt range)
  167. {
  168. if(T._range!=range)
  169. {
  170. T._range=range;
  171. setRanges();
  172. }
  173. return T;
  174. }
  175. WorldManager& WorldManager::_setObjType(ObjMap<Obj> &obj_map, Int obj_type, CPtr c_type)
  176. {
  177. SyncLocker locker(_lock);
  178. if(obj_type>=0)T._obj_container(obj_type).set(obj_map, c_type);
  179. return T;
  180. }
  181. /******************************************************************************/
  182. static void UnloadAreas(Cell<Area> &cell, WorldManager &world) {world.areaUnload(cell());}
  183. WorldManager& WorldManager::del()
  184. {
  185. if(is())
  186. {
  187. SyncLocker locker(_lock);
  188. // unload areas in case they want save data to file
  189. updateObjectAreas(); // first update object areas so they are placed in correct areas (this is needed if object position was modified just before this place in code)
  190. _grid.func(UnloadAreas, T);
  191. REPA(_obj_container)if(ObjMap<Obj> *obj_map=_obj_container[i].map)obj_map->clear(); // delete objects, use 'clear' in case there are any 'Reference' objects left pointing to memory adresses inside containers
  192. _area_active_rect.set(0, 0, -1, -1);
  193. _area_loaded_rect.set(0, 0, -1, -1);
  194. _area_active .del(); _area_draw.del(); _area_draw_shadow.del(); _area_draw_secondary.del();
  195. _area_inactive .del();
  196. _area_cache .del();
  197. _area_background .del();
  198. _path.del();
  199. _grid.fastAccess(null).del();
  200. _path_node.del();
  201. _path_neighbor.del();
  202. _decals.del();
  203. _mesh_overlays.del();
  204. mini_map.del();
  205. _settings.reset();
  206. _id .zero();
  207. _name .del();
  208. _data_path.del();
  209. _xz .zero();
  210. _xzi.zero();
  211. _updated=false;
  212. Time.skipUpdate();
  213. }
  214. return T;
  215. }
  216. Bool WorldManager::NewTry(C Str &world_name)
  217. {
  218. del();
  219. if(!world_name.is())return true;
  220. SyncLocker locker(_lock);
  221. if(FExist(world_name))
  222. {
  223. if(!DecodeFileName(world_name, _id))_id.zero();
  224. T._name=world_name;
  225. T._data_path=world_name; _data_path.tailSlash(true);
  226. // load settings
  227. {
  228. _settings.reset();
  229. File f; if(!f.readTry(dataPath()+"Settings") || !_settings.load(f))goto error;
  230. setRanges(); // after loading settings we need to update the ranges, because they're dependent on world area size
  231. }
  232. // path finder
  233. if(!_path.create(_settings.areaSize()))Exit("Can't initialize PathWorld");
  234. // mini maps
  235. mini_map.load(world_name); // this is OK to fail as it is optional
  236. // start background loading thread
  237. if(D.canUseGPUDataOnSecondaryThread()) // only if we can operate on GPU on secondary threads
  238. if(!_thread.created())_thread.create(WorldThread, this, 0, false, "EE.Game.World");
  239. return true;
  240. }
  241. error:
  242. del(); return false;
  243. }
  244. WorldManager& WorldManager::New(C Str &world_name)
  245. {
  246. if(!NewTry(world_name))Exit(MLT(S+"Can't load world \"" +world_name+"\".",
  247. PL,S+u"Nie można wczytać świata \""+world_name+"\"."));
  248. return T;
  249. }
  250. Bool WorldManager::NewTry(C UID &world_id) {return NewTry(world_id.valid() ? _EncodeFileName(world_id) : null);}
  251. WorldManager& WorldManager::New (C UID &world_id) {return New (world_id.valid() ? _EncodeFileName(world_id) : null);}
  252. void WorldManager::Create(C Str &world_name, C WorldSettings &settings)
  253. {
  254. FCreateDirs(world_name+"/Area" );
  255. settings.save(world_name+"/Settings");
  256. }
  257. /******************************************************************************/
  258. // GET
  259. /******************************************************************************/
  260. Int WorldManager::objType(Obj &obj)
  261. {
  262. CPtr obj_c_type=CType(obj);
  263. if(InRange(obj._type, _obj_container))if(obj_c_type==_obj_container[obj._type].type)return obj._type ; // check if obj.type precisely matches the object container class
  264. REPA(_obj_container) if(obj_c_type==_obj_container[i ].type)return obj._type=i; // search all object containers for matching type
  265. return -1;
  266. }
  267. AREA_STATE WorldManager::rangeState(C VecI2 &xzi)
  268. {
  269. switch(_mode)
  270. {
  271. case WORLD_STREAM:
  272. {
  273. Int dist =Dist2(T._xzi, xzi);
  274. if( dist<=_rangei2 )return AREA_ACTIVE ;
  275. if( dist<=_rangei2_inactive)return AREA_INACTIVE;
  276. if( dist<=_rangei2_cache )return AREA_CACHE ;
  277. return AREA_UNLOADED;
  278. }
  279. case WORLD_FULL: return AREA_ACTIVE;
  280. }
  281. return AREA_UNLOADED;
  282. }
  283. Int WorldManager::areaActiveNum( )C {return _area_active.elms();}
  284. Area* WorldManager::areaActive ( Int i )C {return InRange(i, _area_active) ? _area_active[i] : null;}
  285. Area* WorldManager::areaActive (C VecI2 &xz)C
  286. {
  287. if(Cuts(xz, _area_active_rect))
  288. if(Cell<Area> *cell=_grid.find(xz))
  289. if(Area *area=cell->data())
  290. if(area->state()==AREA_ACTIVE)
  291. return area;
  292. return null;
  293. }
  294. Area* WorldManager::areaLoaded(C VecI2 &xz)C
  295. {
  296. if(Cuts(xz, _area_loaded_rect))
  297. if(Cell<Area> *cell=_grid.find(xz))
  298. if(Area *area=cell->data())
  299. if(area->state()!=AREA_UNLOADED)
  300. return area;
  301. return null;
  302. }
  303. Flt WorldManager::hmHeight(C Vec2 &xz, Bool smooth)
  304. {
  305. if(Area *area=areaLoaded(worldToArea(xz)))return area->hmHeight(xz, smooth);
  306. return 0;
  307. }
  308. C MaterialPtr& WorldManager::hmMaterial(C Vec2 &xz)
  309. {
  310. if(Area *area=areaLoaded(worldToArea(xz)))return area->hmMaterial(xz);
  311. return MaterialNull;
  312. }
  313. static WaterMtrlPtr WaterMtrlGlobal=&Water;
  314. C WaterMtrlPtr& WorldManager::waterUnder(C Vec &pos, Flt *depth)
  315. {
  316. // water plane
  317. if(Water.draw)
  318. {
  319. Flt d=Dist(pos, Water.plane);
  320. if( d<=0)
  321. {
  322. if(depth)*depth=d;
  323. return WaterMtrlGlobal;
  324. }
  325. }
  326. // water areas
  327. if(Area *area=areaLoaded(worldToArea(pos)))
  328. if(Area::Data *data=area->data())
  329. REPA(data->waters)
  330. if(data->waters[i].under(pos, depth))
  331. if(C WaterMtrlPtr &mtrl=data->waters[i].material())return mtrl;else return WaterMtrlGlobal; // WaterMesh material can return null in which case Water is used
  332. return WaterMtrlNull;
  333. }
  334. /******************************************************************************/
  335. // SET
  336. /******************************************************************************/
  337. void WorldManager::setShader()
  338. {
  339. SyncLocker locker(_lock);
  340. REPAO(_area_active )->setShader();
  341. REPAO(_area_inactive)->setShader();
  342. REPAO(_area_cache )->setShader();
  343. }
  344. /******************************************************************************/
  345. // LOAD / UNLOAD
  346. /******************************************************************************/
  347. void WorldManager::areaUnload(Area &area)
  348. {
  349. if(area.state())
  350. {
  351. #if DEBUG
  352. Dbl t=Time.curTime();
  353. #endif
  354. if(area.loaded())
  355. {
  356. area.saveObjs();
  357. }
  358. // path
  359. _path.set(null, area.xz());
  360. // data
  361. if(area.data())
  362. {
  363. // save changes
  364. if(area.data()->customSaveWant())
  365. {
  366. File f; if(area.data()->save(f.writeMem()))
  367. {
  368. Str path=dataPath()+"Area/"; if(!FExistSystem(path))FCreateDirs(path);
  369. f.pos(0); SafeOverwrite(f, path+area.xz(), null, area_cipher);
  370. }
  371. }
  372. Delete(area._data);
  373. }
  374. // objects
  375. REPA(area._objs)
  376. {
  377. Obj &obj=*area._objs[i];
  378. if(ObjMap<Obj> *obj_map=obj.worldObjMap())obj_map->removeObj(&obj);
  379. }
  380. area._objs.del();
  381. // remove
  382. switch(area.state())
  383. {
  384. case AREA_ACTIVE : _area_active .exclude(&area); break;
  385. case AREA_INACTIVE: _area_inactive.exclude(&area); break;
  386. case AREA_CACHE : _area_cache .exclude(&area); break;
  387. }
  388. area._state=AREA_UNLOADED;
  389. #if DEBUG
  390. _time_area_update_state_unload+=Time.curTime()-t;
  391. #endif
  392. }
  393. }
  394. void WorldManager::areaUnloadToCache(Area &area)
  395. {
  396. if(area.loaded())
  397. {
  398. #if DEBUG
  399. Dbl t=Time.curTime();
  400. #endif
  401. if(area.loaded())
  402. {
  403. if(Area::Data *data=area._data)
  404. {
  405. data->customUnloadToCache();
  406. data->actor.del();
  407. REPAO(data->terrain_objs).actor.del();
  408. REPA (data->foliage_objs){Area::Data::GrassObj &go=data->foliage_objs[i]; REPAO(go.instances).actor.del();}
  409. }
  410. area.saveObjs();
  411. }
  412. // path
  413. _path.set(null, area.xz());
  414. // objects
  415. REPA(area._objs)
  416. {
  417. Obj &obj=*area._objs[i];
  418. if(ObjMap<Obj> *obj_map=obj.worldObjMap())obj_map->removeObj(&obj);
  419. }
  420. area._objs.del();
  421. // remove
  422. switch(area.state())
  423. {
  424. case AREA_ACTIVE : _area_active .exclude(&area); break;
  425. case AREA_INACTIVE: _area_inactive.exclude(&area); break;
  426. }
  427. _area_cache.add(&area);
  428. area._state=AREA_CACHE;
  429. #if DEBUG
  430. _time_area_update_state_unload_cache+=Time.curTime()-t;
  431. #endif
  432. }
  433. }
  434. /******************************************************************************/
  435. void WorldManager::areaCache(Area &area, Bool inc_progress, File &file_area)
  436. {
  437. if(area.state()==AREA_UNLOADED)
  438. {
  439. if(file_area.readTry(dataPath()+"Area/"+area.xz(), area_cipher))
  440. {
  441. Area::Data *data; _area_data(data, area).load(file_area); // first create
  442. area._data= data; // then set (this is important for multi-threading, we need to have fully valid 'Area::Data' object before setting pointer to it)
  443. }
  444. _area_cache.add(&area);
  445. area._state=AREA_CACHE;
  446. if(inc_progress && _areas_to_load)_update_progress=Sat(_update_progress+1.0f/_areas_to_load);
  447. }
  448. }
  449. /******************************************************************************/
  450. void WorldManager::areaLoad(Area &area, Bool active, File &file_area)
  451. {
  452. if(area.state()==AREA_UNLOADED || area.state()==AREA_CACHE)
  453. {
  454. #if DEBUG
  455. Dbl t=Time.curTime();
  456. #endif
  457. // load area data
  458. if(area.state()==AREA_UNLOADED)
  459. {
  460. if(file_area.readTry(dataPath()+"Area/"+area.xz(), area_cipher))_area_data(area._data, area).load(file_area);
  461. }
  462. #if DEBUG
  463. _time_area_update_state_load_data+=Time.curTime()-t;
  464. #endif
  465. // objects
  466. {
  467. // original world data
  468. if(area._data)
  469. {
  470. Memc<Area::Data::AreaObj> &objs=area._data->objs;
  471. REPA(objs)
  472. {
  473. Area::Data::AreaObj &obj=objs[i];
  474. switch(obj.access())
  475. {
  476. case OBJ_ACCESS_CUSTOM:
  477. {
  478. if(!area._visited || obj.constant()) // non-constant objects should be created only the first time we're entering an area, since then they are stored in savegame
  479. if(!loadObj(area, active, obj, obj.constant())){} // don't break since objects are stored in container and can proceed
  480. }break;
  481. }
  482. }
  483. }
  484. // temporary/save data
  485. {
  486. File &f=area._saved_obj; f.pos(0);
  487. ChunkReader cr; if(cr.read(f))for(; File *obj_file=cr(); )
  488. {
  489. switch(cr.ver())
  490. {
  491. case 0: loadObj(area, active, ObjType.find(cr.name()), *obj_file); break;
  492. case 1: {UID id; if(DecodeRaw(cr.name(), id))loadObj(area, active, ObjType.find(id ), *obj_file);} break;
  493. }
  494. }
  495. f.reset(); // zero data
  496. }
  497. }
  498. // finalize
  499. if(area.state()==AREA_CACHE)_area_cache .exclude(&area);
  500. if(active )_area_active .add (&area);
  501. else _area_inactive.add (&area);
  502. area._state=(active ? AREA_ACTIVE : AREA_INACTIVE);
  503. if(Area::Data *data=area._data)
  504. {
  505. // create actors for terrain and objects
  506. if(Physics.created())
  507. {
  508. data->actor.create(data->phys, 0).group(AG_TERRAIN);
  509. FREPA(data->terrain_objs)
  510. {
  511. Area::Data::TerrainObj &obj=data->terrain_objs[i];
  512. if(obj.obj->phys())
  513. {
  514. obj.actor.create(*obj.obj->phys(), 0, obj.matrix.scale()).matrix(Matrix(obj.matrix).normalize()).group(AG_TERRAIN);
  515. }
  516. }
  517. FREPA(data->foliage_objs)
  518. {
  519. Area::Data::GrassObj &obj=data->foliage_objs[i];
  520. if(obj.phys)FREPA(obj.instances)
  521. {
  522. Area::Data::GrassObj::Instance &instance=obj.instances[i];
  523. instance.actor.create(*obj.phys, 0, instance.matrix.scale()).matrix(Matrix(instance.matrix).normalize()).group(AG_TERRAIN);
  524. }
  525. }
  526. }
  527. _path.set(data->_path_mesh, area.xz());
  528. data->customLoadFromCache();
  529. if(active)data->customActivate ();
  530. else data->customDeactivate ();
  531. }
  532. area._visited=true;
  533. if(_areas_to_load)_update_progress=Sat(_update_progress+1.0f/_areas_to_load);
  534. Time.skipUpdate();
  535. UpdateThreads();
  536. #if DEBUG
  537. _time_area_update_state_load+=Time.curTime()-t;
  538. #endif
  539. }
  540. }
  541. /******************************************************************************/
  542. // REFERENCES
  543. /******************************************************************************/
  544. void WorldManager::linkReferences()
  545. {
  546. // world object link
  547. REPA(_area_active ){Memc<Obj*> &objs=_area_active [i]->_objs; REPAO(objs)->linkReferences();}
  548. REPA(_area_inactive){Memc<Obj*> &objs=_area_inactive[i]->_objs; REPAO(objs)->linkReferences();}
  549. // custom link
  550. if(link_references)link_references();
  551. // clear
  552. _obj_newly_added .clear();
  553. }
  554. /******************************************************************************/
  555. // UPDATE
  556. /******************************************************************************/
  557. void WorldManager::areaActivate(Area &area)
  558. {
  559. if(area.state()==AREA_INACTIVE)
  560. {
  561. #if DEBUG
  562. Dbl t=Time.curTime();
  563. #endif
  564. REPA(area._objs)area._objs[i]->enable();
  565. _area_inactive.exclude(&area); // remove
  566. _area_active .add (&area); // put
  567. area._state=AREA_ACTIVE;
  568. if(area._data)area._data->customActivate();
  569. #if DEBUG
  570. _time_area_update_state_activate+=Time.curTime()-t;
  571. #endif
  572. }
  573. }
  574. void WorldManager::areaDeactivate(Area &area)
  575. {
  576. if(area.state()==AREA_ACTIVE)
  577. {
  578. #if DEBUG
  579. Dbl t=Time.curTime();
  580. #endif
  581. REPA(area._objs)area._objs[i]->disable();
  582. _area_active .exclude(&area); // remove
  583. _area_inactive.add (&area); // put
  584. area._state=AREA_INACTIVE;
  585. if(area._data)area._data->customDeactivate();
  586. #if DEBUG
  587. _time_area_update_state_deactivate+=Time.curTime()-t;
  588. #endif
  589. }
  590. }
  591. /******************************************************************************/
  592. static Bool NeedLoad(AREA_STATE src, AREA_STATE dest) // warning: must be in sync with function below
  593. {
  594. switch(dest)
  595. {
  596. case AREA_ACTIVE :
  597. case AREA_INACTIVE:
  598. switch(src)
  599. {
  600. case AREA_CACHE :
  601. case AREA_UNLOADED: return true;
  602. }
  603. break;
  604. case AREA_LOAD:
  605. {
  606. switch(src)
  607. {
  608. case AREA_UNLOADED: return true;
  609. }
  610. }break;
  611. }
  612. return false;
  613. }
  614. static Bool NeedUnload(AREA_STATE src, AREA_STATE dest) // warning: must be in sync with function below
  615. {
  616. switch(dest)
  617. {
  618. case AREA_CACHE :
  619. case AREA_UNLOADED:
  620. switch(src)
  621. {
  622. case AREA_ACTIVE :
  623. case AREA_INACTIVE: return true;
  624. }
  625. break;
  626. }
  627. return false;
  628. }
  629. void WorldManager::areaUpdateState(Area &area, AREA_STATE state, File &file_area) // warning: must be in sync with function above
  630. {
  631. if(!_update_break)switch(state)
  632. {
  633. case AREA_ACTIVE:
  634. switch(area.state())
  635. {
  636. case AREA_INACTIVE: areaActivate(area ); break;
  637. case AREA_CACHE :
  638. case AREA_UNLOADED: areaLoad (area, true, file_area); break;
  639. }
  640. break;
  641. case AREA_INACTIVE:
  642. switch(area.state())
  643. {
  644. case AREA_ACTIVE : areaDeactivate(area ); break;
  645. case AREA_CACHE :
  646. case AREA_UNLOADED: areaLoad (area, false, file_area); break;
  647. }
  648. break;
  649. case AREA_CACHE:
  650. switch(area.state())
  651. {
  652. case AREA_ACTIVE :
  653. case AREA_INACTIVE: areaUnloadToCache(area); break;
  654. }
  655. break;
  656. case AREA_UNLOADED:
  657. switch(area.state())
  658. {
  659. case AREA_ACTIVE :
  660. case AREA_INACTIVE:
  661. case AREA_CACHE : areaUnload(area); break;
  662. }
  663. break;
  664. case AREA_LOAD:
  665. {
  666. switch(area.state())
  667. {
  668. case AREA_UNLOADED: areaCache(area, true, file_area); break;
  669. }
  670. }break;
  671. }
  672. }
  673. void WorldManager::areaUpdateState(Area &area, File &file_area)
  674. {
  675. areaUpdateState(area, rangeState(area.xz()), file_area);
  676. }
  677. static void UpdateState (Cell<Area> &cell, File &file_area) {cell().world()->areaUpdateState(cell(), file_area);}
  678. static void GetBackground(Cell<Area> &cell, WorldManager &world)
  679. {
  680. if(cell().state()==AREA_UNLOADED && world.rangeState(cell.xy())==AREA_CACHE) // not loaded and to cache
  681. world._area_background.add(&cell()); // add to list of loaded in the background
  682. }
  683. static void TestState(Cell<Area> &cell, WorldManager &world) {world._areas_to_load+=NeedLoad(cell().state(), world.rangeState(cell.xy()));}
  684. /******************************************************************************/
  685. struct RectSetter
  686. {
  687. Bool active_set , loaded_set;
  688. RectI *active_rect, *loaded_rect;
  689. void includeActive(C VecI2 &xy) {if(active_set)active_rect->include(xy);else{active_set=true; *active_rect=xy;}}
  690. void includeLoaded(C VecI2 &xy) {if(loaded_set)loaded_rect->include(xy);else{loaded_set=true; *loaded_rect=xy;}}
  691. RectSetter(RectI &active_rect, RectI &loaded_rect) {active_set=loaded_set=false; T.active_rect=&active_rect.zero(); T.loaded_rect=&loaded_rect.zero();}
  692. static void Func(Cell<Area> &cell, RectSetter &rs) {if(cell().state()==AREA_ACTIVE)rs.includeActive(cell.xy()); if(cell().state()!=AREA_UNLOADED)rs.includeLoaded(cell.xy());}
  693. };
  694. void WorldManager::areaSetLoadedRect()
  695. {
  696. // set area active/loaded rect
  697. switch(_mode)
  698. {
  699. case WORLD_STREAM:
  700. {
  701. _area_active_rect=_xzi;
  702. _area_active_rect.extend(_rangei);
  703. _area_loaded_rect=_area_active_rect;
  704. _area_loaded_rect.extend(2); // +1=INACTIVE, +1=CACHE
  705. }break;
  706. case WORLD_FULL:
  707. {
  708. _grid.size(_area_loaded_rect); // detect according to loaded 'grid' objects
  709. _area_active_rect=_area_loaded_rect;
  710. }break;
  711. case WORLD_MANUAL:
  712. {
  713. RectSetter rs(_area_active_rect, _area_loaded_rect); _grid.func(RectSetter::Func, rs);
  714. }break;
  715. }
  716. // set fast access
  717. if(_area_loaded_rect.w()>=16384
  718. || _area_loaded_rect.h()>=16384)Exit(S+"Loaded 'Game.Area' coverage exceeds allowed memory limits!\nLoaded Area coordinates:\n"+_area_loaded_rect.asText()+"\nWidth: "+_area_loaded_rect.w()+", Height: "+_area_loaded_rect.h()+"\nTotal Areas: "+_area_loaded_rect.w()*_area_loaded_rect.h());
  719. _grid.fastAccess(&_area_loaded_rect);
  720. }
  721. void WorldManager::areaSetVisibility(Memc<Area*> &area_draw, Bool sort)
  722. {
  723. if(is()) // if world exists
  724. {
  725. Memt<VecI2> areas; Frustum.getIntersectingAreas(areas, areaSize(), true, sort, true, &_area_active_rect);
  726. area_draw.clear(); FREPA(areas)if(Area *area=areaActive(areas[i]))area_draw.add(area); // add in same order
  727. }
  728. }
  729. void WorldManager::areaUpdateState()
  730. {
  731. if(_mode!=WORLD_MANUAL)
  732. {
  733. #if DEBUG
  734. Dbl t=Time.curTime(),
  735. time_area_update_state =t,
  736. time_area_update_state_now=t;
  737. _time_area_update_state_unload_cache=0;
  738. _time_area_update_state_unload =0;
  739. _time_area_update_state_load =0;
  740. _time_area_update_state_load_data =0;
  741. _time_area_update_state_activate =0;
  742. _time_area_update_state_deactivate =0;
  743. #endif
  744. RectI rect(_xzi); rect.extend(_rangei+1); // +1=INACTIVE
  745. // pause background thread
  746. LOG("areaUpdateState lock");
  747. _lock.on();
  748. // make a quick test of which areas need to be loaded (used for 'updateProgress')
  749. LOG("areaUpdateState TestState");
  750. _areas_to_load=0;
  751. if(_mode==WORLD_FULL)_grid.func ( TestState, T);
  752. else _grid.funcCreate(rect, TestState, T);
  753. // before making any changes to area states, make sure that objects are correctly assigned to them
  754. updateObjectAreas();
  755. // process data required for this moment instantly
  756. LOG("areaUpdateState process data required for this moment instantly");
  757. File file_area; // use one file object to make use of the performance improvement for pak load
  758. if(_mode==WORLD_FULL)_grid.func(UpdateState, file_area);else // process all areas for 'WORLD_FULL'
  759. {
  760. Bool delay_remove=(_areas_to_load && !low_memory_usage); // if want to load something and we don't want low memory usage
  761. if( delay_remove)DelayRemoveInc();
  762. REPA(_area_active )areaUpdateState(*_area_active [i], file_area); // order is important
  763. REPA(_area_inactive)areaUpdateState(*_area_inactive[i], file_area); // order is important
  764. REPA(_area_cache )areaUpdateState(*_area_cache [i], file_area); // order is important
  765. _grid.funcCreate(rect, UpdateState, file_area);
  766. if( delay_remove)DelayRemoveDec();
  767. }
  768. #if DEBUG
  769. t=Time.curTime();
  770. _time_area_update_state_now =t-time_area_update_state_now;
  771. Dbl time_area_update_state_back=t;
  772. #endif
  773. rect.extend(1); // +1=CACHE
  774. // set areas to be loaded in the background thread
  775. LOG("areaUpdateState set areas to be loaded in the background thread");
  776. _area_background.clear(); if(use_background_loading && _thread.created() && _mode==WORLD_STREAM)_grid.funcCreate(rect, GetBackground, T);
  777. if(_area_background.elms ())_thread_event.on(); // activate the thread
  778. // enable background thread
  779. LOG("areaUpdateState unlock");
  780. _lock.off();
  781. #if DEBUG
  782. t=Time.curTime();
  783. _time_area_update_state_back=t-time_area_update_state_back;
  784. Dbl time_area_update_state_path=t;
  785. #endif
  786. // set data after updating the areas
  787. LOG("areaUpdateState areaSetLoadedRect");
  788. areaSetLoadedRect(); // set loaded areas lookup table
  789. LOG("areaUpdateState pathBuild");
  790. path2DBuild (); // build paths after setting active areas
  791. // delete unused mini map images
  792. if(_mode==WORLD_STREAM)
  793. {
  794. // at this line of code, 'rect' specifies range up to CACHE
  795. RectI leave(Floor(mini_map.areaToImage(Vec2(rect.min))),
  796. Floor(mini_map.areaToImage(Vec2(rect.max))));
  797. mini_map.clear(&leave);
  798. }
  799. LOG("areaUpdateState end");
  800. #if DEBUG
  801. t=Time.curTime();
  802. _time_area_update_state_path=t-time_area_update_state_path;
  803. _time_area_update_state =t-time_area_update_state;
  804. #endif
  805. }
  806. }
  807. static void AreaUnloadRemaining(Cell<Area> &cell, WorldManager &world)
  808. {
  809. if(cell()._temp)cell()._temp=false; // was marked, so it was processed manually, we can disable the mark flag now
  810. else world.areaUnload(cell()); // was not marked, it was not processed manually, we need to unload the area
  811. }
  812. void WorldManager::areaSetState(C MemPtr<AreaState> &area_states, Bool unload_remaining)
  813. {
  814. if(_mode==WORLD_MANUAL)
  815. {
  816. _update_progress=0;
  817. // pause background thread
  818. _lock.on();
  819. // make a quick test of which areas need to be loaded (used for 'updateProgress')
  820. _areas_to_load =0;
  821. Int areas_to_unload=0;
  822. REPA(area_states)
  823. {
  824. C AreaState &area_state= area_states[i];
  825. AREA_STATE cur_state=_grid.get(area_state.xz).data()->state();
  826. _areas_to_load +=NeedLoad (cur_state, area_state.state);
  827. areas_to_unload+=NeedUnload(cur_state, area_state.state);
  828. }
  829. // before making any changes to area states, make sure that objects are correctly assigned to them
  830. Bool delay_remove=false;
  831. if(unload_remaining || areas_to_unload)
  832. {
  833. updateObjectAreas(); // if unloading at least one area then update area objects
  834. if(!low_memory_usage && _areas_to_load) // if don't want low memory usage and unloading and loading
  835. {
  836. delay_remove=true;
  837. DelayRemoveInc();
  838. }
  839. }
  840. // update area states
  841. File file_area; // use one file object to make use of the performance improvement for pak load
  842. _area_background.clear();
  843. FREPA(area_states) // process in given order
  844. {
  845. C AreaState &area_state= area_states[i];
  846. Area &area =*_grid.get(area_state.xz).data(); if(unload_remaining)area._temp=true; // if want to unload remaining, then mark this area as "manually processed"
  847. areaUpdateState(area, area_state.state, file_area);
  848. if(use_background_loading && _thread.created() && area_state.state==AREA_CACHE && area.state()==AREA_UNLOADED)_area_background.add(&area); // if after update is still unloaded, but wants to be cached then add to background list
  849. }
  850. // unload remaining
  851. if(unload_remaining)_grid.func(AreaUnloadRemaining, T);
  852. // set areas to be loaded in the background thread
  853. if(_area_background.elms())_thread_event.on(); // activate the thread
  854. // enable background thread
  855. _lock.off();
  856. // release resource pointer copies after loading all areas
  857. if(delay_remove)DelayRemoveDec();
  858. // set data after updating the areas
  859. areaSetLoadedRect(); // set loaded areas lookup table
  860. path2DBuild (); // build paths after setting active areas
  861. }
  862. }
  863. void WorldManager::updateBreak()
  864. {
  865. _update_break=true;
  866. }
  867. void WorldManager::updateObjectAreas()
  868. {
  869. // update object area assignments (area which object is assigned to)
  870. REPA(_obj_container)if(ObjMap<Obj> *obj_map=_obj_container[i].map) // update areas of all objects (active and inactive, because objects can be accessed from both area states, and they can be repositioned manually)
  871. REPA(*obj_map) // go from end to start so remove can be used
  872. {
  873. Obj &obj=(*obj_map)[i];
  874. if( !obj.updateArea())obj_map->removeObj(&obj);
  875. }
  876. }
  877. #if !__GNUC__ // fails to compile on GCC
  878. INLINE
  879. #endif
  880. void UpdateObject(WorldManager &world, Obj &obj)
  881. {
  882. obj._update_count=world._update_count;
  883. if(Obj *parent=obj.reliesOn())
  884. if( parent->_update_count!=world._update_count && parent->_area && parent->_area->state()==AREA_ACTIVE) // testing 'area' also guarantees that the object is existing
  885. {
  886. UID id =obj.id(); UpdateObject(world, *parent);
  887. if( id!=obj.id())return; // after parent update, this object could have been removed, that's why check if its 'id' hasn't been changed
  888. }
  889. if(!obj.update())
  890. if(ObjMap<Obj> *obj_map=obj.worldObjMap())obj_map->removeObj(&obj);
  891. }
  892. void WorldManager::updateObjects()
  893. {
  894. Dbl time=Time.curTime();
  895. FREPA(_area_active) // FREPA #2 (rep/frep)
  896. {
  897. Memc<Obj*> &objs=_area_active[i]->_objs;
  898. REPA(objs) // order is important in case of removing
  899. {
  900. Obj *o=objs[i];
  901. if( o->_update_count!=_update_count)UpdateObject(T, *o);
  902. if(i>objs.elms())i=objs.elms(); // in case if some 'Obj::update' would remove other objects and suddenly 'i' would be out of 'objs' container range
  903. }
  904. }
  905. _time_obj_update=Time.curTime()-time;
  906. }
  907. void WorldManager::update(C Vec2 &xz)
  908. {
  909. if(is())
  910. {
  911. _update_break =false;
  912. _update_progress=0;
  913. _update_count ++;
  914. // area change
  915. switch(_mode)
  916. {
  917. case WORLD_STREAM:
  918. {
  919. if(!_updated || (xz-T._xz).abs().max()>areaSize())
  920. {
  921. VecI2 xzi=worldToArea(xz);
  922. if(!_updated || xzi!=T._xzi)
  923. {
  924. T._xz =xz ;
  925. T._xzi =xzi ;
  926. T._updated=true;
  927. areaUpdateState();
  928. }
  929. }
  930. }break;
  931. case WORLD_FULL:
  932. {
  933. if(!_updated)
  934. {
  935. _updated=true;
  936. // create empty Cell<Area> objects for each files inside Paks and Std
  937. if(!FullPath(dataPath()))
  938. {
  939. if (C PaksFile *pf=Paks.find( dataPath()+"Area") )REP(pf->children_num )_grid.get(TextVecI2(Paks.file(pf->children_offset+i).file->name)); // Pak
  940. if(DataPath().is())for(FileFind ff (DataPath()+dataPath()+"Area"); ff(); )if (ff.type==FSTD_FILE)_grid.get(TextVecI2( ff .name)); // DataPath+Std
  941. } for(FileFind ff ( dataPath()+"Area"); ff(); )if (ff.type==FSTD_FILE)_grid.get(TextVecI2( ff .name)); // Std
  942. areaUpdateState();
  943. }
  944. }break;
  945. case WORLD_MANUAL:
  946. {
  947. _updated=true;
  948. // no action required
  949. }break;
  950. }
  951. // link references
  952. if(_obj_newly_added.elms())linkReferences();
  953. // update physics
  954. Bool update_objects_after_physics=T.update_objects_after_physics,
  955. background_simulation =PHYSX;
  956. if( background_simulation)
  957. {
  958. Physics.stopSimulation();
  959. // TODO: update cloth here
  960. if(physics_update)physics_update();
  961. Physics.startSimulation();
  962. update_objects_after_physics=true;
  963. }
  964. // update objects
  965. if(update_objects_after_physics==false)updateObjects();
  966. // start physics
  967. if(!background_simulation)Physics.startSimulation();
  968. // overlays
  969. REPA(_decals) // order is important
  970. {
  971. Decal2 &d=_decals[i];
  972. d.time-=Time.d();
  973. if(d.time<=0)_decals.remove(i, true);
  974. }
  975. REPA(_mesh_overlays) // order is important
  976. {
  977. MeshOverlay2 &mo=_mesh_overlays[i];
  978. mo.time-=Time.d();
  979. if(mo.time<=0)_mesh_overlays.remove(i, true);
  980. }
  981. // effects
  982. D.grassUpdate();
  983. // stop physics
  984. if(!background_simulation){Physics.stopSimulation(); if(physics_update)physics_update();}
  985. // update object areas, call after physics to immediately validate eventual new area position
  986. updateObjectAreas();
  987. // update objects
  988. if(update_objects_after_physics==true)updateObjects();
  989. // update path world
  990. _path.update(); // call this right away after updating objects, to make sure that we request rebuilds ASAP
  991. }
  992. }
  993. /******************************************************************************/
  994. // IO
  995. /******************************************************************************/
  996. static void AreaSave(Cell<Area> &cell, File &f)
  997. {
  998. if(cell().loaded())cell().saveObjs(); // first save loaded areas to temp
  999. cell().save (f, cell.xy()); // then save the temp to file
  1000. }
  1001. Bool WorldManager::save(File &f)
  1002. {
  1003. // timer
  1004. Time.skipUpdate();
  1005. // before saving, make sure that objects are correctly assigned to areas
  1006. updateObjectAreas();
  1007. // save
  1008. f.cmpUIntV( 0); // version
  1009. f.putStr (name()); // world name
  1010. _grid.func (AreaSave, f); // area data
  1011. f<<VecI2(SIGN_BIT, SIGN_BIT); // end marker
  1012. return f.ok();
  1013. }
  1014. Bool WorldManager::save(C Str &save_name, Bool (*save)(File &f), Cipher *cipher)
  1015. {
  1016. File f; if(f.writeTry(save_name, cipher))
  1017. {
  1018. if(T.save(f))
  1019. if(!save || save(f))
  1020. if(f.flushOK())return true;
  1021. f.del(); FDelFile(save_name);
  1022. }
  1023. return false;
  1024. }
  1025. /******************************************************************************/
  1026. Bool WorldManager::load(File &f)
  1027. {
  1028. Str world_name;
  1029. switch(f.decUIntV()) // version
  1030. {
  1031. case 0: f.getStr(world_name); break;
  1032. default: goto error;
  1033. }
  1034. if(NewTry(world_name))
  1035. {
  1036. // area data
  1037. for(;;)
  1038. {
  1039. VecI2 xz; f>>xz;
  1040. if(xz.x==SIGN_BIT
  1041. && xz.y==SIGN_BIT)break; // end marker
  1042. if(!f.ok())goto error;
  1043. Area &area=*_grid.get(xz).data();
  1044. if( !area.load(f))goto error;
  1045. }
  1046. // success
  1047. if(f.ok())return true;
  1048. }
  1049. error:;
  1050. del(); return false;
  1051. }
  1052. Bool WorldManager::load(C Str &save_name, Bool (*load)(File &f), Cipher *cipher)
  1053. {
  1054. File f; if(f.readTry(save_name, cipher))if(T.load(f))if(!load || load(f))return true;
  1055. del(); return false;
  1056. }
  1057. /******************************************************************************/
  1058. // MAIN
  1059. /******************************************************************************/
  1060. WorldManager::~WorldManager()
  1061. {
  1062. _thread.stop(); // first mark the thread to be stopped so it can do this on its own
  1063. _lock.on (); _area_background.clear(); // clear areas for load, so the thread won't process them
  1064. _lock.off();
  1065. _thread_event.on(); // turn on the event in case the thread is waiting for it
  1066. _thread.del(); // delete the thread before other members
  1067. del(); // delete everything
  1068. }
  1069. WorldManager::WorldManager()
  1070. {
  1071. area_cipher=null;
  1072. link_references=null;
  1073. physics_update=null;
  1074. _id.zero();
  1075. _mode=WORLD_STREAM;
  1076. _updated=_update_break=false;
  1077. _update_count=0;
  1078. _update_progress=0;
  1079. _areas_to_load=0;
  1080. _range=0;
  1081. _rangei=_rangei2=_rangei2_inactive=_rangei2_cache=0;
  1082. _xz .zero();
  1083. _xzi.zero();
  1084. _area_active_rect.set(0, 0, -1, -1);
  1085. _area_loaded_rect.set(0, 0, -1, -1);
  1086. _area_data=null; setAreaData<Area::Data>();
  1087. _grid.user(this);
  1088. _path_iteration=0;
  1089. _path_find.create(MAX_PATH_RES*2, MAX_PATH_RES*2);
  1090. activeRange(100);
  1091. }
  1092. /******************************************************************************/
  1093. }}
  1094. /******************************************************************************/