Skip to content

Commit a434586

Browse files
authored
Merge pull request #1481 from Areloch/MiscFixes_20250525
Misc Fixes and improvements including updated autosave handling
2 parents 63b8713 + 51a43d5 commit a434586

33 files changed

+975
-234
lines changed

Engine/source/T3D/Scene.cpp

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ StringTableEntry Scene::getLevelAsset()
291291
return query->mAssetList[0];
292292
}
293293

294-
bool Scene::saveScene(StringTableEntry fileName)
294+
bool Scene::saveScene(StringTableEntry fileName, const bool& saveSubScenes)
295295
{
296296
if (!isServerObject())
297297
return false;
@@ -316,9 +316,12 @@ bool Scene::saveScene(StringTableEntry fileName)
316316

317317
//Inform our subscenes we're saving so they can do any
318318
//special work required as well
319-
for (U32 i = 0; i < mSubScenes.size(); i++)
319+
if (saveSubScenes)
320320
{
321-
mSubScenes[i]->save();
321+
for (U32 i = 0; i < mSubScenes.size(); i++)
322+
{
323+
mSubScenes[i]->save();
324+
}
322325
}
323326

324327
bool saveSuccess = save(fileName);
@@ -381,9 +384,30 @@ void Scene::getUtilizedAssetsFromSceneObject(SimObject* object, Vector<StringTab
381384
}
382385

383386
//
384-
Vector<SceneObject*> Scene::getObjectsByClass(String className)
387+
void Scene::getObjectsByClass(SimObject* object, StringTableEntry className, Vector<SimObject*>* objectsList, bool checkSubscenes)
385388
{
386-
return Vector<SceneObject*>();
389+
if(object->getClassName() == className)
390+
{
391+
objectsList->push_back(object);
392+
}
393+
394+
//If it's a subscene and we DON'T want to scan through them, bail out now
395+
SubScene* subScene = dynamic_cast<SubScene*>(object);
396+
if (subScene && !checkSubscenes)
397+
return;
398+
399+
//If possible, now we iterate over the children
400+
SimGroup* group = dynamic_cast<SimGroup*>(object);
401+
if (group)
402+
{
403+
for (U32 c = 0; c < group->size(); c++)
404+
{
405+
SimObject* childObj = dynamic_cast<SimObject*>(group->getObject(c));
406+
407+
//Recurse down
408+
getObjectsByClass(childObj, className, objectsList);
409+
}
410+
}
387411
}
388412

389413
void Scene::loadAtPosition(const Point3F& position)
@@ -460,15 +484,37 @@ DefineEngineMethod(Scene, removeDynamicObject, void, (SceneObject* sceneObj), (n
460484
object->removeDynamicObject(sceneObj);
461485
}
462486

463-
DefineEngineMethod(Scene, getObjectsByClass, String, (String className), (""),
487+
DefineEngineMethod(Scene, getObjectsByClass, String, (String className, bool checkSubScenes), ("", false),
464488
"Get the root Scene object that is loaded.\n"
465-
"@return The id of the Root Scene. Will be 0 if no root scene is loaded")
489+
"@param className The name of the class of objects to get a list of.\n"
490+
"@param checkSubScenes If true, will also scan through currently loaded subscenes to get matching objects.\n"
491+
"@return A space-separated list of object ids that match the searched-for className")
466492
{
467493
if (className == String::EmptyString)
468494
return "";
469495

470-
//return object->getObjectsByClass(className);
471-
return "";
496+
Vector<SimObject*>* objectsList = new Vector<SimObject*>();
497+
498+
object->getObjectsByClass(object, StringTable->insert(className.c_str()), objectsList, checkSubScenes);
499+
500+
char* retBuffer = Con::getReturnBuffer(1024);
501+
502+
U32 len = 0;
503+
S32 i;
504+
//Get the length of our return string
505+
for(U32 i=0; i < objectsList->size(); i++)
506+
len += dStrlen((*objectsList)[i]->getIdString());
507+
508+
char* ret = Con::getReturnBuffer(len + 1);
509+
ret[0] = 0;
510+
for (U32 i = 0; i < objectsList->size(); i++)
511+
{
512+
dStrcat(ret, (*objectsList)[i]->getIdString(), len + 1);
513+
dStrcat(ret, " ", len + 1);
514+
}
515+
516+
517+
return ret;
472518
}
473519

474520
DefineEngineMethod(Scene, dumpUtilizedAssets, void, (), ,
@@ -492,12 +538,12 @@ DefineEngineMethod(Scene, getLevelAsset, const char*, (), ,
492538
return object->getLevelAsset();
493539
}
494540

495-
DefineEngineMethod(Scene, save, bool, (const char* fileName), (""),
541+
DefineEngineMethod(Scene, save, bool, (const char* fileName, bool saveSubScenes), ("", true),
496542
"Save out the object to the given file.\n"
497543
"@param fileName The name of the file to save to."
498544
"@param True on success, false on failure.")
499545
{
500-
return object->saveScene(StringTable->insert(fileName));
546+
return object->saveScene(StringTable->insert(fileName), saveSubScenes);
501547
}
502548

503549
DefineEngineMethod(Scene, loadAtPosition, void, (Point3F position), (Point3F::Zero),

Engine/source/T3D/Scene.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,15 @@ class Scene : public NetObject, public virtual ITickable
7878
StringTableEntry getOriginatingFile();
7979
StringTableEntry getLevelAsset();
8080

81-
bool saveScene(StringTableEntry fileName);
81+
bool saveScene(StringTableEntry fileName, const bool& saveSubScenes = true);
8282

8383
//
8484
//Networking
8585
U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream) override;
8686
void unpackUpdate(NetConnection *conn, BitStream *stream) override;
8787

8888
//
89-
Vector<SceneObject*> getObjectsByClass(String className);
89+
void getObjectsByClass(SimObject* object, StringTableEntry className, Vector<SimObject*>* objectsList, bool checkSubscenes = false);
9090

9191
void getUtilizedAssetsFromSceneObject(SimObject* object, Vector<StringTableEntry>* usedAssetsList);
9292

Engine/source/T3D/SceneGroup.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "physics/physicsShape.h"
1010
#include "renderInstance/renderPassManager.h"
1111
#include "scene/sceneRenderState.h"
12+
#include "Scene.h"
1213

1314
IMPLEMENT_CO_NETOBJECT_V1(SceneGroup);
1415

@@ -156,6 +157,37 @@ void SceneGroup::onInspect(GuiInspector* inspector)
156157
regenButton->setConsoleCommand(rgBuffer);
157158

158159
regenFieldGui->addObject(regenButton);
160+
161+
//
162+
//Regen bounds button
163+
GuiInspectorField* reparentFieldGui = sceneGroupGrp->createInspectorField();
164+
reparentFieldGui->init(inspector, sceneGroupGrp);
165+
166+
reparentFieldGui->setSpecialEditField(true);
167+
reparentFieldGui->setTargetObject(this);
168+
169+
fldnm = StringTable->insert("ReparentOOBObjs");
170+
171+
reparentFieldGui->setSpecialEditVariableName(fldnm);
172+
173+
reparentFieldGui->setInspectorField(NULL, fldnm);
174+
reparentFieldGui->setDocs("");
175+
176+
stack->addObject(reparentFieldGui);
177+
178+
GuiButtonCtrl* reparentButton = new GuiButtonCtrl();
179+
reparentButton->registerObject();
180+
reparentButton->setDataField(StringTable->insert("profile"), NULL, "ToolsGuiButtonProfile");
181+
reparentButton->setText("Reparent Out-of-bounds Objs");
182+
reparentButton->resize(Point2I::Zero, regenFieldGui->getExtent());
183+
reparentButton->setHorizSizing(GuiControl::horizResizeWidth);
184+
reparentButton->setVertSizing(GuiControl::vertResizeHeight);
185+
186+
char rprntBuffer[512];
187+
dSprintf(rprntBuffer, 512, "%d.reparentOOBObjects();", this->getId());
188+
reparentButton->setConsoleCommand(rprntBuffer);
189+
190+
reparentFieldGui->addObject(reparentButton);
159191
#endif
160192
}
161193

@@ -279,6 +311,27 @@ void SceneGroup::recalculateBoundingBox()
279311
setMaskBits(TransformMask);
280312
}
281313

314+
void SceneGroup::reparentOOBObjects()
315+
{
316+
if (empty())
317+
return;
318+
319+
// Extend the bounding box to include each child's bounding box
320+
for (SimSetIterator itr(this); *itr; ++itr)
321+
{
322+
SceneObject* child = dynamic_cast<SceneObject*>(*itr);
323+
if (child)
324+
{
325+
const Box3F& childBox = child->getWorldBox();
326+
327+
if(!mWorldBox.isOverlapped(childBox))
328+
{
329+
Scene::getRootScene()->addObject(child);
330+
}
331+
}
332+
}
333+
}
334+
282335
U32 SceneGroup::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
283336
{
284337
U32 retMask = Parent::packUpdate(conn, mask, stream);
@@ -363,3 +416,9 @@ DefineEngineMethod(SceneGroup, recalculateBounds, void, (), ,
363416
{
364417
object->recalculateBoundingBox();
365418
}
419+
420+
DefineEngineMethod(SceneGroup, reparentOOBObjects, void, (), ,
421+
"Finds objects that are children of the SceneGroup and, if not overlapping or in the bounds, reparents them to the root scene.\n")
422+
{
423+
object->reparentOOBObjects();
424+
}

Engine/source/T3D/SceneGroup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class SceneGroup : public SceneObject
4646
void addObject(SimObject* object) override;
4747
void removeObject(SimObject* object) override;
4848
void recalculateBoundingBox();
49+
void reparentOOBObjects();
4950

5051
///
5152
bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& sphere) override;

Engine/source/T3D/SubScene.cpp

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include "gfx/gfxDrawUtil.h"
1111
#include "gfx/gfxTransformSaver.h"
1212
#include "gui/editor/inspector/group.h"
13+
#include "gui/worldEditor/editor.h"
14+
#include "math/mathIO.h"
1315
#include "T3D/gameBase/gameBase.h"
1416

1517
bool SubScene::smTransformChildren = false;
@@ -32,7 +34,9 @@ SubScene::SubScene() :
3234
mTickPeriodMS(1000),
3335
mCurrTick(0),
3436
mGlobalLayer(false),
35-
mSaving(false)
37+
mSaving(false),
38+
mUseSeparateLoadBounds(false),
39+
mLoadBounds(Point3F::One)
3640
{
3741
mNetFlags.set(Ghostable | ScopeAlways);
3842

@@ -70,6 +74,8 @@ void SubScene::initPersistFields()
7074
INITPERSISTFIELD_SUBSCENEASSET(SubScene, SubScene, "The subscene asset to load.");
7175
addField("tickPeriodMS", TypeS32, Offset(mTickPeriodMS, SubScene), "evaluation rate (ms)");
7276
addField("gameModes", TypeGameModeList, Offset(mGameModesNames, SubScene), "The game modes that this subscene is associated with.");
77+
addField("UseSeparateLoadBounds", TypeBool, Offset(mUseSeparateLoadBounds, SubScene), "If true, this subscene will utilize a separate bounds for triggering loading/unloading than it's object bounds");
78+
addField("LoadBounds", TypePoint3F, Offset(mLoadBounds, SubScene), "If UseSeparateLoadBounds is true, this subscene will use this value to set up the load/unload bounds");
7379
endGroup("SubScene");
7480

7581
addGroup("LoadingManagement");
@@ -113,6 +119,11 @@ U32 SubScene::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
113119
U32 retMask = Parent::packUpdate(conn, mask, stream);
114120

115121
stream->writeFlag(mGlobalLayer);
122+
if(stream->writeFlag(mUseSeparateLoadBounds))
123+
{
124+
mathWrite(*stream, mLoadBounds);
125+
}
126+
116127

117128
return retMask;
118129
}
@@ -123,6 +134,11 @@ void SubScene::unpackUpdate(NetConnection* conn, BitStream* stream)
123134

124135
mGlobalLayer = stream->readFlag();
125136

137+
mUseSeparateLoadBounds = stream->readFlag();
138+
if(mUseSeparateLoadBounds)
139+
{
140+
mathRead(*stream, &mLoadBounds);
141+
}
126142
}
127143

128144
void SubScene::onInspect(GuiInspector* inspector)
@@ -220,7 +236,21 @@ bool SubScene::testBox(const Box3F& testBox)
220236
bool passes = mGlobalLayer;
221237

222238
if (!passes)
223-
passes = getWorldBox().isOverlapped(testBox);
239+
{
240+
if(mUseSeparateLoadBounds)
241+
{
242+
Box3F loadBox = Box3F(-mLoadBounds.x, -mLoadBounds.y, -mLoadBounds.z,
243+
mLoadBounds.x, mLoadBounds.y, mLoadBounds.z);
244+
245+
loadBox.setCenter(getPosition());
246+
247+
passes = loadBox.isOverlapped(testBox);
248+
}
249+
else
250+
{
251+
passes = getWorldBox().isOverlapped(testBox);
252+
}
253+
}
224254

225255
if (passes)
226256
passes = evaluateCondition();
@@ -268,6 +298,9 @@ void SubScene::processTick(const Move* move)
268298

269299
void SubScene::_onFileChanged(const Torque::Path& path)
270300
{
301+
if (gEditingMission)
302+
return;
303+
271304
if(mSubSceneAsset.isNull() || Torque::Path(mSubSceneAsset->getLevelPath()) != path)
272305
return;
273306

@@ -426,7 +459,7 @@ void SubScene::unload()
426459

427460
}
428461

429-
bool SubScene::save()
462+
bool SubScene::save(const String& filename)
430463
{
431464
if (!isServerObject())
432465
return false;
@@ -451,6 +484,9 @@ bool SubScene::save()
451484

452485
StringTableEntry levelPath = mSubSceneAsset->getLevelPath();
453486

487+
if (filename.isNotEmpty())
488+
levelPath = StringTable->insert(filename.c_str());
489+
454490
FileStream fs;
455491
fs.open(levelPath, Torque::FS::File::Write);
456492
fs.close();
@@ -547,8 +583,26 @@ void SubScene::renderObject(ObjectRenderInst* ri,
547583
//Box3F scale = getScale()
548584
//Box3F bounds = Box3F(-m)
549585

586+
if(mUseSeparateLoadBounds && !mGlobalLayer)
587+
{
588+
Box3F loadBounds = Box3F(-mLoadBounds.x, -mLoadBounds.y, -mLoadBounds.z,
589+
mLoadBounds.x, mLoadBounds.y, mLoadBounds.z);
590+
591+
//bounds.setCenter(getPosition());
592+
593+
ColorI loadBoundsColor = ColorI(200, 200, 100, 50);
594+
595+
drawer->drawCube(desc, loadBounds, loadBoundsColor);
596+
597+
// Render wireframe.
598+
599+
desc.setFillModeWireframe();
600+
drawer->drawCube(desc, loadBounds, ColorI::BLACK);
601+
desc.setFillModeSolid();
602+
}
603+
550604
Point3F scale = getScale();
551-
Box3F bounds = Box3F(-scale/2, scale/2);
605+
Box3F bounds = Box3F(-scale / 2, scale / 2);
552606

553607
ColorI boundsColor = ColorI(135, 206, 235, 50);
554608

@@ -565,10 +619,11 @@ void SubScene::renderObject(ObjectRenderInst* ri,
565619
drawer->drawCube(desc, bounds, ColorI::BLACK);
566620
}
567621

568-
DefineEngineMethod(SubScene, save, bool, (),,
569-
"Save out the subScene.\n")
622+
DefineEngineMethod(SubScene, save, bool, (const char* filename), (""),
623+
"Save out the subScene.\n"
624+
"@param filename (optional) If empty, the subScene will save to it's regular asset path. If defined, it will save out to the filename provided")
570625
{
571-
return object->save();
626+
return object->save(filename);
572627
}
573628

574629

Engine/source/T3D/SubScene.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ class SubScene : public SceneGroup
5252

5353
bool mGlobalLayer;
5454

55+
bool mUseSeparateLoadBounds;
56+
Point3F mLoadBounds;
57+
5558
public:
5659
SubScene();
5760
virtual ~SubScene();
@@ -118,7 +121,7 @@ class SubScene : public SceneGroup
118121
return mStartUnloadTimerMS;
119122
}
120123

121-
bool save();
124+
bool save(const String& filename = String());
122125

123126
DECLARE_CALLBACK(void, onLoaded, ());
124127
DECLARE_CALLBACK(void, onUnloaded, ());

0 commit comments

Comments
 (0)