Initial implementation of the Scene object for handling scenes/levels in a more consistent and deliberate way.

This commit is contained in:
Areloch 2019-02-23 15:55:28 -06:00
parent e0627973fb
commit 1c2f90a190
37 changed files with 509 additions and 140 deletions

236
Engine/source/T3D/Scene.cpp Normal file
View file

@ -0,0 +1,236 @@
#include "Scene.h"
Scene * Scene::smRootScene = nullptr;
Vector<Scene*> Scene::smSceneList;
IMPLEMENT_CO_NETOBJECT_V1(Scene);
Scene::Scene() :
mIsSubScene(false),
mParentScene(nullptr),
mSceneId(-1),
mIsEditing(false),
mIsDirty(false)
{
}
Scene::~Scene()
{
}
void Scene::initPersistFields()
{
Parent::initPersistFields();
addGroup("Internal");
addField("isSubscene", TypeBool, Offset(mIsSubScene, Scene), "", AbstractClassRep::FIELD_HideInInspectors);
addField("isEditing", TypeBool, Offset(mIsEditing, Scene), "", AbstractClassRep::FIELD_HideInInspectors);
addField("isDirty", TypeBool, Offset(mIsDirty, Scene), "", AbstractClassRep::FIELD_HideInInspectors);
endGroup("Internal");
}
bool Scene::onAdd()
{
if (!Parent::onAdd())
return false;
smSceneList.push_back(this);
mSceneId = smSceneList.size() - 1;
/*if (smRootScene == nullptr)
{
//we're the first scene, so we're the root. woo!
smRootScene = this;
}
else
{
mIsSubScene = true;
smRootScene->mSubScenes.push_back(this);
}*/
return true;
}
void Scene::onRemove()
{
Parent::onRemove();
smSceneList.remove(this);
mSceneId = -1;
/*if (smRootScene == this)
{
for (U32 i = 0; i < mSubScenes.size(); i++)
{
mSubScenes[i]->deleteObject();
}
}
else if (smRootScene != nullptr)
{
for (U32 i = 0; i < mSubScenes.size(); i++)
{
if(mSubScenes[i]->getId() == getId())
smRootScene->mSubScenes.erase(i);
}
}*/
}
void Scene::addObject(SimObject* object)
{
//Child scene
Scene* scene = dynamic_cast<Scene*>(object);
if (scene)
{
//We'll keep these principly separate so they don't get saved into each other
mSubScenes.push_back(scene);
return;
}
SceneObject* sceneObj = dynamic_cast<SceneObject*>(object);
if (sceneObj)
{
//We'll operate on the presumption that if it's being added via regular parantage means, it's considered permanent
mPermanentObjects.push_back(sceneObj);
Parent::addObject(object);
return;
}
//Do it like regular, though we should probably bail if we're trying to add non-scene objects to the scene?
Parent::addObject(object);
}
void Scene::removeObject(SimObject* object)
{
//Child scene
Scene* scene = dynamic_cast<Scene*>(object);
if (scene)
{
//We'll keep these principly separate so they don't get saved into each other
mSubScenes.remove(scene);
return;
}
SceneObject* sceneObj = dynamic_cast<SceneObject*>(object);
if (sceneObj)
{
//We'll operate on the presumption that if it's being added via regular parantage means, it's considered permanent
mPermanentObjects.remove(sceneObj);
Parent::removeObject(object);
return;
}
Parent::removeObject(object);
}
void Scene::addDynamicObject(SceneObject* object)
{
mDynamicObjects.push_back(object);
//Do it like regular, though we should probably bail if we're trying to add non-scene objects to the scene?
Parent::addObject(object);
}
void Scene::removeDynamicObject(SceneObject* object)
{
mDynamicObjects.remove(object);
//Do it like regular, though we should probably bail if we're trying to add non-scene objects to the scene?
Parent::removeObject(object);
}
void Scene::interpolateTick(F32 delta)
{
}
void Scene::processTick()
{
}
void Scene::advanceTime(F32 timeDelta)
{
}
U32 Scene::packUpdate(NetConnection *conn, U32 mask, BitStream *stream)
{
bool ret = Parent::packUpdate(conn, mask, stream);
return ret;
}
void Scene::unpackUpdate(NetConnection *conn, BitStream *stream)
{
}
//
Vector<SceneObject*> Scene::getObjectsByClass(String className)
{
return Vector<SceneObject*>();
}
DefineEngineFunction(getScene, Scene*, (U32 sceneId), (0),
"Get the root Scene object that is loaded.\n"
"@return The id of the Root Scene. Will be 0 if no root scene is loaded")
{
if (Scene::smSceneList.empty() || sceneId >= Scene::smSceneList.size())
return nullptr;
return Scene::smSceneList[sceneId];
}
DefineEngineFunction(getRootScene, S32, (), ,
"Get the root Scene object that is loaded.\n"
"@return The id of the Root Scene. Will be 0 if no root scene is loaded")
{
Scene* root = Scene::getRootScene();
if (root)
return root->getId();
return 0;
}
DefineEngineMethod(Scene, getRootScene, S32, (),,
"Get the root Scene object that is loaded.\n"
"@return The id of the Root Scene. Will be 0 if no root scene is loaded")
{
Scene* root = Scene::getRootScene();
if (root)
return root->getId();
return 0;
}
DefineEngineMethod(Scene, addDynamicObject, void, (SceneObject* sceneObj), (nullAsType<SceneObject*>()),
"Get the root Scene object that is loaded.\n"
"@return The id of the Root Scene. Will be 0 if no root scene is loaded")
{
object->addDynamicObject(sceneObj);
}
DefineEngineMethod(Scene, removeDynamicObject, void, (SceneObject* sceneObj), (nullAsType<SceneObject*>()),
"Get the root Scene object that is loaded.\n"
"@return The id of the Root Scene. Will be 0 if no root scene is loaded")
{
object->removeDynamicObject(sceneObj);
}
DefineEngineMethod(Scene, getObjectsByClass, String, (String className), (""),
"Get the root Scene object that is loaded.\n"
"@return The id of the Root Scene. Will be 0 if no root scene is loaded")
{
if (className == String::EmptyString)
return "";
//return object->getObjectsByClass(className);
return "";
}

79
Engine/source/T3D/Scene.h Normal file
View file

@ -0,0 +1,79 @@
#pragma once
#include "console/engineAPI.h"
#ifndef _NETOBJECT_H_
#include "sim/netObject.h"
#endif
#ifndef _ITICKABLE_H_
#include "core/iTickable.h"
#endif
#include "scene/sceneObject.h"
/// Scene
/// This object is effectively a smart container to hold and manage any relevent scene objects and data
/// used to run things.
class Scene : public NetObject, public virtual ITickable
{
typedef NetObject Parent;
bool mIsSubScene;
Scene* mParentScene;
Vector<Scene*> mSubScenes;
Vector<SceneObject*> mPermanentObjects;
Vector<SceneObject*> mDynamicObjects;
S32 mSceneId;
bool mIsEditing;
bool mIsDirty;
protected:
static Scene * smRootScene;
DECLARE_CONOBJECT(Scene);
public:
Scene();
~Scene();
static void initPersistFields();
virtual bool onAdd();
virtual void onRemove();
virtual void interpolateTick(F32 delta);
virtual void processTick();
virtual void advanceTime(F32 timeDelta);
virtual void addObject(SimObject* object);
virtual void removeObject(SimObject* object);
void addDynamicObject(SceneObject* object);
void removeDynamicObject(SceneObject* object);
//
//Networking
U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
void unpackUpdate(NetConnection *conn, BitStream *stream);
//
Vector<SceneObject*> getObjectsByClass(String className);
static Scene *getRootScene()
{
if (Scene::smSceneList.empty())
return nullptr;
return Scene::smSceneList[0];
}
static Vector<Scene*> smSceneList;
};

View file

@ -34,6 +34,8 @@
#include "T3D/physics/physicsShape.h"
#include "core/util/path.h"
#include "T3D/Scene.h"
// We use this locally ( within this file ) to prevent infinite recursion
// while loading prefab files that contain other prefabs.
static Vector<String> sPrefabFileStack;
@ -269,11 +271,11 @@ void Prefab::setFile( String file )
SimGroup* Prefab::explode()
{
SimGroup *missionGroup;
Scene* scene = Scene::getRootScene();
if ( !Sim::findObject( "MissionGroup", missionGroup ) )
if ( !scene)
{
Con::errorf( "Prefab::explode, MissionGroup was not found." );
Con::errorf( "Prefab::explode, Scene was not found." );
return NULL;
}
@ -295,7 +297,7 @@ SimGroup* Prefab::explode()
smChildToPrefabMap.erase( child->getId() );
}
missionGroup->addObject(group);
scene->addObject(group);
mChildGroup = NULL;
mChildMap.clear();
@ -468,10 +470,10 @@ Prefab* Prefab::getPrefabByChild( SimObject *child )
bool Prefab::isValidChild( SimObject *simobj, bool logWarnings )
{
if ( simobj->getName() && dStricmp(simobj->getName(),"MissionGroup") == 0 )
if ( simobj->getName() && simobj == Scene::getRootScene() )
{
if ( logWarnings )
Con::warnf( "MissionGroup is not valid within a Prefab." );
Con::warnf( "root Scene is not valid within a Prefab." );
return false;
}

View file

@ -93,7 +93,7 @@ public:
void setFile( String file );
/// Removes all children from this Prefab and puts them into a SimGroup
/// which is added to the MissionGroup and returned to the caller.
/// which is added to the Scene and returned to the caller.
SimGroup* explode();
bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF& sphere);