Scene.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. #include "Scene.h"
  2. #include "T3D/assets/LevelAsset.h"
  3. #include "T3D/gameBase/gameConnection.h"
  4. #include "T3D/gameMode.h"
  5. Scene * Scene::smRootScene = nullptr;
  6. Vector<Scene*> Scene::smSceneList;
  7. IMPLEMENT_CALLBACK(Scene, onSaving, void, (const char* fileName), (fileName),
  8. "@brief Called when a scene is saved to allow scenes to special-handle prepwork for saving if required.\n\n"
  9. "@param fileName The level file being saved\n");
  10. IMPLEMENT_CO_NETOBJECT_V1(Scene);
  11. Scene::Scene() :
  12. mParentScene(nullptr),
  13. mSceneId(-1),
  14. mIsEditing(false),
  15. mIsDirty(false),
  16. mEditPostFX(0)
  17. {
  18. mGameModesNames = StringTable->EmptyString();
  19. }
  20. Scene::~Scene()
  21. {
  22. }
  23. void Scene::initPersistFields()
  24. {
  25. docsURL;
  26. Parent::initPersistFields();
  27. addGroup("Internal");
  28. addField("isEditing", TypeBool, Offset(mIsEditing, Scene), "", AbstractClassRep::FIELD_HideInInspectors);
  29. addField("isDirty", TypeBool, Offset(mIsDirty, Scene), "", AbstractClassRep::FIELD_HideInInspectors);
  30. endGroup("Internal");
  31. addGroup("Gameplay");
  32. addField("gameModes", TypeGameModeList, Offset(mGameModesNames, Scene), "The game modes that this Scene is associated with.");
  33. endGroup("Gameplay");
  34. addGroup("PostFX");
  35. addProtectedField("EditPostEffects", TypeBool, Offset(mEditPostFX, Scene),
  36. &Scene::_editPostEffects, &defaultProtectedGetFn, "Edit Scene's default Post Effects", AbstractClassRep::FieldFlags::FIELD_ComponentInspectors);
  37. endGroup("PostFX");
  38. }
  39. bool Scene::onAdd()
  40. {
  41. if (!Parent::onAdd())
  42. return false;
  43. smSceneList.push_back(this);
  44. mSceneId = smSceneList.size() - 1;
  45. GameMode::findGameModes(mGameModesNames, &mGameModesList);
  46. return true;
  47. }
  48. void Scene::onRemove()
  49. {
  50. for (U32 i = 0; i < mGameModesList.size(); i++)
  51. {
  52. mGameModesList[i]->onSceneUnloaded_callback();
  53. }
  54. Parent::onRemove();
  55. smSceneList.remove(this);
  56. mSceneId = -1;
  57. }
  58. void Scene::onPostAdd()
  59. {
  60. if (isMethod("onPostAdd"))
  61. Con::executef(this, "onPostAdd");
  62. for (U32 i = 0; i < mGameModesList.size(); i++)
  63. {
  64. mGameModesList[i]->onSceneLoaded_callback();
  65. }
  66. }
  67. bool Scene::_editPostEffects(void* object, const char* index, const char* data)
  68. {
  69. Scene* scene = static_cast<Scene*>(object);
  70. #ifdef TORQUE_TOOLS
  71. if(Con::isFunction("editScenePostEffects"))
  72. Con::executef("editScenePostEffects", scene);
  73. #endif
  74. return false;
  75. }
  76. void Scene::addObject(SimObject* object)
  77. {
  78. //Child scene
  79. SubScene* scene = dynamic_cast<SubScene*>(object);
  80. if (scene)
  81. {
  82. //We'll keep these principly separate so they don't get saved into each other
  83. mSubScenes.push_back(scene);
  84. Parent::addObject(object);
  85. return;
  86. }
  87. SceneObject* sceneObj = dynamic_cast<SceneObject*>(object);
  88. if (sceneObj)
  89. {
  90. //We'll operate on the presumption that if it's being added via regular parantage means, it's considered permanent
  91. mPermanentObjects.push_back(sceneObj);
  92. Parent::addObject(object);
  93. return;
  94. }
  95. //Do it like regular, though we should probably bail if we're trying to add non-scene objects to the scene?
  96. Parent::addObject(object);
  97. }
  98. void Scene::removeObject(SimObject* object)
  99. {
  100. //Child scene
  101. SubScene* scene = dynamic_cast<SubScene*>(object);
  102. if (scene)
  103. {
  104. //We'll keep these principly separate so they don't get saved into each other
  105. mSubScenes.remove(scene);
  106. return;
  107. }
  108. SceneObject* sceneObj = dynamic_cast<SceneObject*>(object);
  109. if (sceneObj)
  110. {
  111. //We'll operate on the presumption that if it's being added via regular parantage means, it's considered permanent
  112. mPermanentObjects.remove(sceneObj);
  113. Parent::removeObject(object);
  114. return;
  115. }
  116. Parent::removeObject(object);
  117. }
  118. void Scene::addDynamicObject(SimObject* object)
  119. {
  120. mDynamicObjects.push_back(object);
  121. SimGroup* cleanupGroup;
  122. if(Sim::findObject("MissionCleanup", cleanupGroup))
  123. {
  124. cleanupGroup->addObject(object);
  125. }
  126. //Do it like regular, though we should probably bail if we're trying to add non-scene objects to the scene?
  127. //Parent::addObject(object);
  128. }
  129. void Scene::removeDynamicObject(SimObject* object)
  130. {
  131. mDynamicObjects.remove(object);
  132. SimGroup* cleanupGroup;
  133. if (Sim::findObject("MissionCleanup", cleanupGroup))
  134. {
  135. cleanupGroup->removeObject(object);
  136. }
  137. //Do it like regular, though we should probably bail if we're trying to add non-scene objects to the scene?
  138. //Parent::removeObject(object);
  139. }
  140. void Scene::interpolateTick(F32 delta)
  141. {
  142. }
  143. void Scene::processTick()
  144. {
  145. if (!isServerObject())
  146. return;
  147. //iterate over our subscenes to update their status of loaded or unloaded based on if any control objects intersect their bounds
  148. for (U32 i = 0; i < mSubScenes.size(); i++)
  149. {
  150. bool hasClients = false;
  151. SimGroup* pClientGroup = Sim::getClientGroup();
  152. for (SimGroup::iterator itr = pClientGroup->begin(); itr != pClientGroup->end(); itr++)
  153. {
  154. GameConnection* gc = dynamic_cast<GameConnection*>(*itr);
  155. if (gc)
  156. {
  157. GameBase* controlObj = gc->getControlObject();
  158. if (controlObj == nullptr)
  159. {
  160. controlObj = gc->getCameraObject();
  161. }
  162. if (controlObj != nullptr)
  163. {
  164. if (mSubScenes[i]->testBox(controlObj->getWorldBox()))
  165. {
  166. //we have a client controlling object in the bounds, so we ensure the contents are loaded
  167. hasClients = true;
  168. break;
  169. }
  170. }
  171. }
  172. }
  173. if (hasClients)
  174. {
  175. mSubScenes[i]->setUnloadTimeMS(-1);
  176. mSubScenes[i]->load();
  177. }
  178. else
  179. {
  180. if (mSubScenes[i]->isLoaded() && mSubScenes[i]->getUnloadTimsMS() == -1)
  181. {
  182. mSubScenes[i]->setUnloadTimeMS(Sim::getCurrentTime());
  183. }
  184. if (Sim::getCurrentTime() - mSubScenes[i]->getUnloadTimsMS() > 5000)
  185. mSubScenes[i]->unload();
  186. }
  187. }
  188. }
  189. void Scene::advanceTime(F32 timeDelta)
  190. {
  191. }
  192. U32 Scene::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
  193. {
  194. bool ret = Parent::packUpdate(conn, mask, stream);
  195. return ret;
  196. }
  197. void Scene::unpackUpdate(NetConnection *conn, BitStream *stream)
  198. {
  199. }
  200. void Scene::dumpUtilizedAssets()
  201. {
  202. Con::printf("Dumping utilized assets in scene!");
  203. Vector<StringTableEntry> utilizedAssetsList;
  204. /*for (U32 i = 0; i < mPermanentObjects.size(); i++)
  205. {
  206. mPermanentObjects[i]->getUtilizedAssets(&utilizedAssetsList);
  207. }
  208. for (U32 i = 0; i < mDynamicObjects.size(); i++)
  209. {
  210. mDynamicObjects[i]->getUtilizedAssets(&utilizedAssetsList);
  211. }*/
  212. for (U32 i = 0; i < utilizedAssetsList.size(); i++)
  213. {
  214. Con::printf("Utilized Asset: %s", utilizedAssetsList[i]);
  215. }
  216. Con::printf("Utilized Asset dump complete!");
  217. }
  218. StringTableEntry Scene::getOriginatingFile()
  219. {
  220. return getFilename();
  221. }
  222. StringTableEntry Scene::getLevelAsset()
  223. {
  224. StringTableEntry levelFile = getFilename();
  225. if (levelFile == StringTable->EmptyString())
  226. return StringTable->EmptyString();
  227. AssetQuery* query = new AssetQuery();
  228. query->registerObject();
  229. S32 foundAssetcount = AssetDatabase.findAssetLooseFile(query, levelFile);
  230. if (foundAssetcount == 0)
  231. return StringTable->EmptyString();
  232. else
  233. return query->mAssetList[0];
  234. }
  235. bool Scene::saveScene(StringTableEntry fileName)
  236. {
  237. //So, we ultimately want to not only save out the level, but also collate all the assets utilized
  238. //by the static objects in the scene so we can have those before we parse the level file itself
  239. //Useful for preloading or stat tracking
  240. //First, save the level file
  241. if (fileName == StringTable->EmptyString())
  242. {
  243. fileName = getOriginatingFile();
  244. }
  245. for (SimGroupIterator itr(this); *itr; ++itr)
  246. {
  247. if((*itr)->isMethod("onSaving"))
  248. {
  249. ConsoleValue vars[3];
  250. vars[2].setString(fileName);
  251. Con::execute((*itr), 3, vars);
  252. }
  253. }
  254. //Inform our subscenes we're saving so they can do any
  255. //special work required as well
  256. for (U32 i = 0; i < mSubScenes.size(); i++)
  257. {
  258. mSubScenes[i]->save();
  259. }
  260. bool saveSuccess = save(fileName);
  261. if (!saveSuccess)
  262. return false;
  263. //Get the level asset
  264. StringTableEntry levelAsset = getLevelAsset();
  265. if (levelAsset == StringTable->EmptyString())
  266. return saveSuccess;
  267. LevelAsset* levelAssetDef = AssetDatabase.acquireAsset<LevelAsset>(levelAsset);
  268. levelAssetDef->clearAssetDependencyFields("staticObjectAssetDependency");
  269. //Next, lets build out our
  270. Vector<StringTableEntry> utilizedAssetsList;
  271. for (U32 i = 0; i < size(); i++)
  272. {
  273. getUtilizedAssetsFromSceneObject(getObject(i), &utilizedAssetsList);
  274. }
  275. for (U32 i = 0; i < utilizedAssetsList.size(); i++)
  276. {
  277. char depSlotName[50];
  278. dSprintf(depSlotName, sizeof(depSlotName), "%s%d", "staticObjectAssetDependency", i);
  279. char depValue[255];
  280. dSprintf(depValue, sizeof(depValue), "%s=%s", ASSET_ID_SIGNATURE, utilizedAssetsList[i]);
  281. levelAssetDef->setDataField(StringTable->insert(depSlotName), NULL, StringTable->insert(depValue));
  282. }
  283. //update the gamemode list as well
  284. levelAssetDef->setDataField(StringTable->insert("gameModesNames"), NULL, StringTable->insert(mGameModesNames));
  285. //Finally, save
  286. saveSuccess = levelAssetDef->saveAsset();
  287. return saveSuccess;
  288. }
  289. void Scene::getUtilizedAssetsFromSceneObject(SimObject* object, Vector<StringTableEntry>* usedAssetsList)
  290. {
  291. SceneObject* obj = dynamic_cast<SceneObject*>(object);
  292. if(obj)
  293. obj->getUtilizedAssets(usedAssetsList);
  294. SimGroup* group = dynamic_cast<SimGroup*>(object);
  295. if (group)
  296. {
  297. for (U32 c = 0; c < group->size(); c++)
  298. {
  299. SceneObject* childObj = dynamic_cast<SceneObject*>(group->getObject(c));
  300. //Recurse down
  301. getUtilizedAssetsFromSceneObject(childObj, usedAssetsList);
  302. }
  303. }
  304. }
  305. //
  306. Vector<SceneObject*> Scene::getObjectsByClass(String className)
  307. {
  308. return Vector<SceneObject*>();
  309. }
  310. void Scene::loadAtPosition(const Point3F& position)
  311. {
  312. for (U32 i = 0; i < mSubScenes.size(); i++)
  313. {
  314. Box3F testBox = Box3F(0.5);
  315. testBox.setCenter(position);
  316. if (mSubScenes[i]->testBox(testBox))
  317. {
  318. mSubScenes[i]->setUnloadTimeMS(-1);
  319. mSubScenes[i]->load();
  320. }
  321. }
  322. }
  323. DefineEngineFunction(getScene, Scene*, (U32 sceneId), (0),
  324. "Get the root Scene object that is loaded.\n"
  325. "@return The id of the Root Scene. Will be 0 if no root scene is loaded")
  326. {
  327. if (Scene::smSceneList.empty() || sceneId >= Scene::smSceneList.size())
  328. return nullptr;
  329. return Scene::smSceneList[sceneId];
  330. }
  331. DefineEngineFunction(getSceneCount, S32, (),,
  332. "Get the number of active Scene objects that are loaded.\n"
  333. "@return The number of active scenes")
  334. {
  335. return Scene::smSceneList.size();
  336. }
  337. DefineEngineFunction(getRootScene, S32, (), ,
  338. "Get the root Scene object that is loaded.\n"
  339. "@return The id of the Root Scene. Will be 0 if no root scene is loaded")
  340. {
  341. Scene* root = Scene::getRootScene();
  342. if (root)
  343. return root->getId();
  344. return 0;
  345. }
  346. DefineEngineMethod(Scene, getRootScene, S32, (),,
  347. "Get the root Scene object that is loaded.\n"
  348. "@return The id of the Root Scene. Will be 0 if no root scene is loaded")
  349. {
  350. Scene* root = Scene::getRootScene();
  351. if (root)
  352. return root->getId();
  353. return 0;
  354. }
  355. DefineEngineMethod(Scene, addDynamicObject, void, (SceneObject* sceneObj), (nullAsType<SceneObject*>()),
  356. "Adds an object to the scene's dynamic objects list. Used for things spawned as part of gameplay and not permanent objects to be saved out as part of the level proper.")
  357. {
  358. object->addDynamicObject(sceneObj);
  359. }
  360. DefineEngineMethod(Scene, clearDynamicObjects, void, (),,
  361. "Clears all objects from the scene's dynamic objects list.")
  362. {
  363. object->clearDynamicObjects();
  364. }
  365. DefineEngineMethod(Scene, removeDynamicObject, void, (SceneObject* sceneObj), (nullAsType<SceneObject*>()),
  366. "Removes an object from the scene's dynamic objects list.")
  367. {
  368. object->removeDynamicObject(sceneObj);
  369. }
  370. DefineEngineMethod(Scene, getObjectsByClass, String, (String className), (""),
  371. "Get the root Scene object that is loaded.\n"
  372. "@return The id of the Root Scene. Will be 0 if no root scene is loaded")
  373. {
  374. if (className == String::EmptyString)
  375. return "";
  376. //return object->getObjectsByClass(className);
  377. return "";
  378. }
  379. DefineEngineMethod(Scene, dumpUtilizedAssets, void, (), ,
  380. "Get the root Scene object that is loaded.\n"
  381. "@return The id of the Root Scene. Will be 0 if no root scene is loaded")
  382. {
  383. object->dumpUtilizedAssets();
  384. }
  385. DefineEngineMethod(Scene, getOriginatingFile, const char*, (), ,
  386. "Get the root Scene object that is loaded.\n"
  387. "@return The id of the Root Scene. Will be 0 if no root scene is loaded")
  388. {
  389. return object->getOriginatingFile();
  390. }
  391. DefineEngineMethod(Scene, getLevelAsset, const char*, (), ,
  392. "Get the root Scene object that is loaded.\n"
  393. "@return The id of the Root Scene. Will be 0 if no root scene is loaded")
  394. {
  395. return object->getLevelAsset();
  396. }
  397. DefineEngineMethod(Scene, save, bool, (const char* fileName), (""),
  398. "Save out the object to the given file.\n"
  399. "@param fileName The name of the file to save to."
  400. "@param True on success, false on failure.")
  401. {
  402. return object->saveScene(StringTable->insert(fileName));
  403. }
  404. DefineEngineMethod(Scene, loadAtPosition, void, (Point3F position), (Point3F::Zero),
  405. "Loads any subscenes at a given point by force.\n")
  406. {
  407. object->loadAtPosition(position);
  408. }