mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-12 07:04:36 +00:00
Merge branch 'SubScenes_Gamemode_PR' of https://github.com/Areloch/Torque3D into development
This commit is contained in:
commit
81ac23fd35
60 changed files with 4200 additions and 525 deletions
|
|
@ -1,20 +1,26 @@
|
|||
#include "Scene.h"
|
||||
#include "T3D/assets/LevelAsset.h"
|
||||
#include "T3D/gameBase/gameConnection.h"
|
||||
#include "T3D/gameMode.h"
|
||||
|
||||
Scene * Scene::smRootScene = nullptr;
|
||||
Vector<Scene*> Scene::smSceneList;
|
||||
|
||||
IMPLEMENT_CALLBACK(Scene, onSaving, void, (const char* fileName), (fileName),
|
||||
"@brief Called when a scene is saved to allow scenes to special-handle prepwork for saving if required.\n\n"
|
||||
|
||||
"@param fileName The level file being saved\n");
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(Scene);
|
||||
|
||||
Scene::Scene() :
|
||||
mIsSubScene(false),
|
||||
mParentScene(nullptr),
|
||||
mSceneId(-1),
|
||||
mIsEditing(false),
|
||||
mIsDirty(false),
|
||||
mEditPostFX(0)
|
||||
{
|
||||
mGameModeName = StringTable->EmptyString();
|
||||
mGameModesNames = StringTable->EmptyString();
|
||||
}
|
||||
|
||||
Scene::~Scene()
|
||||
|
|
@ -28,13 +34,12 @@ 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");
|
||||
|
||||
addGroup("Gameplay");
|
||||
addField("gameModeName", TypeString, Offset(mGameModeName, Scene), "The name of the gamemode that this scene utilizes");
|
||||
addField("gameModes", TypeGameModeList, Offset(mGameModesNames, Scene), "The game modes that this Scene is associated with.");
|
||||
endGroup("Gameplay");
|
||||
|
||||
addGroup("PostFX");
|
||||
|
|
@ -51,48 +56,33 @@ bool Scene::onAdd()
|
|||
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);
|
||||
}*/
|
||||
GameMode::findGameModes(mGameModesNames, &mGameModesList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Scene::onRemove()
|
||||
{
|
||||
for (U32 i = 0; i < mGameModesList.size(); i++)
|
||||
{
|
||||
mGameModesList[i]->onSceneUnloaded_callback();
|
||||
}
|
||||
|
||||
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::onPostAdd()
|
||||
{
|
||||
if (isMethod("onPostAdd"))
|
||||
Con::executef(this, "onPostAdd");
|
||||
|
||||
for (U32 i = 0; i < mGameModesList.size(); i++)
|
||||
{
|
||||
mGameModesList[i]->onSceneLoaded_callback();
|
||||
}
|
||||
}
|
||||
|
||||
bool Scene::_editPostEffects(void* object, const char* index, const char* data)
|
||||
|
|
@ -110,11 +100,12 @@ bool Scene::_editPostEffects(void* object, const char* index, const char* data)
|
|||
void Scene::addObject(SimObject* object)
|
||||
{
|
||||
//Child scene
|
||||
Scene* scene = dynamic_cast<Scene*>(object);
|
||||
SubScene* scene = dynamic_cast<SubScene*>(object);
|
||||
if (scene)
|
||||
{
|
||||
//We'll keep these principly separate so they don't get saved into each other
|
||||
mSubScenes.push_back(scene);
|
||||
Parent::addObject(object);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -135,7 +126,7 @@ void Scene::addObject(SimObject* object)
|
|||
void Scene::removeObject(SimObject* object)
|
||||
{
|
||||
//Child scene
|
||||
Scene* scene = dynamic_cast<Scene*>(object);
|
||||
SubScene* scene = dynamic_cast<SubScene*>(object);
|
||||
if (scene)
|
||||
{
|
||||
//We'll keep these principly separate so they don't get saved into each other
|
||||
|
|
@ -157,30 +148,88 @@ void Scene::removeObject(SimObject* object)
|
|||
Parent::removeObject(object);
|
||||
}
|
||||
|
||||
void Scene::addDynamicObject(SceneObject* object)
|
||||
void Scene::addDynamicObject(SimObject* object)
|
||||
{
|
||||
mDynamicObjects.push_back(object);
|
||||
|
||||
SimGroup* cleanupGroup;
|
||||
if(Sim::findObject("MissionCleanup", cleanupGroup))
|
||||
{
|
||||
cleanupGroup->addObject(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);
|
||||
//Parent::addObject(object);
|
||||
}
|
||||
|
||||
void Scene::removeDynamicObject(SceneObject* object)
|
||||
void Scene::removeDynamicObject(SimObject* object)
|
||||
{
|
||||
mDynamicObjects.remove(object);
|
||||
|
||||
SimGroup* cleanupGroup;
|
||||
if (Sim::findObject("MissionCleanup", cleanupGroup))
|
||||
{
|
||||
cleanupGroup->removeObject(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);
|
||||
//Parent::removeObject(object);
|
||||
}
|
||||
|
||||
void Scene::interpolateTick(F32 delta)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Scene::processTick()
|
||||
{
|
||||
if (!isServerObject())
|
||||
return;
|
||||
|
||||
//iterate over our subscenes to update their status of loaded or unloaded based on if any control objects intersect their bounds
|
||||
for (U32 i = 0; i < mSubScenes.size(); i++)
|
||||
{
|
||||
bool hasClients = false;
|
||||
|
||||
SimGroup* pClientGroup = Sim::getClientGroup();
|
||||
for (SimGroup::iterator itr = pClientGroup->begin(); itr != pClientGroup->end(); itr++)
|
||||
{
|
||||
GameConnection* gc = dynamic_cast<GameConnection*>(*itr);
|
||||
if (gc)
|
||||
{
|
||||
GameBase* controlObj = gc->getControlObject();
|
||||
if (controlObj == nullptr)
|
||||
{
|
||||
controlObj = gc->getCameraObject();
|
||||
}
|
||||
|
||||
if (controlObj != nullptr)
|
||||
{
|
||||
if (mSubScenes[i]->testBox(controlObj->getWorldBox()))
|
||||
{
|
||||
//we have a client controlling object in the bounds, so we ensure the contents are loaded
|
||||
hasClients = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasClients)
|
||||
{
|
||||
mSubScenes[i]->setUnloadTimeMS(-1);
|
||||
mSubScenes[i]->load();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mSubScenes[i]->isLoaded() && mSubScenes[i]->getUnloadTimsMS() == -1)
|
||||
{
|
||||
mSubScenes[i]->setUnloadTimeMS(Sim::getCurrentTime());
|
||||
}
|
||||
|
||||
if (Sim::getCurrentTime() - mSubScenes[i]->getUnloadTimsMS() > 5000)
|
||||
mSubScenes[i]->unload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::advanceTime(F32 timeDelta)
|
||||
|
|
@ -205,7 +254,7 @@ void Scene::dumpUtilizedAssets()
|
|||
Con::printf("Dumping utilized assets in scene!");
|
||||
|
||||
Vector<StringTableEntry> utilizedAssetsList;
|
||||
for (U32 i = 0; i < mPermanentObjects.size(); i++)
|
||||
/*for (U32 i = 0; i < mPermanentObjects.size(); i++)
|
||||
{
|
||||
mPermanentObjects[i]->getUtilizedAssets(&utilizedAssetsList);
|
||||
}
|
||||
|
|
@ -213,7 +262,7 @@ void Scene::dumpUtilizedAssets()
|
|||
for (U32 i = 0; i < mDynamicObjects.size(); i++)
|
||||
{
|
||||
mDynamicObjects[i]->getUtilizedAssets(&utilizedAssetsList);
|
||||
}
|
||||
}*/
|
||||
|
||||
for (U32 i = 0; i < utilizedAssetsList.size(); i++)
|
||||
{
|
||||
|
|
@ -247,6 +296,9 @@ StringTableEntry Scene::getLevelAsset()
|
|||
|
||||
bool Scene::saveScene(StringTableEntry fileName)
|
||||
{
|
||||
if (!isServerObject())
|
||||
return false;
|
||||
|
||||
//So, we ultimately want to not only save out the level, but also collate all the assets utilized
|
||||
//by the static objects in the scene so we can have those before we parse the level file itself
|
||||
//Useful for preloading or stat tracking
|
||||
|
|
@ -257,6 +309,21 @@ bool Scene::saveScene(StringTableEntry fileName)
|
|||
fileName = getOriginatingFile();
|
||||
}
|
||||
|
||||
for (SimGroupIterator itr(this); *itr; ++itr)
|
||||
{
|
||||
if((*itr)->isMethod("onSaving"))
|
||||
{
|
||||
Con::executef((*itr), "onSaving", fileName);
|
||||
}
|
||||
}
|
||||
|
||||
//Inform our subscenes we're saving so they can do any
|
||||
//special work required as well
|
||||
for (U32 i = 0; i < mSubScenes.size(); i++)
|
||||
{
|
||||
mSubScenes[i]->save();
|
||||
}
|
||||
|
||||
bool saveSuccess = save(fileName);
|
||||
|
||||
if (!saveSuccess)
|
||||
|
|
@ -286,9 +353,12 @@ bool Scene::saveScene(StringTableEntry fileName)
|
|||
dSprintf(depValue, sizeof(depValue), "%s=%s", ASSET_ID_SIGNATURE, utilizedAssetsList[i]);
|
||||
|
||||
levelAssetDef->setDataField(StringTable->insert(depSlotName), NULL, StringTable->insert(depValue));
|
||||
|
||||
}
|
||||
|
||||
//update the gamemode list as well
|
||||
levelAssetDef->setDataField(StringTable->insert("gameModesNames"), NULL, StringTable->insert(mGameModesNames));
|
||||
|
||||
//Finally, save
|
||||
saveSuccess = levelAssetDef->saveAsset();
|
||||
|
||||
return saveSuccess;
|
||||
|
|
@ -314,11 +384,26 @@ void Scene::getUtilizedAssetsFromSceneObject(SimObject* object, Vector<StringTab
|
|||
}
|
||||
|
||||
//
|
||||
Vector<SceneObject*> Scene::getObjectsByClass(String className, bool checkSubscenes)
|
||||
Vector<SceneObject*> Scene::getObjectsByClass(String className)
|
||||
{
|
||||
return Vector<SceneObject*>();
|
||||
}
|
||||
|
||||
void Scene::loadAtPosition(const Point3F& position)
|
||||
{
|
||||
for (U32 i = 0; i < mSubScenes.size(); i++)
|
||||
{
|
||||
Box3F testBox = Box3F(0.5);
|
||||
testBox.setCenter(position);
|
||||
|
||||
if (mSubScenes[i]->testBox(testBox))
|
||||
{
|
||||
mSubScenes[i]->setUnloadTimeMS(-1);
|
||||
mSubScenes[i]->load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
|
|
@ -413,9 +498,13 @@ DefineEngineMethod(Scene, getLevelAsset, const char*, (), ,
|
|||
DefineEngineMethod(Scene, save, bool, (const char* fileName), (""),
|
||||
"Save out the object to the given file.\n"
|
||||
"@param fileName The name of the file to save to."
|
||||
"@param selectedOnly If true, only objects marked as selected will be saved out.\n"
|
||||
"@param preAppendString Text which will be preprended directly to the object serialization.\n"
|
||||
"@param True on success, false on failure.")
|
||||
{
|
||||
return object->saveScene(StringTable->insert(fileName));
|
||||
}
|
||||
|
||||
DefineEngineMethod(Scene, loadAtPosition, void, (Point3F position), (Point3F::Zero),
|
||||
"Loads any subscenes at a given point by force.\n")
|
||||
{
|
||||
object->loadAtPosition(position);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef SCENE_H
|
||||
#include "console/engineAPI.h"
|
||||
|
||||
#ifndef _NETOBJECT_H_
|
||||
|
|
@ -9,8 +9,16 @@
|
|||
#ifndef _ITICKABLE_H_
|
||||
#include "core/iTickable.h"
|
||||
#endif
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "scene/sceneObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef GAME_MODE_H
|
||||
#include "gameMode.h"
|
||||
#endif
|
||||
#ifndef SUB_SCENE_H
|
||||
#include "SubScene.h"
|
||||
#endif
|
||||
|
||||
/// Scene
|
||||
/// This object is effectively a smart container to hold and manage any relevent scene objects and data
|
||||
|
|
@ -19,15 +27,12 @@ class Scene : public NetObject, public virtual ITickable
|
|||
{
|
||||
typedef NetObject Parent;
|
||||
|
||||
bool mIsSubScene;
|
||||
|
||||
Scene* mParentScene;
|
||||
|
||||
Vector<Scene*> mSubScenes;
|
||||
Vector<SubScene*> mSubScenes;
|
||||
|
||||
Vector<SceneObject*> mPermanentObjects;
|
||||
|
||||
Vector<SceneObject*> mDynamicObjects;
|
||||
Vector<SimObject*> mPermanentObjects;
|
||||
Vector<SimObject*> mDynamicObjects;
|
||||
|
||||
S32 mSceneId;
|
||||
|
||||
|
|
@ -37,7 +42,8 @@ class Scene : public NetObject, public virtual ITickable
|
|||
|
||||
bool mEditPostFX;
|
||||
|
||||
StringTableEntry mGameModeName;
|
||||
StringTableEntry mGameModesNames;
|
||||
Vector<GameMode*> mGameModesList;
|
||||
|
||||
protected:
|
||||
static Scene * smRootScene;
|
||||
|
|
@ -63,8 +69,8 @@ public:
|
|||
void addObject(SimObject* object) override;
|
||||
void removeObject(SimObject* object) override;
|
||||
|
||||
void addDynamicObject(SceneObject* object);
|
||||
void removeDynamicObject(SceneObject* object);
|
||||
void addDynamicObject(SimObject* object);
|
||||
void removeDynamicObject(SimObject* object);
|
||||
void clearDynamicObjects() { mDynamicObjects.clear(); }
|
||||
|
||||
void dumpUtilizedAssets();
|
||||
|
|
@ -80,12 +86,14 @@ public:
|
|||
void unpackUpdate(NetConnection *conn, BitStream *stream) override;
|
||||
|
||||
//
|
||||
Vector<SceneObject*> getObjectsByClass(String className, bool checkSubscenes);
|
||||
Vector<SceneObject*> getObjectsByClass(String className);
|
||||
|
||||
void getUtilizedAssetsFromSceneObject(SimObject* object, Vector<StringTableEntry>* usedAssetsList);
|
||||
|
||||
template <class T>
|
||||
Vector<T*> getObjectsByClass(bool checkSubscenes);
|
||||
Vector<T*> getObjectsByClass();
|
||||
|
||||
void loadAtPosition(const Point3F& position);
|
||||
|
||||
static Scene *getRootScene()
|
||||
{
|
||||
|
|
@ -96,11 +104,13 @@ public:
|
|||
}
|
||||
|
||||
static Vector<Scene*> smSceneList;
|
||||
|
||||
DECLARE_CALLBACK(void, onSaving, (const char* fileName));
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
Vector<T*> Scene::getObjectsByClass(bool checkSubscenes)
|
||||
Vector<T*> Scene::getObjectsByClass()
|
||||
{
|
||||
Vector<T*> foundObjects;
|
||||
|
||||
|
|
@ -121,18 +131,6 @@ Vector<T*> Scene::getObjectsByClass(bool checkSubscenes)
|
|||
foundObjects.push_back(curObject);
|
||||
}
|
||||
|
||||
if (checkSubscenes)
|
||||
{
|
||||
for (U32 i = 0; i < mSubScenes.size(); i++)
|
||||
{
|
||||
Vector<T*> appendList = mSubScenes[i]->getObjectsByClass<T>(true);
|
||||
|
||||
for (U32 a = 0; a < appendList.size(); a++)
|
||||
{
|
||||
foundObjects.push_back(appendList[a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return foundObjects;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
362
Engine/source/T3D/SceneGroup.cpp
Normal file
362
Engine/source/T3D/SceneGroup.cpp
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
#include "SceneGroup.h"
|
||||
|
||||
#include "gameBase/gameConnection.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "gui/editor/inspector/group.h"
|
||||
#include "gui/worldEditor/editor.h"
|
||||
#include "math/mathIO.h"
|
||||
#include "physics/physicsShape.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(SceneGroup);
|
||||
|
||||
ConsoleDocClass(SceneGroup,
|
||||
"@brief A collection of arbitrary objects which can be allocated and manipulated as a group.\n\n"
|
||||
|
||||
"%SceneGroup always points to a (.SceneGroup) file which defines its objects. In "
|
||||
"fact more than one %SceneGroup can reference this file and both will update "
|
||||
"if the file is modified.\n\n"
|
||||
|
||||
"%SceneGroup is a very simple object and only exists on the server. When it is "
|
||||
"created it allocates children objects by reading the (.SceneGroup) file like "
|
||||
"a list of instructions. It then sets their transform relative to the %SceneGroup "
|
||||
"and Torque networking handles the rest by ghosting the new objects to clients. "
|
||||
"%SceneGroup itself is not ghosted.\n\n"
|
||||
|
||||
"@ingroup enviroMisc"
|
||||
);
|
||||
|
||||
SceneGroup::SceneGroup()
|
||||
{
|
||||
// Not ghosted unless we're editing
|
||||
mNetFlags.clear(Ghostable | ScopeAlways);
|
||||
|
||||
mTypeMask |= StaticObjectType;
|
||||
}
|
||||
|
||||
SceneGroup::~SceneGroup()
|
||||
{
|
||||
}
|
||||
|
||||
void SceneGroup::initPersistFields()
|
||||
{
|
||||
docsURL;
|
||||
|
||||
addGroup("SceneGroup");
|
||||
endGroup("SceneGroup");
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
bool SceneGroup::onAdd()
|
||||
{
|
||||
if (!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
mObjBox.set(Point3F(-0.5f, -0.5f, -0.5f),
|
||||
Point3F(0.5f, 0.5f, 0.5f));
|
||||
|
||||
resetWorldBox();
|
||||
|
||||
// Not added to the scene unless we are editing.
|
||||
if (gEditingMission)
|
||||
onEditorEnable();
|
||||
|
||||
addToScene();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SceneGroup::onRemove()
|
||||
{
|
||||
removeFromScene();
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
void SceneGroup::onEditorEnable()
|
||||
{
|
||||
if (isClientObject())
|
||||
return;
|
||||
|
||||
// Just in case we are already in the scene, lets not cause an assert.
|
||||
if (mContainer != NULL)
|
||||
return;
|
||||
|
||||
// Enable ghosting so we can see this on the client.
|
||||
mNetFlags.set(Ghostable);
|
||||
setScopeAlways();
|
||||
addToScene();
|
||||
|
||||
Parent::onEditorEnable();
|
||||
}
|
||||
|
||||
void SceneGroup::onEditorDisable()
|
||||
{
|
||||
if (isClientObject())
|
||||
return;
|
||||
|
||||
// Just in case we are not in the scene, lets not cause an assert.
|
||||
if (mContainer == NULL)
|
||||
return;
|
||||
|
||||
// Do not need this on the client if we are not editing.
|
||||
removeFromScene();
|
||||
mNetFlags.clear(Ghostable);
|
||||
clearScopeAlways();
|
||||
|
||||
Parent::onEditorDisable();
|
||||
}
|
||||
|
||||
void SceneGroup::inspectPostApply()
|
||||
{
|
||||
Parent::inspectPostApply();
|
||||
}
|
||||
|
||||
void SceneGroup::onInspect(GuiInspector* inspector)
|
||||
{
|
||||
Parent::onInspect(inspector);
|
||||
|
||||
//Put the SubScene group before everything that'd be SubScene-effecting, for orginazational purposes
|
||||
GuiInspectorGroup* sceneGroupGrp = inspector->findExistentGroup(StringTable->insert("Editing"));
|
||||
if (!sceneGroupGrp)
|
||||
return;
|
||||
|
||||
GuiControl* stack = dynamic_cast<GuiControl*>(sceneGroupGrp->findObjectByInternalName(StringTable->insert("Stack")));
|
||||
|
||||
//Regen bounds button
|
||||
GuiInspectorField* regenFieldGui = sceneGroupGrp->createInspectorField();
|
||||
regenFieldGui->init(inspector, sceneGroupGrp);
|
||||
|
||||
regenFieldGui->setSpecialEditField(true);
|
||||
regenFieldGui->setTargetObject(this);
|
||||
|
||||
StringTableEntry fldnm = StringTable->insert("RegenerateBounds");
|
||||
|
||||
regenFieldGui->setSpecialEditVariableName(fldnm);
|
||||
|
||||
regenFieldGui->setInspectorField(NULL, fldnm);
|
||||
regenFieldGui->setDocs("");
|
||||
|
||||
stack->addObject(regenFieldGui);
|
||||
|
||||
GuiButtonCtrl* regenButton = new GuiButtonCtrl();
|
||||
regenButton->registerObject();
|
||||
regenButton->setDataField(StringTable->insert("profile"), NULL, "ToolsGuiButtonProfile");
|
||||
regenButton->setText("Regenerate Bounds");
|
||||
regenButton->resize(Point2I::Zero, regenFieldGui->getExtent());
|
||||
regenButton->setHorizSizing(GuiControl::horizResizeWidth);
|
||||
regenButton->setVertSizing(GuiControl::vertResizeHeight);
|
||||
|
||||
char rgBuffer[512];
|
||||
dSprintf(rgBuffer, 512, "%d.recalculateBounds();", this->getId());
|
||||
regenButton->setConsoleCommand(rgBuffer);
|
||||
|
||||
regenFieldGui->addObject(regenButton);
|
||||
}
|
||||
|
||||
void SceneGroup::setTransform(const MatrixF& mat)
|
||||
{
|
||||
if (isServerObject())
|
||||
{
|
||||
setMaskBits(TransformMask);
|
||||
|
||||
MatrixF newXform = mat;
|
||||
MatrixF oldXform = getTransform();
|
||||
oldXform.affineInverse();
|
||||
|
||||
MatrixF offset;
|
||||
offset.mul(newXform, oldXform);
|
||||
|
||||
// Update all child transforms
|
||||
for (SimSetIterator itr(this); *itr; ++itr)
|
||||
{
|
||||
SceneObject* child = dynamic_cast<SceneObject*>(*itr);
|
||||
if (child)
|
||||
{
|
||||
MatrixF childMat;
|
||||
|
||||
//add the "offset" caused by the parents change, and add it to it's own
|
||||
// This is needed by objects that update their own render transform thru interpolate tick
|
||||
// Mostly for stationary objects.
|
||||
childMat.mul(offset, child->getTransform());
|
||||
child->setTransform(childMat);
|
||||
|
||||
PhysicsShape* childPS = dynamic_cast<PhysicsShape*>(child);
|
||||
if (childPS)
|
||||
childPS->storeRestorePos();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Parent::setTransform(mat);
|
||||
}
|
||||
|
||||
void SceneGroup::setRenderTransform(const MatrixF& mat)
|
||||
{
|
||||
MatrixF newXform = mat;
|
||||
MatrixF oldXform = getRenderTransform();
|
||||
oldXform.affineInverse();
|
||||
|
||||
MatrixF offset;
|
||||
offset.mul(newXform, oldXform);
|
||||
|
||||
// Update all child transforms
|
||||
for (SimSetIterator itr(this); *itr; ++itr)
|
||||
{
|
||||
SceneObject* child = dynamic_cast<SceneObject*>(*itr);
|
||||
if (child)
|
||||
{
|
||||
MatrixF childMat;
|
||||
|
||||
//add the "offset" caused by the parents change, and add it to it's own
|
||||
// This is needed by objects that update their own render transform thru interpolate tick
|
||||
// Mostly for stationary objects.
|
||||
childMat.mul(offset, child->getRenderTransform());
|
||||
child->setRenderTransform(childMat);
|
||||
|
||||
PhysicsShape* childPS = dynamic_cast<PhysicsShape*>(child);
|
||||
if (childPS)
|
||||
childPS->storeRestorePos();
|
||||
}
|
||||
}
|
||||
|
||||
Parent::setRenderTransform(mat);
|
||||
}
|
||||
|
||||
void SceneGroup::addObject(SimObject* object)
|
||||
{
|
||||
Parent::addObject(object);
|
||||
|
||||
// Recalculate the bounding box from scratch (simpler but potentially costly)
|
||||
recalculateBoundingBox();
|
||||
}
|
||||
|
||||
void SceneGroup::removeObject(SimObject* object)
|
||||
{
|
||||
Parent::removeObject(object);
|
||||
|
||||
// Recalculate the bounding box from scratch (simpler but potentially costly)
|
||||
recalculateBoundingBox();
|
||||
}
|
||||
|
||||
void SceneGroup::recalculateBoundingBox()
|
||||
{
|
||||
if (empty())
|
||||
return;
|
||||
|
||||
// Reset the bounding box
|
||||
Box3F bounds;
|
||||
|
||||
bounds.minExtents.set(1e10, 1e10, 1e10);
|
||||
bounds.maxExtents.set(-1e10, -1e10, -1e10);
|
||||
|
||||
// Extend the bounding box to include each child's bounding box
|
||||
for (SimSetIterator itr(this); *itr; ++itr)
|
||||
{
|
||||
SceneObject* child = dynamic_cast<SceneObject*>(*itr);
|
||||
if (child)
|
||||
{
|
||||
const Box3F& childBox = child->getWorldBox();
|
||||
|
||||
bounds.minExtents.setMin(childBox.minExtents);
|
||||
bounds.maxExtents.setMax(childBox.maxExtents);
|
||||
}
|
||||
}
|
||||
|
||||
MatrixF newTrans = mObjToWorld;
|
||||
newTrans.setPosition(bounds.getCenter());
|
||||
Parent::setTransform(newTrans);
|
||||
|
||||
mObjScale = Point3F(bounds.len_x(), bounds.len_y(), bounds.len_z());
|
||||
mWorldBox = bounds;
|
||||
resetObjectBox();
|
||||
|
||||
setMaskBits(TransformMask);
|
||||
}
|
||||
|
||||
U32 SceneGroup::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
|
||||
{
|
||||
U32 retMask = Parent::packUpdate(conn, mask, stream);
|
||||
|
||||
mathWrite(*stream, mObjBox);
|
||||
|
||||
if (stream->writeFlag(mask & TransformMask))
|
||||
{
|
||||
mathWrite(*stream, getTransform());
|
||||
mathWrite(*stream, getScale());
|
||||
}
|
||||
|
||||
return retMask;
|
||||
}
|
||||
|
||||
void SceneGroup::unpackUpdate(NetConnection* conn, BitStream* stream)
|
||||
{
|
||||
Parent::unpackUpdate(conn, stream);
|
||||
|
||||
mathRead(*stream, &mObjBox);
|
||||
resetWorldBox();
|
||||
|
||||
// TransformMask
|
||||
if (stream->readFlag())
|
||||
{
|
||||
mathRead(*stream, &mObjToWorld);
|
||||
mathRead(*stream, &mObjScale);
|
||||
|
||||
setTransform(mObjToWorld);
|
||||
}
|
||||
}
|
||||
|
||||
bool SceneGroup::buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& sphere)
|
||||
{
|
||||
Vector<SceneObject*> foundObjects;
|
||||
if (empty())
|
||||
{
|
||||
Con::warnf("SceneGroup::buildPolyList() - SceneGroup %s is empty!", getName());
|
||||
return false;
|
||||
}
|
||||
findObjectByType(foundObjects);
|
||||
|
||||
for (S32 i = 0; i < foundObjects.size(); i++)
|
||||
{
|
||||
foundObjects[i]->buildPolyList(context, polyList, box, sphere);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SceneGroup::buildExportPolyList(ColladaUtils::ExportData* exportData, const Box3F& box, const SphereF& sphere)
|
||||
{
|
||||
Vector<SceneObject*> foundObjects;
|
||||
findObjectByType(foundObjects);
|
||||
|
||||
for (S32 i = 0; i < foundObjects.size(); i++)
|
||||
{
|
||||
foundObjects[i]->buildExportPolyList(exportData, box, sphere);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SceneGroup::getUtilizedAssets(Vector<StringTableEntry>* usedAssetsList)
|
||||
{
|
||||
//if (empty())
|
||||
return;
|
||||
|
||||
Vector<SceneObject*> foundObjects;
|
||||
findObjectByType(foundObjects);
|
||||
|
||||
for (S32 i = 0; i < foundObjects.size(); i++)
|
||||
{
|
||||
SceneObject* child = foundObjects[i];
|
||||
|
||||
child->getUtilizedAssets(usedAssetsList);
|
||||
}
|
||||
}
|
||||
|
||||
DefineEngineMethod(SceneGroup, recalculateBounds, void, (), ,
|
||||
"Recalculates the SceneGroups' bounds and centerpoint.\n")
|
||||
{
|
||||
object->recalculateBoundingBox();
|
||||
}
|
||||
55
Engine/source/T3D/SceneGroup.h
Normal file
55
Engine/source/T3D/SceneGroup.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
#ifndef SCENE_GROUP_H
|
||||
#define SCENE_GROUP_H
|
||||
|
||||
#ifndef _SCENEOBJECT_H_
|
||||
#include "scene/sceneObject.h"
|
||||
#endif
|
||||
|
||||
class SceneGroup : public SceneObject
|
||||
{
|
||||
typedef SceneObject Parent;
|
||||
|
||||
public:
|
||||
enum MaskBits
|
||||
{
|
||||
TransformMask = Parent::NextFreeMask << 0,
|
||||
NextFreeMask = Parent::NextFreeMask << 1
|
||||
};
|
||||
|
||||
public:
|
||||
SceneGroup();
|
||||
virtual ~SceneGroup();
|
||||
|
||||
DECLARE_CONOBJECT(SceneGroup);
|
||||
DECLARE_CATEGORY("Object \t Collection");
|
||||
|
||||
static void initPersistFields();
|
||||
|
||||
// SimObject
|
||||
bool onAdd() override;
|
||||
void onRemove() override;
|
||||
void onEditorEnable() override;
|
||||
void onEditorDisable() override;
|
||||
void inspectPostApply() override;
|
||||
void onInspect(GuiInspector* inspector) override;
|
||||
|
||||
// NetObject
|
||||
U32 packUpdate(NetConnection* conn, U32 mask, BitStream* stream) override;
|
||||
void unpackUpdate(NetConnection* conn, BitStream* stream) override;
|
||||
|
||||
// SceneObject
|
||||
void setTransform(const MatrixF& mat) override;
|
||||
void setRenderTransform(const MatrixF& mat) override;
|
||||
|
||||
// Object management
|
||||
void addObject(SimObject* object) override;
|
||||
void removeObject(SimObject* object) override;
|
||||
void recalculateBoundingBox();
|
||||
|
||||
///
|
||||
bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& sphere) override;
|
||||
bool buildExportPolyList(ColladaUtils::ExportData* exportData, const Box3F& box, const SphereF&) override;
|
||||
void getUtilizedAssets(Vector<StringTableEntry>* usedAssetsList) override;
|
||||
};
|
||||
#endif
|
||||
556
Engine/source/T3D/SubScene.cpp
Normal file
556
Engine/source/T3D/SubScene.cpp
Normal file
|
|
@ -0,0 +1,556 @@
|
|||
#include "SubScene.h"
|
||||
|
||||
#include "gameMode.h"
|
||||
#include "console/persistenceManager.h"
|
||||
#include "console/script.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "renderInstance/renderPassManager.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "gui/editor/inspector/group.h"
|
||||
#include "T3D/gameBase/gameBase.h"
|
||||
|
||||
bool SubScene::smTransformChildren = false;
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(SubScene);
|
||||
|
||||
S32 SubScene::mUnloadTimeoutMs = 5000;
|
||||
|
||||
IMPLEMENT_CALLBACK(SubScene, onLoaded, void, (), (),
|
||||
"@brief Called when a subScene has been loaded and has game mode implications.\n\n");
|
||||
IMPLEMENT_CALLBACK(SubScene, onUnloaded, void, (), (),
|
||||
"@brief Called when a subScene has been unloaded and has game mode implications.\n\n");
|
||||
|
||||
SubScene::SubScene() :
|
||||
mLevelAssetId(StringTable->EmptyString()),
|
||||
mGameModesNames(StringTable->EmptyString()),
|
||||
mScopeDistance(-1),
|
||||
mLoaded(false),
|
||||
mFreezeLoading(false),
|
||||
mTickPeriodMS(1000),
|
||||
mCurrTick(0),
|
||||
mGlobalLayer(false)
|
||||
{
|
||||
mNetFlags.set(Ghostable | ScopeAlways);
|
||||
|
||||
mTypeMask |= StaticObjectType;
|
||||
}
|
||||
|
||||
SubScene::~SubScene()
|
||||
{
|
||||
}
|
||||
|
||||
bool SubScene::onAdd()
|
||||
{
|
||||
if (!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
setProcessTick(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SubScene::onRemove()
|
||||
{
|
||||
if (isClientObject())
|
||||
removeFromScene();
|
||||
|
||||
unload();
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
void SubScene::initPersistFields()
|
||||
{
|
||||
addGroup("SubScene");
|
||||
addField("isGlobalLayer", TypeBool, Offset(mGlobalLayer, SubScene), "");
|
||||
INITPERSISTFIELD_LEVELASSET(Level, SubScene, "The level asset to load.");
|
||||
addField("gameModes", TypeGameModeList, Offset(mGameModesNames, SubScene), "The game modes that this subscene is associated with.");
|
||||
endGroup("SubScene");
|
||||
|
||||
addGroup("LoadingManagement");
|
||||
addField("freezeLoading", TypeBool, Offset(mFreezeLoading, SubScene), "If true, will prevent the zone from being changed from it's current loading state.");
|
||||
addField("loadIf", TypeCommand, Offset(mLoadIf, SubScene), "evaluation condition (true/false)");
|
||||
|
||||
addField("tickPeriodMS", TypeS32, Offset(mTickPeriodMS, SubScene), "evaluation rate (ms)");
|
||||
|
||||
addField("onLoadCommand", TypeCommand, Offset(mOnLoadCommand, SubScene), "The command to execute when the subscene is loaded. Maximum 1023 characters.");
|
||||
addField("onUnloadCommand", TypeCommand, Offset(mOnUnloadCommand, SubScene), "The command to execute when subscene is unloaded. Maximum 1023 characters.");
|
||||
endGroup("LoadingManagement");
|
||||
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
void SubScene::consoleInit()
|
||||
{
|
||||
Parent::consoleInit();
|
||||
|
||||
Con::addVariable("$SubScene::UnloadTimeoutMS", TypeBool, &SubScene::mUnloadTimeoutMs, "The amount of time in milliseconds it takes for a SubScene to be unloaded if it's inactive.\n"
|
||||
"@ingroup Editors\n");
|
||||
|
||||
Con::addVariable("$SubScene::transformChildren", TypeBool, &SubScene::smTransformChildren,
|
||||
"@brief If true, then transform manipulations modify child objects. If false, only triggering bounds is manipulated\n\n"
|
||||
"@ingroup Editors");
|
||||
}
|
||||
|
||||
void SubScene::addObject(SimObject* object)
|
||||
{
|
||||
SceneObject::addObject(object);
|
||||
}
|
||||
|
||||
void SubScene::removeObject(SimObject* object)
|
||||
{
|
||||
SceneObject::removeObject(object);
|
||||
}
|
||||
|
||||
U32 SubScene::packUpdate(NetConnection* conn, U32 mask, BitStream* stream)
|
||||
{
|
||||
U32 retMask = Parent::packUpdate(conn, mask, stream);
|
||||
|
||||
stream->writeFlag(mGlobalLayer);
|
||||
|
||||
return retMask;
|
||||
}
|
||||
|
||||
void SubScene::unpackUpdate(NetConnection* conn, BitStream* stream)
|
||||
{
|
||||
Parent::unpackUpdate(conn, stream);
|
||||
|
||||
mGlobalLayer = stream->readFlag();
|
||||
|
||||
}
|
||||
|
||||
void SubScene::onInspect(GuiInspector* inspector)
|
||||
{
|
||||
Parent::onInspect(inspector);
|
||||
|
||||
//Put the SubScene group before everything that'd be SubScene-effecting, for orginazational purposes
|
||||
GuiInspectorGroup* subsceneGrp = inspector->findExistentGroup(StringTable->insert("SubScene"));
|
||||
if (!subsceneGrp)
|
||||
return;
|
||||
|
||||
GuiControl* stack = dynamic_cast<GuiControl*>(subsceneGrp->findObjectByInternalName(StringTable->insert("Stack")));
|
||||
|
||||
//Save button
|
||||
GuiInspectorField* saveFieldGui = subsceneGrp->createInspectorField();
|
||||
saveFieldGui->init(inspector, subsceneGrp);
|
||||
|
||||
saveFieldGui->setSpecialEditField(true);
|
||||
saveFieldGui->setTargetObject(this);
|
||||
|
||||
StringTableEntry fldnm = StringTable->insert("SaveSubScene");
|
||||
|
||||
saveFieldGui->setSpecialEditVariableName(fldnm);
|
||||
|
||||
saveFieldGui->setInspectorField(NULL, fldnm);
|
||||
saveFieldGui->setDocs("");
|
||||
|
||||
stack->addObject(saveFieldGui);
|
||||
|
||||
GuiButtonCtrl* saveButton = new GuiButtonCtrl();
|
||||
saveButton->registerObject();
|
||||
saveButton->setDataField(StringTable->insert("profile"), NULL, "ToolsGuiButtonProfile");
|
||||
saveButton->setText("Save SubScene");
|
||||
saveButton->resize(Point2I::Zero, saveFieldGui->getExtent());
|
||||
saveButton->setHorizSizing(GuiControl::horizResizeWidth);
|
||||
saveButton->setVertSizing(GuiControl::vertResizeHeight);
|
||||
|
||||
char szBuffer[512];
|
||||
dSprintf(szBuffer, 512, "%d.save();", this->getId());
|
||||
saveButton->setConsoleCommand(szBuffer);
|
||||
|
||||
saveFieldGui->addObject(saveButton);
|
||||
}
|
||||
|
||||
void SubScene::inspectPostApply()
|
||||
{
|
||||
Parent::inspectPostApply();
|
||||
setMaskBits(-1);
|
||||
}
|
||||
|
||||
void SubScene::setTransform(const MatrixF& mat)
|
||||
{
|
||||
if(SubScene::smTransformChildren)
|
||||
{
|
||||
Parent::setTransform(mat);
|
||||
}
|
||||
else
|
||||
{
|
||||
SceneObject::setTransform(mat);
|
||||
}
|
||||
}
|
||||
|
||||
void SubScene::setRenderTransform(const MatrixF& mat)
|
||||
{
|
||||
if (SubScene::smTransformChildren)
|
||||
{
|
||||
Parent::setRenderTransform(mat);
|
||||
}
|
||||
else
|
||||
{
|
||||
SceneObject::setRenderTransform(mat);
|
||||
}
|
||||
}
|
||||
|
||||
bool SubScene::evaluateCondition()
|
||||
{
|
||||
if (!mLoadIf.isEmpty())
|
||||
{
|
||||
//test the mapper plugged in condition line
|
||||
String resVar = getIdString() + String(".result");
|
||||
Con::setBoolVariable(resVar.c_str(), false);
|
||||
String command = resVar + "=" + mLoadIf + ";";
|
||||
|
||||
Con::evaluatef(command.c_str());
|
||||
return Con::getBoolVariable(resVar.c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SubScene::testBox(const Box3F& testBox)
|
||||
{
|
||||
if (mGlobalLayer)
|
||||
return true;
|
||||
|
||||
bool passes = getWorldBox().isOverlapped(testBox);
|
||||
if (passes)
|
||||
passes = evaluateCondition();
|
||||
return passes;
|
||||
}
|
||||
|
||||
void SubScene::write(Stream& stream, U32 tabStop, U32 flags)
|
||||
{
|
||||
MutexHandle handle;
|
||||
handle.lock(mMutex);
|
||||
|
||||
// export selected only?
|
||||
if ((flags & SelectedOnly) && !isSelected())
|
||||
{
|
||||
for (U32 i = 0; i < size(); i++)
|
||||
(*this)[i]->write(stream, tabStop, flags);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
stream.writeTabs(tabStop);
|
||||
char buffer[2048];
|
||||
const U32 bufferWriteLen = dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() && !(flags & NoName) ? getName() : "");
|
||||
stream.write(bufferWriteLen, buffer);
|
||||
writeFields(stream, tabStop + 1);
|
||||
|
||||
//The only meaningful difference between this and simSet for writing is we skip the children, since they're just the levelAsset contents
|
||||
|
||||
stream.writeTabs(tabStop);
|
||||
stream.write(4, "};\r\n");
|
||||
}
|
||||
|
||||
void SubScene::processTick(const Move* move)
|
||||
{
|
||||
mCurrTick += TickMs;
|
||||
if (mCurrTick > mTickPeriodMS)
|
||||
{
|
||||
mCurrTick = 0;
|
||||
//re-evaluate
|
||||
if (!evaluateCondition())
|
||||
unload();
|
||||
}
|
||||
}
|
||||
|
||||
void SubScene::_onFileChanged(const Torque::Path& path)
|
||||
{
|
||||
if(mLevelAsset.isNull() || Torque::Path(mLevelAsset->getLevelPath()) != path)
|
||||
return;
|
||||
|
||||
AssertFatal(path == mLevelAsset->getLevelPath(), "Prefab::_onFileChanged - path does not match filename.");
|
||||
|
||||
_closeFile(false);
|
||||
_loadFile(false);
|
||||
setMaskBits(U32_MAX);
|
||||
}
|
||||
|
||||
void SubScene::_removeContents(SimGroupIterator set)
|
||||
{
|
||||
for (SimGroupIterator itr(set); *itr; ++itr)
|
||||
{
|
||||
|
||||
SimGroup* child = dynamic_cast<SimGroup*>(*itr);
|
||||
if (child)
|
||||
{
|
||||
_removeContents(SimGroupIterator(child));
|
||||
|
||||
GameBase* asGameBase = dynamic_cast<GameBase*>(child);
|
||||
if (asGameBase)
|
||||
{
|
||||
asGameBase->scriptOnRemove();
|
||||
}
|
||||
|
||||
Sim::cancelPendingEvents(child);
|
||||
|
||||
child->safeDeleteObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SubScene::_closeFile(bool removeFileNotify)
|
||||
{
|
||||
AssertFatal(isServerObject(), "Trying to close out a subscene file on the client is bad!");
|
||||
|
||||
_removeContents(SimGroupIterator(this));
|
||||
|
||||
if (removeFileNotify && mLevelAsset.notNull() && mLevelAsset->getLevelPath() != StringTable->EmptyString())
|
||||
{
|
||||
Torque::FS::RemoveChangeNotification(mLevelAsset->getLevelPath(), this, &SubScene::_onFileChanged);
|
||||
}
|
||||
|
||||
mGameModesList.clear();
|
||||
}
|
||||
|
||||
void SubScene::_loadFile(bool addFileNotify)
|
||||
{
|
||||
AssertFatal(isServerObject(), "Trying to load a SubScene file on the client is bad!");
|
||||
|
||||
if(mLevelAsset.isNull() || mLevelAsset->getLevelPath() == StringTable->EmptyString())
|
||||
return;
|
||||
|
||||
String evalCmd = String::ToString("exec(\"%s\");", mLevelAsset->getLevelPath());
|
||||
|
||||
String instantGroup = Con::getVariable("InstantGroup");
|
||||
Con::setIntVariable("InstantGroup", this->getId());
|
||||
Con::evaluate((const char*)evalCmd.c_str(), false, mLevelAsset->getLevelPath());
|
||||
Con::setVariable("InstantGroup", instantGroup.c_str());
|
||||
|
||||
if (addFileNotify)
|
||||
Torque::FS::AddChangeNotification(mLevelAsset->getLevelPath(), this, &SubScene::_onFileChanged);
|
||||
}
|
||||
|
||||
void SubScene::load()
|
||||
{
|
||||
mStartUnloadTimerMS = -1; //reset unload timers
|
||||
|
||||
//no need to load multiple times
|
||||
if (mLoaded)
|
||||
return;
|
||||
|
||||
if (mFreezeLoading)
|
||||
return;
|
||||
|
||||
_loadFile(true);
|
||||
mLoaded = true;
|
||||
|
||||
GameMode::findGameModes(mGameModesNames, &mGameModesList);
|
||||
|
||||
onLoaded_callback();
|
||||
for (U32 i = 0; i < mGameModesList.size(); i++)
|
||||
{
|
||||
mGameModesList[i]->onSubsceneLoaded_callback(this);
|
||||
}
|
||||
|
||||
if (!mOnLoadCommand.isEmpty())
|
||||
{
|
||||
String command = "%this = " + String(getIdString()) + "; " + mLoadIf + ";";
|
||||
Con::evaluatef(command.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void SubScene::unload()
|
||||
{
|
||||
if (!mLoaded)
|
||||
return;
|
||||
|
||||
if (mFreezeLoading)
|
||||
return;
|
||||
|
||||
if (isSelected())
|
||||
{
|
||||
mStartUnloadTimerMS = Sim::getCurrentTime();
|
||||
return; //if a child is selected, then we don't want to unload
|
||||
}
|
||||
|
||||
//scan down through our child objects, see if any are marked as selected,
|
||||
//if so, skip unloading and reset the timer
|
||||
for (SimGroupIterator itr(this); *itr; ++itr)
|
||||
{
|
||||
SimGroup* childGrp = dynamic_cast<SimGroup*>(*itr);
|
||||
if (childGrp)
|
||||
{
|
||||
if (childGrp->isSelected())
|
||||
{
|
||||
mStartUnloadTimerMS = Sim::getCurrentTime();
|
||||
return; //if a child is selected, then we don't want to unload
|
||||
}
|
||||
for (SimGroupIterator cldItr(childGrp); *cldItr; ++cldItr)
|
||||
{
|
||||
SimObject* chldChld = dynamic_cast<SimObject*>(*cldItr);
|
||||
if (chldChld && chldChld->isSelected())
|
||||
{
|
||||
mStartUnloadTimerMS = Sim::getCurrentTime();
|
||||
return; //if a child is selected, then we don't want to unload
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onUnloaded_callback();
|
||||
for (U32 i = 0; i < mGameModesList.size(); i++)
|
||||
{
|
||||
mGameModesList[i]->onSubsceneUnloaded_callback(this);
|
||||
}
|
||||
|
||||
if (!mOnUnloadCommand.isEmpty())
|
||||
{
|
||||
String command = "%this = " + String(getIdString()) + "; " + mOnUnloadCommand + ";";
|
||||
Con::evaluatef(command.c_str());
|
||||
}
|
||||
|
||||
_closeFile(true);
|
||||
mLoaded = false;
|
||||
|
||||
}
|
||||
|
||||
bool SubScene::save()
|
||||
{
|
||||
if (!isServerObject())
|
||||
return false;
|
||||
|
||||
//if there's nothing TO save, don't bother
|
||||
if (size() == 0 || !isLoaded())
|
||||
return false;
|
||||
|
||||
if (mLevelAsset.isNull())
|
||||
return false;
|
||||
|
||||
//If we're flagged for unload, push back the unload timer so we can't accidentally trip be saving partway through an unload
|
||||
if (mStartUnloadTimerMS != -1)
|
||||
mStartUnloadTimerMS = Sim::getCurrentTime();
|
||||
|
||||
PersistenceManager prMger;
|
||||
|
||||
StringTableEntry levelPath = mLevelAsset->getLevelPath();
|
||||
|
||||
FileStream fs;
|
||||
fs.open(levelPath, Torque::FS::File::Write);
|
||||
fs.close();
|
||||
|
||||
for (SimGroupIterator itr(this); *itr; ++itr)
|
||||
{
|
||||
SimObject* childObj = (*itr);
|
||||
|
||||
if (!prMger.isDirty(childObj))
|
||||
{
|
||||
if ((*itr)->isMethod("onSaving"))
|
||||
{
|
||||
Con::executef((*itr), "onSaving", mLevelAssetId);
|
||||
}
|
||||
|
||||
if (childObj->getGroup() == this)
|
||||
{
|
||||
prMger.setDirty((*itr), levelPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prMger.saveDirty();
|
||||
|
||||
//process our gameModeList and write it out to the levelAsset for metadata stashing
|
||||
bool saveSuccess = false;
|
||||
|
||||
//Get the level asset
|
||||
if (mLevelAsset.isNull())
|
||||
return saveSuccess;
|
||||
|
||||
//update the gamemode list as well
|
||||
mLevelAsset->setDataField(StringTable->insert("gameModesNames"), NULL, StringTable->insert(mGameModesNames));
|
||||
|
||||
//Finally, save
|
||||
saveSuccess = mLevelAsset->saveAsset();
|
||||
|
||||
return saveSuccess;
|
||||
}
|
||||
|
||||
void SubScene::_onSelected()
|
||||
{
|
||||
if (!isLoaded() && isServerObject())
|
||||
load();
|
||||
}
|
||||
|
||||
void SubScene::_onUnselected()
|
||||
{
|
||||
}
|
||||
|
||||
void SubScene::prepRenderImage(SceneRenderState* state)
|
||||
{
|
||||
// only render if selected or render flag is set
|
||||
if (/*!smRenderTriggers && */!isSelected())
|
||||
return;
|
||||
|
||||
ObjectRenderInst* ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
|
||||
ri->renderDelegate.bind(this, &SubScene::renderObject);
|
||||
ri->type = RenderPassManager::RIT_Editor;
|
||||
ri->translucentSort = true;
|
||||
ri->defaultKey = 1;
|
||||
state->getRenderPass()->addInst(ri);
|
||||
}
|
||||
|
||||
void SubScene::renderObject(ObjectRenderInst* ri,
|
||||
SceneRenderState* state,
|
||||
BaseMatInstance* overrideMat)
|
||||
{
|
||||
if (overrideMat)
|
||||
return;
|
||||
|
||||
GFXStateBlockDesc desc;
|
||||
desc.setZReadWrite(true, false);
|
||||
desc.setBlend(true);
|
||||
|
||||
// Trigger polyhedrons are set up with outward facing normals and CCW ordering
|
||||
// so can't enable backface culling.
|
||||
desc.setCullMode(GFXCullNone);
|
||||
|
||||
GFXTransformSaver saver;
|
||||
|
||||
MatrixF mat = getRenderTransform();
|
||||
GFX->multWorld(mat);
|
||||
|
||||
GFXDrawUtil* drawer = GFX->getDrawUtil();
|
||||
|
||||
//Box3F scale = getScale()
|
||||
//Box3F bounds = Box3F(-m)
|
||||
|
||||
Point3F scale = getScale();
|
||||
Box3F bounds = Box3F(-scale/2, scale/2);
|
||||
|
||||
ColorI boundsColor = ColorI(135, 206, 235, 50);
|
||||
|
||||
if (mGlobalLayer)
|
||||
boundsColor = ColorI(200, 100, 100, 25);
|
||||
else if (mLoaded)
|
||||
boundsColor = ColorI(50, 200, 50, 50);
|
||||
|
||||
drawer->drawCube(desc, bounds, boundsColor);
|
||||
|
||||
// Render wireframe.
|
||||
|
||||
desc.setFillModeWireframe();
|
||||
drawer->drawCube(desc, bounds, ColorI::BLACK);
|
||||
}
|
||||
|
||||
DefineEngineMethod(SubScene, save, bool, (),,
|
||||
"Save out the subScene.\n")
|
||||
{
|
||||
return object->save();
|
||||
}
|
||||
|
||||
|
||||
DefineEngineMethod(SubScene, load, void, (), ,
|
||||
"Loads the SubScene's level file.\n")
|
||||
{
|
||||
object->load();
|
||||
}
|
||||
|
||||
DefineEngineMethod(SubScene, unload, void, (), ,
|
||||
"Unloads the SubScene's level file.\n")
|
||||
{
|
||||
object->unload();
|
||||
}
|
||||
126
Engine/source/T3D/SubScene.h
Normal file
126
Engine/source/T3D/SubScene.h
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
#pragma once
|
||||
#ifndef SUB_SCENE_H
|
||||
#define SUB_SCENE_H
|
||||
|
||||
#ifndef SCENE_GROUP_H
|
||||
#include "SceneGroup.h"
|
||||
#endif
|
||||
#ifndef LEVEL_ASSET_H
|
||||
#include "assets/LevelAsset.h"
|
||||
#endif
|
||||
|
||||
class GameMode;
|
||||
|
||||
class SubScene : public SceneGroup
|
||||
{
|
||||
typedef SceneGroup Parent;
|
||||
|
||||
public:
|
||||
enum MaskBits
|
||||
{
|
||||
NextFreeMask = Parent::NextFreeMask << 0
|
||||
};
|
||||
|
||||
void onLevelChanged() {}
|
||||
|
||||
protected:
|
||||
static bool smTransformChildren;
|
||||
|
||||
private:
|
||||
DECLARE_LEVELASSET(SubScene, Level, onLevelChanged);
|
||||
|
||||
StringTableEntry mGameModesNames;
|
||||
Vector<GameMode*> mGameModesList;
|
||||
|
||||
F32 mScopeDistance;
|
||||
|
||||
/// <summary>
|
||||
/// How long we wait once every control object has left the SubScene's load boundary for us to unload the levelAsset.
|
||||
/// </summary>
|
||||
S32 mStartUnloadTimerMS;
|
||||
|
||||
bool mLoaded;
|
||||
bool mFreezeLoading;
|
||||
|
||||
String mLoadIf;
|
||||
String mOnLoadCommand;
|
||||
String mOnUnloadCommand;
|
||||
|
||||
S32 mTickPeriodMS;
|
||||
U32 mCurrTick;
|
||||
|
||||
bool mGlobalLayer;
|
||||
|
||||
public:
|
||||
SubScene();
|
||||
virtual ~SubScene();
|
||||
|
||||
DECLARE_CONOBJECT(SubScene);
|
||||
DECLARE_CATEGORY("Object \t Collection");
|
||||
|
||||
static void initPersistFields();
|
||||
static void consoleInit();
|
||||
StringTableEntry getTypeHint() const override { return (getLevelAsset()) ? getLevelAsset()->getAssetName() : StringTable->EmptyString(); }
|
||||
|
||||
// SimObject
|
||||
bool onAdd() override;
|
||||
void onRemove() override;
|
||||
|
||||
U32 packUpdate(NetConnection* conn, U32 mask, BitStream* stream) override;
|
||||
void unpackUpdate(NetConnection* conn, BitStream* stream) override;
|
||||
|
||||
void addObject(SimObject* object);
|
||||
void removeObject(SimObject* object);
|
||||
//void onEditorEnable() override;
|
||||
//void onEditorDisable() override;
|
||||
void inspectPostApply() override;
|
||||
|
||||
void setTransform(const MatrixF& mat) override;
|
||||
void setRenderTransform(const MatrixF& mat) override;
|
||||
|
||||
bool testBox(const Box3F& testBox);
|
||||
bool evaluateCondition();
|
||||
void _onSelected() override;
|
||||
void _onUnselected() override;
|
||||
|
||||
static S32 mUnloadTimeoutMs;
|
||||
|
||||
protected:
|
||||
void write(Stream& stream, U32 tabStop, U32 flags = 0) override;
|
||||
|
||||
//
|
||||
void _onFileChanged(const Torque::Path& path);
|
||||
void _removeContents(SimGroupIterator);
|
||||
void _closeFile(bool removeFileNotify);
|
||||
void _loadFile(bool addFileNotify);
|
||||
|
||||
//
|
||||
public:
|
||||
void processTick(const Move* move) override;
|
||||
|
||||
//
|
||||
void onInspect(GuiInspector* inspector) override;
|
||||
|
||||
void load();
|
||||
void unload();
|
||||
|
||||
void prepRenderImage(SceneRenderState* state) override;
|
||||
void renderObject(ObjectRenderInst* ri,
|
||||
SceneRenderState* state,
|
||||
BaseMatInstance* overrideMat);
|
||||
|
||||
bool isLoaded() { return mLoaded; }
|
||||
void setUnloadTimeMS(S32 unloadTimeMS) {
|
||||
mStartUnloadTimerMS = unloadTimeMS;
|
||||
}
|
||||
inline S32 getUnloadTimsMS() {
|
||||
return mStartUnloadTimerMS;
|
||||
}
|
||||
|
||||
bool save();
|
||||
|
||||
DECLARE_CALLBACK(void, onLoaded, ());
|
||||
DECLARE_CALLBACK(void, onUnloaded, ());
|
||||
DECLARE_ASSET_SETGET(SubScene, Level);
|
||||
};
|
||||
#endif
|
||||
|
|
@ -104,7 +104,7 @@ ConsoleSetType(TypeImageAssetId)
|
|||
}
|
||||
|
||||
// Warn.
|
||||
Con::warnf("(TypeAssetId) - Cannot set multiple args to a single asset.");
|
||||
Con::warnf("(TypeImageAssetId) - Cannot set multiple args to a single asset.");
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -748,7 +748,7 @@ void GuiInspectorTypeImageAssetPtr::setPreviewImage(StringTableEntry assetId)
|
|||
IMPLEMENT_CONOBJECT(GuiInspectorTypeImageAssetId);
|
||||
|
||||
ConsoleDocClass(GuiInspectorTypeImageAssetId,
|
||||
"@brief Inspector field type for Shapes\n\n"
|
||||
"@brief Inspector field type for Images\n\n"
|
||||
"Editor use only.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
|
|
|||
|
|
@ -42,12 +42,14 @@
|
|||
|
||||
// Debug Profiling.
|
||||
#include "platform/profiler.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CONOBJECT(LevelAsset);
|
||||
|
||||
ConsoleType(LevelAssetPtr, TypeLevelAssetPtr, const char*, ASSET_ID_FIELD_PREFIX)
|
||||
ConsoleType(LevelAssetPtr, TypeLevelAssetPtr, const char*, "")
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -74,6 +76,28 @@ ConsoleSetType(TypeLevelAssetPtr)
|
|||
Con::warnf("(TypeLevelAssetPtr) - Cannot set multiple args to a single asset.");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
ConsoleType(assetIdString, TypeLevelAssetId, const char*, "")
|
||||
|
||||
ConsoleGetType(TypeLevelAssetId)
|
||||
{
|
||||
// Fetch asset Id.
|
||||
return *((const char**)(dptr));
|
||||
}
|
||||
|
||||
ConsoleSetType(TypeLevelAssetId)
|
||||
{
|
||||
// Was a single argument specified?
|
||||
if (argc == 1)
|
||||
{
|
||||
*((const char**)dptr) = StringTable->insert(argv[0]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Warn.
|
||||
Con::warnf("(TypeLevelAssetId) - Cannot set multiple args to a single asset.");
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
LevelAsset::LevelAsset() : AssetBase(), mIsSubLevel(false)
|
||||
|
|
@ -91,7 +115,7 @@ LevelAsset::LevelAsset() : AssetBase(), mIsSubLevel(false)
|
|||
mForestPath = StringTable->EmptyString();
|
||||
mNavmeshPath = StringTable->EmptyString();
|
||||
|
||||
mGamemodeName = StringTable->EmptyString();
|
||||
mGameModesNames = StringTable->EmptyString();
|
||||
mMainLevelAsset = StringTable->EmptyString();
|
||||
|
||||
mEditorFile = StringTable->EmptyString();
|
||||
|
|
@ -134,7 +158,7 @@ void LevelAsset::initPersistFields()
|
|||
&setBakedSceneFile, &getBakedSceneFile, "Path to the level file with the objects generated as part of the baking process");
|
||||
|
||||
addField("isSubScene", TypeBool, Offset(mIsSubLevel, LevelAsset), "Is this a sublevel to another Scene");
|
||||
addField("gameModeName", TypeString, Offset(mGamemodeName, LevelAsset), "Name of the Game Mode to be used with this level");
|
||||
addField("gameModesNames", TypeString, Offset(mGameModesNames, LevelAsset), "Name of the Game Mode to be used with this level");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -357,7 +381,7 @@ void LevelAsset::unloadDependencies()
|
|||
}
|
||||
}
|
||||
|
||||
DefineEngineMethod(LevelAsset, getLevelPath, const char*, (),,
|
||||
DefineEngineMethod(LevelAsset, getLevelPath, const char*, (), ,
|
||||
"Gets the full path of the asset's defined level file.\n"
|
||||
"@return The string result of the level path")
|
||||
{
|
||||
|
|
@ -417,3 +441,99 @@ DefineEngineMethod(LevelAsset, unloadDependencies, void, (), ,
|
|||
{
|
||||
return object->unloadDependencies();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GuiInspectorTypeAssetId
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiInspectorTypeLevelAssetPtr);
|
||||
|
||||
ConsoleDocClass(GuiInspectorTypeLevelAssetPtr,
|
||||
"@brief Inspector field type for Shapes\n\n"
|
||||
"Editor use only.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
void GuiInspectorTypeLevelAssetPtr::consoleInit()
|
||||
{
|
||||
Parent::consoleInit();
|
||||
|
||||
ConsoleBaseType::getType(TypeLevelAssetPtr)->setInspectorFieldType("GuiInspectorTypeLevelAssetPtr");
|
||||
}
|
||||
|
||||
GuiControl* GuiInspectorTypeLevelAssetPtr::constructEditControl()
|
||||
{
|
||||
// Create base filename edit controls
|
||||
GuiControl* retCtrl = Parent::constructEditControl();
|
||||
if (retCtrl == NULL)
|
||||
return retCtrl;
|
||||
|
||||
// Change filespec
|
||||
char szBuffer[512];
|
||||
dSprintf(szBuffer, sizeof(szBuffer), "AssetBrowser.showDialog(\"LevelAsset\", \"AssetBrowser.changeAsset\", %s, \"\");",
|
||||
getIdString());
|
||||
mBrowseButton->setField("Command", szBuffer);
|
||||
|
||||
setDataField(StringTable->insert("targetObject"), NULL, mInspector->getInspectObject()->getIdString());
|
||||
|
||||
// Create "Open in Editor" button
|
||||
mEditButton = new GuiBitmapButtonCtrl();
|
||||
|
||||
dSprintf(szBuffer, sizeof(szBuffer), "$createAndAssignField = %s; AssetBrowser.setupCreateNewAsset(\"LevelAsset\", AssetBrowser.selectedModule, \"createAndAssignLevelAsset\");",
|
||||
getIdString());
|
||||
mEditButton->setField("Command", szBuffer);
|
||||
|
||||
char bitmapName[512] = "ToolsModule:iconAdd_image";
|
||||
mEditButton->setBitmap(StringTable->insert(bitmapName));
|
||||
|
||||
mEditButton->setDataField(StringTable->insert("Profile"), NULL, "GuiButtonProfile");
|
||||
mEditButton->setDataField(StringTable->insert("tooltipprofile"), NULL, "GuiToolTipProfile");
|
||||
mEditButton->setDataField(StringTable->insert("hovertime"), NULL, "1000");
|
||||
mEditButton->setDataField(StringTable->insert("tooltip"), NULL, "Test play this sound");
|
||||
|
||||
mEditButton->registerObject();
|
||||
addObject(mEditButton);
|
||||
|
||||
return retCtrl;
|
||||
}
|
||||
|
||||
bool GuiInspectorTypeLevelAssetPtr::updateRects()
|
||||
{
|
||||
S32 dividerPos, dividerMargin;
|
||||
mInspector->getDivider(dividerPos, dividerMargin);
|
||||
Point2I fieldExtent = getExtent();
|
||||
Point2I fieldPos = getPosition();
|
||||
|
||||
mCaptionRect.set(0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y);
|
||||
mEditCtrlRect.set(fieldExtent.x - dividerPos + dividerMargin, 1, dividerPos - dividerMargin - 34, fieldExtent.y);
|
||||
|
||||
bool resized = mEdit->resize(mEditCtrlRect.point, mEditCtrlRect.extent);
|
||||
if (mBrowseButton != NULL)
|
||||
{
|
||||
mBrowseRect.set(fieldExtent.x - 32, 2, 14, fieldExtent.y - 4);
|
||||
resized |= mBrowseButton->resize(mBrowseRect.point, mBrowseRect.extent);
|
||||
}
|
||||
|
||||
if (mEditButton != NULL)
|
||||
{
|
||||
RectI shapeEdRect(fieldExtent.x - 16, 2, 14, fieldExtent.y - 4);
|
||||
resized |= mEditButton->resize(shapeEdRect.point, shapeEdRect.extent);
|
||||
}
|
||||
|
||||
return resized;
|
||||
}
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiInspectorTypeLevelAssetId);
|
||||
|
||||
ConsoleDocClass(GuiInspectorTypeLevelAssetId,
|
||||
"@brief Inspector field type for Levels\n\n"
|
||||
"Editor use only.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
void GuiInspectorTypeLevelAssetId::consoleInit()
|
||||
{
|
||||
Parent::consoleInit();
|
||||
|
||||
ConsoleBaseType::getType(TypeLevelAssetId)->setInspectorFieldType("GuiInspectorTypeLevelAssetId");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@
|
|||
#endif
|
||||
#include "T3D/assets/ImageAsset.h"
|
||||
|
||||
#ifndef _GUI_INSPECTOR_TYPES_H_
|
||||
#include "gui/editor/guiInspectorTypes.h"
|
||||
#endif
|
||||
#include <gui/controls/guiBitmapCtrl.h>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class LevelAsset : public AssetBase
|
||||
{
|
||||
|
|
@ -64,7 +69,7 @@ class LevelAsset : public AssetBase
|
|||
bool mIsSubLevel;
|
||||
StringTableEntry mMainLevelAsset;
|
||||
|
||||
StringTableEntry mGamemodeName;
|
||||
StringTableEntry mGameModesNames;
|
||||
|
||||
Vector<AssetBase*> mAssetDependencies;
|
||||
|
||||
|
|
@ -114,7 +119,7 @@ public:
|
|||
U32 load() override { return Ok; };
|
||||
|
||||
protected:
|
||||
static bool setLevelFile(void *obj, const char *index, const char *data) { static_cast<LevelAsset*>(obj)->setLevelFile(data); return false; }
|
||||
static bool setLevelFile(void* obj, const char* index, const char* data) { static_cast<LevelAsset*>(obj)->setLevelFile(data); return false; }
|
||||
static const char* getLevelFile(void* obj, const char* data) { return static_cast<LevelAsset*>(obj)->getLevelFile(); }
|
||||
|
||||
static bool setEditorFile(void* obj, const char* index, const char* data) { static_cast<LevelAsset*>(obj)->setEditorFile(data); return false; }
|
||||
|
|
@ -135,10 +140,96 @@ protected:
|
|||
|
||||
void initializeAsset(void) override;
|
||||
void onAssetRefresh(void) override;
|
||||
void loadAsset();
|
||||
void loadAsset();
|
||||
|
||||
typedef Signal<void()> LevelAssetChanged;
|
||||
LevelAssetChanged mChangeSignal;
|
||||
|
||||
public:
|
||||
LevelAssetChanged& getChangedSignal() { return mChangeSignal; }
|
||||
};
|
||||
|
||||
#ifdef TORQUE_TOOLS
|
||||
class GuiInspectorTypeLevelAssetPtr : public GuiInspectorTypeFileName
|
||||
{
|
||||
typedef GuiInspectorTypeFileName Parent;
|
||||
public:
|
||||
|
||||
GuiBitmapButtonCtrl* mEditButton;
|
||||
|
||||
DECLARE_CONOBJECT(GuiInspectorTypeLevelAssetPtr);
|
||||
static void consoleInit();
|
||||
|
||||
GuiControl* constructEditControl() override;
|
||||
bool updateRects() override;
|
||||
};
|
||||
|
||||
class GuiInspectorTypeLevelAssetId : public GuiInspectorTypeLevelAssetPtr
|
||||
{
|
||||
typedef GuiInspectorTypeLevelAssetPtr Parent;
|
||||
public:
|
||||
|
||||
DECLARE_CONOBJECT(GuiInspectorTypeLevelAssetId);
|
||||
static void consoleInit();
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
DefineConsoleType(TypeLevelAssetPtr, LevelAsset)
|
||||
DefineConsoleType(TypeLevelAssetId, String)
|
||||
|
||||
#pragma region Singular Asset Macros
|
||||
|
||||
//Singular assets
|
||||
/// <Summary>
|
||||
/// Declares an level asset
|
||||
/// This establishes the assetId, asset and legacy filepath fields, along with supplemental getter and setter functions
|
||||
/// </Summary>
|
||||
#define DECLARE_LEVELASSET(className, name, changeFunc) public: \
|
||||
StringTableEntry m##name##AssetId;\
|
||||
AssetPtr<LevelAsset> m##name##Asset;\
|
||||
public: \
|
||||
const AssetPtr<LevelAsset> & get##name##Asset() const { return m##name##Asset; }\
|
||||
void set##name##Asset(const AssetPtr<LevelAsset> &_in) { m##name##Asset = _in;}\
|
||||
\
|
||||
bool _set##name(StringTableEntry _in)\
|
||||
{\
|
||||
if(m##name##AssetId != _in)\
|
||||
{\
|
||||
if (m##name##Asset.notNull())\
|
||||
{\
|
||||
m##name##Asset->getChangedSignal().remove(this, &className::changeFunc);\
|
||||
}\
|
||||
if (_in == NULL || _in == StringTable->EmptyString())\
|
||||
{\
|
||||
m##name##AssetId = StringTable->EmptyString();\
|
||||
m##name##Asset = NULL;\
|
||||
return true;\
|
||||
}\
|
||||
if (AssetDatabase.isDeclaredAsset(_in))\
|
||||
{\
|
||||
m##name##AssetId = _in;\
|
||||
m##name##Asset = _in;\
|
||||
return true;\
|
||||
}\
|
||||
}\
|
||||
\
|
||||
if(get##name() == StringTable->EmptyString())\
|
||||
return true;\
|
||||
\
|
||||
return false;\
|
||||
}\
|
||||
\
|
||||
const StringTableEntry get##name() const\
|
||||
{\
|
||||
return m##name##AssetId;\
|
||||
}\
|
||||
bool name##Valid() {return (get##name() != StringTable->EmptyString() && m##name##Asset->getStatus() == AssetBase::Ok); }
|
||||
|
||||
#define INITPERSISTFIELD_LEVELASSET(name, consoleClass, docs) \
|
||||
addProtectedField(assetText(name, Asset), TypeLevelAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.));
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#endif // _ASSET_BASE_H_
|
||||
|
||||
|
|
|
|||
|
|
@ -317,10 +317,10 @@ void ConvexShape::initPersistFields()
|
|||
addGroup( "Internal" );
|
||||
|
||||
addProtectedField( "surface", TypeRealString, 0, &protectedSetSurface, &defaultProtectedGetFn,
|
||||
"Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors );
|
||||
"Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors | AbstractClassRep::FIELD_SpecialtyArrayField);
|
||||
|
||||
addProtectedField( "surfaceTexture", TypeRealString, 0, &protectedSetSurfaceTexture, &defaultProtectedGetFn,
|
||||
"Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors );
|
||||
"Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors | AbstractClassRep::FIELD_SpecialtyArrayField);
|
||||
|
||||
endGroup( "Internal" );
|
||||
|
||||
|
|
@ -498,6 +498,55 @@ bool ConvexShape::writeField( StringTableEntry fieldname, const char *value )
|
|||
return Parent::writeField( fieldname, value );
|
||||
}
|
||||
|
||||
U32 ConvexShape::getSpecialFieldSize(StringTableEntry fieldName)
|
||||
{
|
||||
if (fieldName == StringTable->insert("surface") || fieldName == StringTable->insert("surfaceTexture"))
|
||||
{
|
||||
return mSurfaces.size();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* ConvexShape::getSpecialFieldOut(StringTableEntry fieldName, const U32& index)
|
||||
{
|
||||
if (index >= smMaxSurfaces)
|
||||
return NULL;
|
||||
|
||||
if (fieldName == StringTable->insert("surface"))
|
||||
{
|
||||
if(index >= mSurfaces.size())
|
||||
return NULL;
|
||||
|
||||
const MatrixF& mat = mSurfaces[index];
|
||||
|
||||
QuatF quat(mat);
|
||||
Point3F pos(mat.getPosition());
|
||||
|
||||
char buffer[1024];
|
||||
dMemset(buffer, 0, 1024);
|
||||
|
||||
dSprintf(buffer, 1024, "%g %g %g %g %g %g %g %i %g %g %g %g %g %i %i",
|
||||
quat.x, quat.y, quat.z, quat.w, pos.x, pos.y, pos.z, mSurfaceUVs[index].matID,
|
||||
mSurfaceUVs[index].offset.x, mSurfaceUVs[index].offset.y, mSurfaceUVs[index].scale.x,
|
||||
mSurfaceUVs[index].scale.y, mSurfaceUVs[index].zRot, mSurfaceUVs[index].horzFlip, mSurfaceUVs[index].vertFlip);
|
||||
|
||||
return StringTable->insert(buffer);
|
||||
}
|
||||
else if (fieldName == StringTable->insert("surfaceTexture"))
|
||||
{
|
||||
if (index >= mSurfaceTextures.size())
|
||||
return NULL;
|
||||
|
||||
char buffer[1024];
|
||||
dMemset(buffer, 0, 1024);
|
||||
|
||||
dSprintf(buffer, 1024, "%s", mSurfaceTextures[index].getMaterial());
|
||||
|
||||
return StringTable->insert(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void ConvexShape::onScaleChanged()
|
||||
{
|
||||
if ( isProperlyAdded() )
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ class ConvexShape : public SceneObject
|
|||
typedef SceneObject Parent;
|
||||
friend class GuiConvexEditorCtrl;
|
||||
friend class GuiConvexEditorUndoAction;
|
||||
friend class ConvexShapeCollisionConvex;
|
||||
friend class ConvexShapeCollisionConvex;
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -113,10 +113,10 @@ public:
|
|||
U32 p1;
|
||||
U32 p2;
|
||||
|
||||
U32 operator []( U32 index ) const
|
||||
U32 operator [](U32 index) const
|
||||
{
|
||||
AssertFatal( index >= 0 && index <= 2, "index out of range" );
|
||||
return *( (&p0) + index );
|
||||
AssertFatal(index >= 0 && index <= 2, "index out of range");
|
||||
return *((&p0) + index);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -126,23 +126,23 @@ public:
|
|||
Vector< U32 > points;
|
||||
Vector< U32 > winding;
|
||||
Vector< Point2F > texcoords;
|
||||
Vector< Triangle > triangles;
|
||||
Vector< Triangle > triangles;
|
||||
Point3F tangent;
|
||||
Point3F normal;
|
||||
Point3F centroid;
|
||||
F32 area;
|
||||
S32 id;
|
||||
};
|
||||
};
|
||||
|
||||
struct surfaceMaterial
|
||||
{
|
||||
// The name of the Material we will use for rendering
|
||||
DECLARE_MATERIALASSET(surfaceMaterial, Material);
|
||||
|
||||
|
||||
DECLARE_ASSET_SETGET(surfaceMaterial, Material);
|
||||
|
||||
// The actual Material instance
|
||||
BaseMatInstance* materialInst;
|
||||
BaseMatInstance* materialInst;
|
||||
|
||||
surfaceMaterial()
|
||||
{
|
||||
|
|
@ -174,26 +174,26 @@ public:
|
|||
U32 mPrimCount;
|
||||
};
|
||||
|
||||
struct Geometry
|
||||
{
|
||||
void generate(const Vector< PlaneF > &planes, const Vector< Point3F > &tangents, const Vector< surfaceMaterial > surfaceTextures, const Vector< Point2F > texOffset, const Vector< Point2F > texScale, const Vector< bool > horzFlip, const Vector< bool > vertFlip);
|
||||
struct Geometry
|
||||
{
|
||||
void generate(const Vector< PlaneF >& planes, const Vector< Point3F >& tangents, const Vector< surfaceMaterial > surfaceTextures, const Vector< Point2F > texOffset, const Vector< Point2F > texScale, const Vector< bool > horzFlip, const Vector< bool > vertFlip);
|
||||
|
||||
Vector< Point3F > points;
|
||||
Vector< Face > faces;
|
||||
};
|
||||
Vector< Point3F > points;
|
||||
Vector< Face > faces;
|
||||
};
|
||||
|
||||
static bool smRenderEdges;
|
||||
static bool smRenderEdges;
|
||||
|
||||
// To prevent bitpack overflows.
|
||||
// This is only indirectly enforced by trucation when serializing.
|
||||
static const S32 smMaxSurfaces = 100;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
ConvexShape();
|
||||
virtual ~ConvexShape();
|
||||
|
||||
DECLARE_CONOBJECT( ConvexShape );
|
||||
DECLARE_CONOBJECT(ConvexShape);
|
||||
DECLARE_CATEGORY("Object \t Simple");
|
||||
|
||||
// ConsoleObject
|
||||
|
|
@ -203,73 +203,76 @@ public:
|
|||
void inspectPostApply() override;
|
||||
bool onAdd() override;
|
||||
void onRemove() override;
|
||||
void writeFields(Stream &stream, U32 tabStop) override;
|
||||
bool writeField( StringTableEntry fieldname, const char *value ) override;
|
||||
void writeFields(Stream& stream, U32 tabStop) override;
|
||||
bool writeField(StringTableEntry fieldname, const char* value) override;
|
||||
|
||||
U32 getSpecialFieldSize(StringTableEntry fieldName) override;
|
||||
const char* getSpecialFieldOut(StringTableEntry fieldName, const U32& index) override;
|
||||
|
||||
// NetObject
|
||||
U32 packUpdate( NetConnection *conn, U32 mask, BitStream *stream ) override;
|
||||
void unpackUpdate( NetConnection *conn, BitStream *stream ) override;
|
||||
U32 packUpdate(NetConnection* conn, U32 mask, BitStream* stream) override;
|
||||
void unpackUpdate(NetConnection* conn, BitStream* stream) override;
|
||||
|
||||
// SceneObject
|
||||
void onScaleChanged() override;
|
||||
void setTransform( const MatrixF &mat ) override;
|
||||
void prepRenderImage( SceneRenderState *state ) override;
|
||||
void buildConvex( const Box3F &box, Convex *convex ) override;
|
||||
bool buildPolyList( PolyListContext context, AbstractPolyList *polyList, const Box3F &box, const SphereF &sphere ) override;
|
||||
bool buildExportPolyList(ColladaUtils::ExportData* exportData, const Box3F &box, const SphereF &) override;
|
||||
bool castRay( const Point3F &start, const Point3F &end, RayInfo *info ) override;
|
||||
bool collideBox( const Point3F &start, const Point3F &end, RayInfo *info ) override;
|
||||
void setTransform(const MatrixF& mat) override;
|
||||
void prepRenderImage(SceneRenderState* state) override;
|
||||
void buildConvex(const Box3F& box, Convex* convex) override;
|
||||
bool buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& sphere) override;
|
||||
bool buildExportPolyList(ColladaUtils::ExportData* exportData, const Box3F& box, const SphereF&) override;
|
||||
bool castRay(const Point3F& start, const Point3F& end, RayInfo* info) override;
|
||||
bool collideBox(const Point3F& start, const Point3F& end, RayInfo* info) override;
|
||||
|
||||
|
||||
void updateBounds( bool recenter );
|
||||
void updateBounds(bool recenter);
|
||||
void recenter();
|
||||
|
||||
/// Geometry access.
|
||||
/// @{
|
||||
|
||||
MatrixF getSurfaceWorldMat( S32 faceid, bool scaled = false ) const;
|
||||
void cullEmptyPlanes( Vector< U32 > *removedPlanes );
|
||||
void exportToCollada();
|
||||
void resizePlanes( const Point3F &size );
|
||||
void getSurfaceLineList( S32 surfId, Vector< Point3F > &lineList );
|
||||
Geometry& getGeometry() { return mGeometry; }
|
||||
Vector<MatrixF>& getSurfaces() { return mSurfaces; }
|
||||
void getSurfaceTriangles( S32 surfId, Vector< Point3F > *outPoints, Vector< Point2F > *outCoords, bool worldSpace );
|
||||
|
||||
MatrixF getSurfaceWorldMat(S32 faceid, bool scaled = false) const;
|
||||
void cullEmptyPlanes(Vector< U32 >* removedPlanes);
|
||||
void exportToCollada();
|
||||
void resizePlanes(const Point3F& size);
|
||||
void getSurfaceLineList(S32 surfId, Vector< Point3F >& lineList);
|
||||
Geometry& getGeometry() { return mGeometry; }
|
||||
Vector<MatrixF>& getSurfaces() { return mSurfaces; }
|
||||
void getSurfaceTriangles(S32 surfId, Vector< Point3F >* outPoints, Vector< Point2F >* outCoords, bool worldSpace);
|
||||
|
||||
/// @}
|
||||
|
||||
/// Geometry Visualization.
|
||||
/// @{
|
||||
|
||||
void renderFaceEdges( S32 faceid, const ColorI &color = ColorI::WHITE, F32 lineWidth = 1.0f );
|
||||
void renderFaceEdges(S32 faceid, const ColorI& color = ColorI::WHITE, F32 lineWidth = 1.0f);
|
||||
|
||||
/// @}
|
||||
|
||||
String getMaterialName() { return mMaterialName; }
|
||||
String getMaterialName() { return mMaterialName; }
|
||||
|
||||
protected:
|
||||
|
||||
void _updateMaterial();
|
||||
void _updateGeometry( bool updateCollision = false );
|
||||
void _updateGeometry(bool updateCollision = false);
|
||||
void _updateCollision();
|
||||
void _export( OptimizedPolyList *plist, const Box3F &box, const SphereF &sphere );
|
||||
void _export(OptimizedPolyList* plist, const Box3F& box, const SphereF& sphere);
|
||||
|
||||
void _renderDebug( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mat );
|
||||
void _renderDebug(ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* mat);
|
||||
|
||||
static S32 QSORT_CALLBACK _comparePlaneDist( const void *a, const void *b );
|
||||
static S32 QSORT_CALLBACK _comparePlaneDist(const void* a, const void* b);
|
||||
|
||||
static bool protectedSetSurface( void *object, const char *index, const char *data );
|
||||
static bool protectedSetSurface(void* object, const char* index, const char* data);
|
||||
|
||||
static bool protectedSetSurfaceTexture(void* object, const char* index, const char* data);
|
||||
static bool protectedSetSurfaceUV(void* object, const char* index, const char* data);
|
||||
|
||||
static bool protectedSetSurfaceTexture( void *object, const char *index, const char *data );
|
||||
static bool protectedSetSurfaceUV(void *object, const char *index, const char *data);
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
DECLARE_MATERIALASSET(ConvexShape, Material);
|
||||
DECLARE_ASSET_SETGET(ConvexShape, Material);
|
||||
|
||||
// The actual Material instance
|
||||
BaseMatInstance* mMaterialInst;
|
||||
BaseMatInstance* mMaterialInst;
|
||||
|
||||
// The GFX vertex and primitive buffers
|
||||
/*GFXVertexBufferHandle< VertexType > mVertexBuffer;
|
||||
|
|
@ -278,7 +281,7 @@ protected:
|
|||
U32 mVertCount;
|
||||
U32 mPrimCount;*/
|
||||
|
||||
Geometry mGeometry;
|
||||
Geometry mGeometry;
|
||||
|
||||
Vector< PlaneF > mPlanes;
|
||||
|
||||
|
|
@ -291,14 +294,14 @@ protected:
|
|||
Vector< surfaceUV > mSurfaceUVs;
|
||||
Vector< surfaceBuffers > mSurfaceBuffers;
|
||||
|
||||
Convex *mConvexList;
|
||||
Convex* mConvexList;
|
||||
|
||||
PhysicsBody *mPhysicsRep;
|
||||
PhysicsBody* mPhysicsRep;
|
||||
|
||||
/// Geometry visualization
|
||||
/// @{
|
||||
|
||||
F32 mNormalLength;
|
||||
F32 mNormalLength;
|
||||
|
||||
/// @}
|
||||
|
||||
|
|
|
|||
460
Engine/source/T3D/gameMode.cpp
Normal file
460
Engine/source/T3D/gameMode.cpp
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
#include "gameMode.h"
|
||||
|
||||
#ifdef TORQUE_TOOLS
|
||||
#include "gui/containers/guiDynamicCtrlArrayCtrl.h"
|
||||
#endif
|
||||
|
||||
#include "console/arrayObject.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT(GameMode);
|
||||
|
||||
IMPLEMENT_CALLBACK(GameMode, onActivated, void, (), (),
|
||||
"@brief Called when a gamemode is activated.\n\n");
|
||||
IMPLEMENT_CALLBACK(GameMode, onDeactivated, void, (), (),
|
||||
"@brief Called when a gamemode is deactivated.\n\n");
|
||||
IMPLEMENT_CALLBACK(GameMode, onSceneLoaded, void, (), (),
|
||||
"@brief Called when a scene has been loaded and has game mode implications.\n\n");
|
||||
IMPLEMENT_CALLBACK(GameMode, onSceneUnloaded, void, (), (),
|
||||
"@brief Called when a scene has been unloaded and has game mode implications.\n\n");
|
||||
IMPLEMENT_CALLBACK(GameMode, onSubsceneLoaded, void, (SubScene*), ("SubScene"),
|
||||
"@brief Called when a subScene has been loaded and has game mode implications.\n\n");
|
||||
IMPLEMENT_CALLBACK(GameMode, onSubsceneUnloaded, void, (SubScene*), ("SubScene"),
|
||||
"@brief Called when a subScene has been unloaded and has game mode implications.\n\n");
|
||||
|
||||
|
||||
ConsoleType(GameModeList, TypeGameModeList, const char*, "")
|
||||
|
||||
ConsoleGetType(TypeGameModeList)
|
||||
{
|
||||
// Fetch asset Id.
|
||||
return *((const char**)(dptr));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ConsoleSetType(TypeGameModeList)
|
||||
{
|
||||
// Was a single argument specified?
|
||||
if (argc == 1)
|
||||
{
|
||||
// Yes, so fetch field value.
|
||||
*((const char**)dptr) = StringTable->insert(argv[0]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Warn.
|
||||
//Con::warnf("(TypeGameModeList) - Cannot set multiple args to a single asset.");
|
||||
}
|
||||
|
||||
GameMode::GameMode() :
|
||||
mGameModeName(StringTable->EmptyString()),
|
||||
mGameModeDesc(StringTable->EmptyString()),
|
||||
mIsActive(false),
|
||||
mIsAlwaysActive(false)
|
||||
{
|
||||
INIT_ASSET(PreviewImage);
|
||||
}
|
||||
|
||||
void GameMode::initPersistFields()
|
||||
{
|
||||
Parent::initPersistFields();
|
||||
|
||||
addField("gameModeName", TypeString, Offset(mGameModeName, GameMode), "Human-readable name of the gamemode");
|
||||
addField("description", TypeString, Offset(mGameModeDesc, GameMode), "Description of the gamemode");
|
||||
|
||||
INITPERSISTFIELD_IMAGEASSET(PreviewImage, GameMode, "Preview Image");
|
||||
|
||||
addField("active", TypeBool, Offset(mIsActive, GameMode), "Is the gamemode active");
|
||||
addField("alwaysActive", TypeBool, Offset(mIsAlwaysActive, GameMode), "Is the gamemode always active");
|
||||
}
|
||||
|
||||
bool GameMode::onAdd()
|
||||
{
|
||||
if (!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameMode::onRemove()
|
||||
{
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
void GameMode::findGameModes(const char* gameModeList, Vector<GameMode*> *outGameModes)
|
||||
{
|
||||
if (outGameModes == nullptr)
|
||||
return;
|
||||
|
||||
Vector<String> gameModeNames;
|
||||
U32 uCount = StringUnit::getUnitCount(gameModeList, ";");
|
||||
for (U32 i = 0; i < uCount; i++)
|
||||
{
|
||||
String name = StringUnit::getUnit(gameModeList, i, ";");
|
||||
if (!name.isEmpty())
|
||||
gameModeNames.push_back(name);
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < gameModeNames.size(); i++)
|
||||
{
|
||||
GameMode* gm;
|
||||
if (Sim::findObject(gameModeNames[i].c_str(), gm))
|
||||
{
|
||||
outGameModes->push_back(gm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameMode::setActive(const bool& active)
|
||||
{
|
||||
mIsActive = active;
|
||||
if (mIsActive)
|
||||
onActivated_callback();
|
||||
else
|
||||
onDeactivated_callback();
|
||||
}
|
||||
|
||||
void GameMode::setAlwaysActive(const bool& alwaysActive)
|
||||
{
|
||||
mIsAlwaysActive = alwaysActive;
|
||||
}
|
||||
|
||||
DefineEngineMethod(GameMode, isActive, bool, (), ,
|
||||
"Returns if the GameMode is currently active.\n"
|
||||
"@return The active status of the GameMode")
|
||||
{
|
||||
return object->isActive();
|
||||
}
|
||||
|
||||
DefineEngineMethod(GameMode, setActive, void, (bool active), (true),
|
||||
"Sets the active state of the GameMode.\n"
|
||||
"@param active A bool of the state the GameMode should be set to")
|
||||
{
|
||||
object->setActive(active);
|
||||
}
|
||||
|
||||
DefineEngineMethod(GameMode, isALwaysActive, bool, (), ,
|
||||
"Returns if the GameMode is currently active.\n"
|
||||
"@return The active status of the GameMode")
|
||||
{
|
||||
return object->isActive();
|
||||
}
|
||||
|
||||
DefineEngineMethod(GameMode, setAlwaysActive, void, (bool alwaysActive), (true),
|
||||
"Sets the active state of the GameMode.\n"
|
||||
"@param active A bool of the state the GameMode should be set to")
|
||||
{
|
||||
object->setAlwaysActive(alwaysActive);
|
||||
}
|
||||
|
||||
DefineEngineFunction(getGameModesList, ArrayObject*, (), , "")
|
||||
{
|
||||
ArrayObject* dictionary = new ArrayObject();
|
||||
dictionary->registerObject();
|
||||
|
||||
char activeValBuffer[16];
|
||||
|
||||
for (SimGroup::iterator itr = Sim::getRootGroup()->begin(); itr != Sim::getRootGroup()->end(); itr++)
|
||||
{
|
||||
GameMode* gm = dynamic_cast<GameMode*>(*itr);
|
||||
if (gm)
|
||||
{
|
||||
dSprintf(activeValBuffer, 16, "%d", (gm->mIsActive || gm->mIsAlwaysActive));
|
||||
dictionary->push_back(gm->getName(), activeValBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GuiInspectorTypeAssetId
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef TORQUE_TOOLS
|
||||
|
||||
GuiInspectorTypeGameModeList::GuiInspectorTypeGameModeList()
|
||||
: mHelper(NULL),
|
||||
mRollout(NULL),
|
||||
mArrayCtrl(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
IMPLEMENT_CONOBJECT(GuiInspectorTypeGameModeList);
|
||||
|
||||
ConsoleDocClass(GuiInspectorTypeGameModeList,
|
||||
"@brief Inspector field type for selecting GameModes\n\n"
|
||||
"Editor use only.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
bool GuiInspectorTypeGameModeList::onAdd()
|
||||
{
|
||||
// Skip our parent because we aren't using mEditCtrl
|
||||
// and according to our parent that would be cause to fail onAdd.
|
||||
if (!Parent::Parent::onAdd())
|
||||
return false;
|
||||
|
||||
if (!mInspector)
|
||||
return false;
|
||||
|
||||
//build out our list of gamemodes
|
||||
Vector<GameMode*> gameModesList;
|
||||
|
||||
for (SimGroup::iterator itr = Sim::getRootGroup()->begin(); itr != Sim::getRootGroup()->end(); itr++)
|
||||
{
|
||||
GameMode* gm = dynamic_cast<GameMode*>(*itr);
|
||||
if (gm)
|
||||
gameModesList.push_back(gm);
|
||||
}
|
||||
|
||||
static StringTableEntry sProfile = StringTable->insert("profile");
|
||||
setDataField(sProfile, NULL, "GuiInspectorFieldProfile");
|
||||
setBounds(0, 0, 100, 18);
|
||||
|
||||
// Allocate our children controls...
|
||||
|
||||
mRollout = new GuiRolloutCtrl();
|
||||
mRollout->setMargin(14, 0, 0, 0);
|
||||
mRollout->setCanCollapse(false);
|
||||
mRollout->registerObject();
|
||||
addObject(mRollout);
|
||||
|
||||
mArrayCtrl = new GuiDynamicCtrlArrayControl();
|
||||
mArrayCtrl->setDataField(sProfile, NULL, "GuiInspectorBitMaskArrayProfile");
|
||||
mArrayCtrl->setField("autoCellSize", "true");
|
||||
mArrayCtrl->setField("fillRowFirst", "true");
|
||||
mArrayCtrl->setField("dynamicSize", "true");
|
||||
mArrayCtrl->setField("rowSpacing", "4");
|
||||
mArrayCtrl->setField("colSpacing", "1");
|
||||
mArrayCtrl->setField("frozen", "true");
|
||||
mArrayCtrl->registerObject();
|
||||
|
||||
mRollout->addObject(mArrayCtrl);
|
||||
|
||||
GuiCheckBoxCtrl* pCheckBox = NULL;
|
||||
|
||||
for (S32 i = 0; i < gameModesList.size(); i++)
|
||||
{
|
||||
pCheckBox = new GuiCheckBoxCtrl();
|
||||
pCheckBox->setText(gameModesList[i]->getName());
|
||||
pCheckBox->registerObject();
|
||||
mArrayCtrl->addObject(pCheckBox);
|
||||
|
||||
pCheckBox->autoSize();
|
||||
|
||||
// Override the normal script callbacks for GuiInspectorTypeCheckBox
|
||||
char szBuffer[512];
|
||||
dSprintf(szBuffer, 512, "%d.applyValue();", getId());
|
||||
pCheckBox->setField("Command", szBuffer);
|
||||
}
|
||||
|
||||
mArrayCtrl->setField("frozen", "false");
|
||||
mArrayCtrl->refresh();
|
||||
|
||||
mHelper = new GuiInspectorTypeGameModeListHelper();
|
||||
mHelper->init(mInspector, mParent);
|
||||
mHelper->mParentRollout = mRollout;
|
||||
mHelper->mParentField = this;
|
||||
mHelper->setInspectorField(mField, mCaption, mFieldArrayIndex);
|
||||
mHelper->registerObject();
|
||||
mHelper->setExtent(pCheckBox->getExtent());
|
||||
mHelper->setPosition(0, 0);
|
||||
mRollout->addObject(mHelper);
|
||||
|
||||
mRollout->sizeToContents();
|
||||
mRollout->instantCollapse();
|
||||
|
||||
updateValue();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiInspectorTypeGameModeList::consoleInit()
|
||||
{
|
||||
Parent::consoleInit();
|
||||
|
||||
ConsoleBaseType::getType(TypeGameModeList)->setInspectorFieldType("GuiInspectorTypeGameModeList");
|
||||
}
|
||||
|
||||
void GuiInspectorTypeGameModeList::childResized(GuiControl* child)
|
||||
{
|
||||
setExtent(mRollout->getExtent());
|
||||
}
|
||||
|
||||
bool GuiInspectorTypeGameModeList::resize(const Point2I& newPosition, const Point2I& newExtent)
|
||||
{
|
||||
if (!Parent::resize(newPosition, newExtent))
|
||||
return false;
|
||||
|
||||
// Hack... height of 18 is hardcoded
|
||||
return mHelper->resize(Point2I(0, 0), Point2I(newExtent.x, 18));
|
||||
}
|
||||
|
||||
bool GuiInspectorTypeGameModeList::updateRects()
|
||||
{
|
||||
if (!mRollout)
|
||||
return false;
|
||||
|
||||
bool result = mRollout->setExtent(getExtent());
|
||||
|
||||
for (U32 i = 0; i < mArrayCtrl->size(); i++)
|
||||
{
|
||||
GuiInspectorField* pField = dynamic_cast<GuiInspectorField*>(mArrayCtrl->at(i));
|
||||
if (pField)
|
||||
if (pField->updateRects())
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (mHelper && mHelper->updateRects())
|
||||
result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
StringTableEntry GuiInspectorTypeGameModeList::getValue()
|
||||
{
|
||||
if (!mRollout)
|
||||
return StringTable->insert("");
|
||||
|
||||
String results = "";
|
||||
|
||||
for (U32 i = 0; i < mArrayCtrl->size(); i++)
|
||||
{
|
||||
GuiCheckBoxCtrl* pCheckBox = dynamic_cast<GuiCheckBoxCtrl*>(mArrayCtrl->at(i));
|
||||
|
||||
if (pCheckBox->getStateOn())
|
||||
results += pCheckBox->getText() + String(";");
|
||||
}
|
||||
|
||||
if (!results.isEmpty())
|
||||
return StringTable->insert(results.c_str());
|
||||
else
|
||||
return StringTable->EmptyString();
|
||||
}
|
||||
|
||||
void GuiInspectorTypeGameModeList::setValue(StringTableEntry value)
|
||||
{
|
||||
Vector<String> gameModeNames;
|
||||
U32 uCount = StringUnit::getUnitCount(value, ";");
|
||||
for (U32 i = 0; i < uCount; i++)
|
||||
{
|
||||
String name = StringUnit::getUnit(value, i, ";");
|
||||
if (!name.isEmpty())
|
||||
gameModeNames.push_back(name);
|
||||
}
|
||||
|
||||
for (U32 i = 0; i < mArrayCtrl->size(); i++)
|
||||
{
|
||||
GuiCheckBoxCtrl* pCheckBox = dynamic_cast<GuiCheckBoxCtrl*>(mArrayCtrl->at(i));
|
||||
|
||||
for (U32 m = 0; m < gameModeNames.size(); m++)
|
||||
{
|
||||
if (gameModeNames[m].equal(pCheckBox->getText()))
|
||||
{
|
||||
pCheckBox->setStateOn(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mHelper->setValue(value);
|
||||
}
|
||||
|
||||
void GuiInspectorTypeGameModeList::updateData()
|
||||
{
|
||||
StringTableEntry data = getValue();
|
||||
setData(data);
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiInspectorTypeGameModeList, applyValue, void, (), , "")
|
||||
{
|
||||
object->updateData();
|
||||
}
|
||||
|
||||
GuiInspectorTypeGameModeListHelper::GuiInspectorTypeGameModeListHelper()
|
||||
: mButton(NULL),
|
||||
mParentRollout(NULL),
|
||||
mParentField(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
IMPLEMENT_CONOBJECT(GuiInspectorTypeGameModeListHelper);
|
||||
|
||||
ConsoleDocClass(GuiInspectorTypeGameModeListHelper,
|
||||
"@brief Inspector field type support for GameModes lists.\n\n"
|
||||
"Editor use only.\n\n"
|
||||
"@internal"
|
||||
);
|
||||
|
||||
GuiControl* GuiInspectorTypeGameModeListHelper::constructEditControl()
|
||||
{
|
||||
GuiControl* retCtrl = new GuiTextEditCtrl();
|
||||
retCtrl->setDataField(StringTable->insert("profile"), NULL, "GuiInspectorTextEditProfile");
|
||||
retCtrl->setField("hexDisplay", "true");
|
||||
|
||||
_registerEditControl(retCtrl);
|
||||
|
||||
char szBuffer[512];
|
||||
dSprintf(szBuffer, 512, "%d.apply(%d.getText());", mParentField->getId(), retCtrl->getId());
|
||||
retCtrl->setField("AltCommand", szBuffer);
|
||||
retCtrl->setField("Validate", szBuffer);
|
||||
|
||||
mButton = new GuiBitmapButtonCtrl();
|
||||
|
||||
RectI browseRect(Point2I((getLeft() + getWidth()) - 26, getTop() + 2), Point2I(20, getHeight() - 4));
|
||||
dSprintf(szBuffer, 512, "%d.toggleExpanded(false);", mParentRollout->getId());
|
||||
mButton->setField("Command", szBuffer);
|
||||
mButton->setField("buttonType", "ToggleButton");
|
||||
mButton->setDataField(StringTable->insert("Profile"), NULL, "GuiInspectorButtonProfile");
|
||||
mButton->setBitmap(StringTable->insert("ToolsModule:arrowBtn_N_image"));
|
||||
mButton->setStateOn(true);
|
||||
mButton->setExtent(16, 16);
|
||||
mButton->registerObject();
|
||||
addObject(mButton);
|
||||
|
||||
mButton->resize(browseRect.point, browseRect.extent);
|
||||
|
||||
return retCtrl;
|
||||
}
|
||||
|
||||
bool GuiInspectorTypeGameModeListHelper::resize(const Point2I& newPosition, const Point2I& newExtent)
|
||||
{
|
||||
if (!Parent::resize(newPosition, newExtent))
|
||||
return false;
|
||||
|
||||
if (mEdit != NULL)
|
||||
{
|
||||
return updateRects();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GuiInspectorTypeGameModeListHelper::updateRects()
|
||||
{
|
||||
S32 dividerPos, dividerMargin;
|
||||
mInspector->getDivider(dividerPos, dividerMargin);
|
||||
Point2I fieldExtent = getExtent();
|
||||
Point2I fieldPos = getPosition();
|
||||
|
||||
mCaptionRect.set(0, 0, fieldExtent.x - dividerPos - dividerMargin, fieldExtent.y);
|
||||
mEditCtrlRect.set(fieldExtent.x - dividerPos + dividerMargin, 1, dividerPos - dividerMargin - 32, fieldExtent.y);
|
||||
|
||||
bool editResize = mEdit->resize(mEditCtrlRect.point, mEditCtrlRect.extent);
|
||||
bool buttonResize = false;
|
||||
|
||||
if (mButton != NULL)
|
||||
{
|
||||
mButtonRect.set(fieldExtent.x - 26, 2, 16, 16);
|
||||
buttonResize = mButton->resize(mButtonRect.point, mButtonRect.extent);
|
||||
}
|
||||
|
||||
return (editResize || buttonResize);
|
||||
}
|
||||
|
||||
void GuiInspectorTypeGameModeListHelper::setValue(StringTableEntry newValue)
|
||||
{
|
||||
GuiTextEditCtrl* edit = dynamic_cast<GuiTextEditCtrl*>(mEdit);
|
||||
edit->setText(newValue);
|
||||
}
|
||||
#endif
|
||||
117
Engine/source/T3D/gameMode.h
Normal file
117
Engine/source/T3D/gameMode.h
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
#pragma once
|
||||
#ifndef GAME_MODE_H
|
||||
#define GAME_MODE_H
|
||||
|
||||
#ifdef TORQUE_TOOLS
|
||||
#ifndef _GUI_INSPECTOR_TYPES_H_
|
||||
#include "gui/editor/guiInspectorTypes.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SUB_SCENE_H
|
||||
#include "SubScene.h"
|
||||
#endif
|
||||
|
||||
#include "T3D/assets/ImageAsset.h"
|
||||
|
||||
class GameMode : public SimObject
|
||||
{
|
||||
typedef SimObject Parent;
|
||||
private:
|
||||
StringTableEntry mGameModeName;
|
||||
StringTableEntry mGameModeDesc;
|
||||
|
||||
DECLARE_IMAGEASSET(GameMode, PreviewImage, previewChange, GFXStaticTextureSRGBProfile);
|
||||
DECLARE_ASSET_SETGET(GameMode, PreviewImage);
|
||||
|
||||
bool mIsActive;
|
||||
bool mIsAlwaysActive;
|
||||
|
||||
public:
|
||||
|
||||
GameMode();
|
||||
~GameMode() = default;
|
||||
static void initPersistFields();
|
||||
bool onAdd() override;
|
||||
void onRemove() override;
|
||||
|
||||
bool isActive() { return mIsActive; }
|
||||
void setActive(const bool& active);
|
||||
|
||||
bool isAlwaysActive() { return mIsAlwaysActive; }
|
||||
void setAlwaysActive(const bool& alwaysActive);
|
||||
|
||||
DECLARE_CONOBJECT(GameMode);
|
||||
|
||||
static void findGameModes(const char* gameModeList, Vector<GameMode*>* outGameModes);
|
||||
|
||||
void previewChange() {}
|
||||
|
||||
DECLARE_CALLBACK(void, onActivated, ());
|
||||
DECLARE_CALLBACK(void, onDeactivated, ());
|
||||
DECLARE_CALLBACK(void, onSceneLoaded, ());
|
||||
DECLARE_CALLBACK(void, onSceneUnloaded, ());
|
||||
DECLARE_CALLBACK(void, onSubsceneLoaded, (SubScene*));
|
||||
DECLARE_CALLBACK(void, onSubsceneUnloaded, (SubScene*));
|
||||
};
|
||||
|
||||
DefineConsoleType(TypeGameModeList, String)
|
||||
|
||||
#ifdef TORQUE_TOOLS
|
||||
class GuiInspectorTypeGameModeListHelper;
|
||||
|
||||
class GuiInspectorTypeGameModeList : public GuiInspectorField
|
||||
{
|
||||
typedef GuiInspectorField Parent;
|
||||
public:
|
||||
|
||||
GuiInspectorTypeGameModeListHelper* mHelper;
|
||||
GuiRolloutCtrl* mRollout;
|
||||
GuiDynamicCtrlArrayControl* mArrayCtrl;
|
||||
Vector<GuiInspectorField*> mChildren;
|
||||
|
||||
GuiBitmapButtonCtrl* mButton;
|
||||
RectI mButtonRect;
|
||||
|
||||
DECLARE_CONOBJECT(GuiInspectorTypeGameModeList);
|
||||
|
||||
GuiInspectorTypeGameModeList();
|
||||
|
||||
// ConsoleObject
|
||||
bool onAdd() override;
|
||||
static void consoleInit();
|
||||
|
||||
// GuiInspectorField
|
||||
bool resize(const Point2I& newPosition, const Point2I& newExtent) override;
|
||||
void childResized(GuiControl* child) override;
|
||||
bool updateRects() override;
|
||||
void updateData() override;
|
||||
StringTableEntry getValue() override;
|
||||
void setValue(StringTableEntry value) override;
|
||||
};
|
||||
|
||||
class GuiInspectorTypeGameModeListHelper : public GuiInspectorField
|
||||
{
|
||||
typedef GuiInspectorField Parent;
|
||||
|
||||
public:
|
||||
|
||||
GuiInspectorTypeGameModeListHelper();
|
||||
|
||||
DECLARE_CONOBJECT(GuiInspectorTypeGameModeListHelper);
|
||||
|
||||
GuiBitmapButtonCtrl* mButton;
|
||||
GuiRolloutCtrl* mParentRollout;
|
||||
GuiInspectorTypeGameModeList* mParentField;
|
||||
RectI mButtonRect;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Override able methods for custom edit fields
|
||||
//-----------------------------------------------------------------------------
|
||||
GuiControl* constructEditControl() override;
|
||||
bool resize(const Point2I& newPosition, const Point2I& newExtent) override;
|
||||
bool updateRects() override;
|
||||
void setValue(StringTableEntry value) override;
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -371,6 +371,12 @@ void Prefab::_loadFile( bool addFileNotify )
|
|||
return;
|
||||
}
|
||||
|
||||
SimObjectPtr<Scene> rootScene = Scene::getRootScene();
|
||||
if(rootScene.isValid())
|
||||
{
|
||||
rootScene->addDynamicObject(group);
|
||||
}
|
||||
|
||||
if ( addFileNotify )
|
||||
Torque::FS::AddChangeNotification( mFilename, this, &Prefab::_onFileChanged );
|
||||
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ Trigger::Trigger()
|
|||
mPhysicsRep = NULL;
|
||||
mTripOnce = false;
|
||||
mTrippedBy = 0xFFFFFFFF;
|
||||
mTripCondition = "";
|
||||
mTripIf = "";
|
||||
|
||||
//Default up a basic square
|
||||
Point3F vecs[3] = { Point3F(1.0, 0.0, 0.0),
|
||||
|
|
@ -379,7 +379,7 @@ void Trigger::initPersistFields()
|
|||
"representing the edges extending from the corner.\n");
|
||||
|
||||
addField("TripOnce", TypeBool, Offset(mTripOnce, Trigger),"Do we trigger callacks just the once?");
|
||||
addField("TripCondition", TypeRealString, Offset(mTripCondition, Trigger),"evaluation condition to trip callbacks (true/false)");
|
||||
addField("tripIf", TypeRealString, Offset(mTripIf, Trigger),"evaluation condition to trip callbacks (true/false)");
|
||||
addField("TrippedBy", TypeGameTypeMasksType, Offset(mTrippedBy, Trigger), "typemask filter");
|
||||
addProtectedField("enterCommand", TypeCommand, Offset(mEnterCommand, Trigger), &setEnterCmd, &defaultProtectedGetFn,
|
||||
"The command to execute when an object enters this trigger. Object id stored in %%obj. Maximum 1023 characters." );
|
||||
|
|
@ -697,13 +697,13 @@ bool Trigger::testTrippable()
|
|||
|
||||
bool Trigger::testCondition()
|
||||
{
|
||||
if (mTripCondition.isEmpty())
|
||||
if (mTripIf.isEmpty())
|
||||
return true; //we've got no tests to run so just do it
|
||||
|
||||
//test the mapper plugged in condition line
|
||||
String resVar = getIdString() + String(".result");
|
||||
Con::setBoolVariable(resVar.c_str(), false);
|
||||
String command = resVar + "=" + mTripCondition + ";";
|
||||
String command = resVar + "=" + mTripIf + ";";
|
||||
Con::evaluatef(command.c_str());
|
||||
if (Con::getBoolVariable(resVar.c_str()) == 1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ class Trigger : public GameBase
|
|||
bool mTripped;
|
||||
S32 mTrippedBy;
|
||||
|
||||
String mTripCondition;
|
||||
String mTripIf;
|
||||
String mEnterCommand;
|
||||
String mLeaveCommand;
|
||||
String mTickCommand;
|
||||
|
|
|
|||
|
|
@ -498,6 +498,7 @@ public:
|
|||
FIELD_ComponentInspectors = BIT(1), ///< Custom fields used by components. They are likely to be non-standard size/configuration, so
|
||||
///< They are handled specially
|
||||
FIELD_CustomInspectors = BIT(2), ///< Display as a button in inspectors.
|
||||
FIELD_SpecialtyArrayField = BIT(3)
|
||||
};
|
||||
|
||||
struct Field
|
||||
|
|
|
|||
|
|
@ -652,6 +652,31 @@ S32 PersistenceManager::getPropertyIndex(ParsedObject* parsedObject, const char*
|
|||
return propertyIndex;
|
||||
}
|
||||
|
||||
S32 PersistenceManager::getSpecialPropertyAtOffset(ParsedObject* parsedObject, const char* fieldName, U32 offsetPos)
|
||||
{
|
||||
S32 propertyIndex = -1;
|
||||
|
||||
if (!parsedObject)
|
||||
return propertyIndex;
|
||||
|
||||
U32 hitCount = -1;
|
||||
for (U32 i = 0; i < parsedObject->properties.size(); i++)
|
||||
{
|
||||
if (dStricmp(fieldName, parsedObject->properties[i].name) == 0)
|
||||
{
|
||||
hitCount++;
|
||||
|
||||
if (hitCount == offsetPos)
|
||||
{
|
||||
propertyIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return propertyIndex;
|
||||
}
|
||||
|
||||
char* PersistenceManager::getObjectIndent(ParsedObject* object)
|
||||
{
|
||||
char* indent = Con::getReturnBuffer(2048);
|
||||
|
|
@ -1361,166 +1386,335 @@ void PersistenceManager::updateObject(SimObject* object, ParsedObject* parentObj
|
|||
if ( f->type >= AbstractClassRep::ARCFirstCustomField || f->flag.test(AbstractClassRep::FieldFlags::FIELD_ComponentInspectors))
|
||||
continue;
|
||||
|
||||
for(U32 j = 0; S32(j) < f->elementCount; j++)
|
||||
if (f->flag.test(AbstractClassRep::FIELD_SpecialtyArrayField))
|
||||
{
|
||||
const char* value = getFieldValue(object, f->pFieldname, j);
|
||||
U32 fieldArraySize = object->getSpecialFieldSize(f->pFieldname);
|
||||
|
||||
// Make sure we got a value
|
||||
if (!value)
|
||||
continue;
|
||||
|
||||
// Let's see if this field is already in the file
|
||||
S32 propertyIndex = getPropertyIndex(parsedObject, f->pFieldname, j);
|
||||
|
||||
if (propertyIndex > -1)
|
||||
for(U32 j = 0; j < fieldArraySize; j++)
|
||||
{
|
||||
ParsedProperty& prop = parsedObject->properties[propertyIndex];
|
||||
const char* value = object->getSpecialFieldOut(f->pFieldname, j);
|
||||
|
||||
// If this field is on the remove list then remove it and continue
|
||||
if (findRemoveField(object, f->pFieldname, j) || !object->writeField(f->pFieldname, value))
|
||||
{
|
||||
removeField( parsedObject->properties[ propertyIndex ] );
|
||||
dFree( value );
|
||||
// Make sure we got a value
|
||||
if (!value)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Run the parsed value through the console system conditioners so
|
||||
// that it will better match the data we got back from the object.
|
||||
const char* evalue = Con::getFormattedData(f->type, prop.value, f->table, f->flag);
|
||||
// Let's see if this field is already in the file
|
||||
S32 propertyIndex = getSpecialPropertyAtOffset(parsedObject, f->pFieldname, j);
|
||||
|
||||
// If our data doesn't match then we get to update it.
|
||||
//
|
||||
// As for copy-sources, we just assume here that if a property setting
|
||||
// is there in the file, the user does not want it inherited from the copy-source
|
||||
// even in the case the actual values are identical.
|
||||
|
||||
if( dStricmp(value, evalue) != 0 )
|
||||
if (propertyIndex > -1)
|
||||
{
|
||||
if( value[ 0 ] == '\0' &&
|
||||
dStricmp( getFieldValue( defaultObject, f->pFieldname, j ), value ) == 0 &&
|
||||
( !object->getCopySource() || dStricmp( getFieldValue( object->getCopySource(), f->pFieldname, j ), value ) == 0 ) )
|
||||
ParsedProperty& prop = parsedObject->properties[propertyIndex];
|
||||
|
||||
// If this field is on the remove list then remove it and continue
|
||||
if (findRemoveField(object, f->pFieldname, j))
|
||||
{
|
||||
removeField( prop );
|
||||
removeField(parsedObject->properties[propertyIndex]);
|
||||
dFree(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Run the parsed value through the console system conditioners so
|
||||
// that it will better match the data we got back from the object.
|
||||
const char* evalue = Con::getFormattedData(f->type, prop.value, f->table, f->flag);
|
||||
|
||||
// If our data doesn't match then we get to update it.
|
||||
//
|
||||
// As for copy-sources, we just assume here that if a property setting
|
||||
// is there in the file, the user does not want it inherited from the copy-source
|
||||
// even in the case the actual values are identical.
|
||||
|
||||
if (dStricmp(value, evalue) != 0)
|
||||
{
|
||||
if (value[0] == '\0' &&
|
||||
dStricmp(getFieldValue(defaultObject, f->pFieldname, j), value) == 0 &&
|
||||
(!object->getCopySource() || dStricmp(getFieldValue(object->getCopySource(), f->pFieldname, j), value) == 0))
|
||||
{
|
||||
removeField(prop);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: This should be wrapped in a helper method... probably.
|
||||
// Detect and collapse relative path information
|
||||
if (f->type == TypeFilename ||
|
||||
f->type == TypeStringFilename ||
|
||||
f->type == TypeImageFilename ||
|
||||
f->type == TypePrefabFilename ||
|
||||
f->type == TypeShapeFilename ||
|
||||
f->type == TypeSoundFilename)
|
||||
{
|
||||
char fnBuf[1024];
|
||||
Con::collapseScriptFilename(fnBuf, 1024, value);
|
||||
|
||||
updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, fnBuf, true);
|
||||
}
|
||||
else if (f->type == TypeCommand || f->type == TypeString || f->type == TypeRealString)
|
||||
{
|
||||
char cmdBuf[1024];
|
||||
expandEscape(cmdBuf, value);
|
||||
|
||||
updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, cmdBuf, true);
|
||||
}
|
||||
else
|
||||
updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No need to process a removed field that doesn't exist in the file
|
||||
if (findRemoveField(object, f->pFieldname, j))
|
||||
{
|
||||
dFree(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool mustUpdate = false;
|
||||
|
||||
// If we didn't find the property in the ParsedObject
|
||||
// then we need to compare against the default value
|
||||
// for this property and save it out if it is different
|
||||
|
||||
const char* defaultValue = defaultObject->getSpecialFieldOut(f->pFieldname, j);
|
||||
if (!defaultValue || dStricmp(value, defaultValue) != 0)
|
||||
{
|
||||
// Value differs. Check whether it also differs from the
|
||||
// value in the copy source if there is one.
|
||||
|
||||
if (object->getCopySource())
|
||||
{
|
||||
const char* copySourceValue = getFieldValue(object->getCopySource(), f->pFieldname, j);
|
||||
if (!copySourceValue || dStricmp(copySourceValue, value) != 0)
|
||||
mustUpdate = true;
|
||||
|
||||
if (copySourceValue)
|
||||
dFree(copySourceValue);
|
||||
}
|
||||
else
|
||||
mustUpdate = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Value does not differ. If it differs from the copy source's value,
|
||||
// though, we still want to write it out as otherwise we'll see the
|
||||
// copy source's value override us.
|
||||
|
||||
if (object->getCopySource())
|
||||
{
|
||||
const char* copySourceValue = getFieldValue(object->getCopySource(), f->pFieldname, j);
|
||||
if (copySourceValue && dStricmp(copySourceValue, value) != 0)
|
||||
mustUpdate = true;
|
||||
|
||||
if (copySourceValue)
|
||||
dFree(copySourceValue);
|
||||
}
|
||||
}
|
||||
|
||||
// The default value for most string type fields is
|
||||
// NULL so we can't just continue here or we'd never ever
|
||||
// write them out...
|
||||
//
|
||||
//if (!defaultValue)
|
||||
// continue;
|
||||
|
||||
// If the object's value is different from the default
|
||||
// value then add it to the ParsedObject's newLines
|
||||
if (mustUpdate)
|
||||
{
|
||||
// TODO: This should be wrapped in a helper method... probably.
|
||||
// Detect and collapse relative path information
|
||||
if (f->type == TypeFilename ||
|
||||
f->type == TypeStringFilename ||
|
||||
f->type == TypeImageFilename ||
|
||||
f->type == TypePrefabFilename ||
|
||||
f->type == TypeShapeFilename ||
|
||||
f->type == TypeSoundFilename )
|
||||
if (f->type == TypeFilename ||
|
||||
f->type == TypeStringFilename ||
|
||||
f->type == TypeImageFilename ||
|
||||
f->type == TypePrefabFilename ||
|
||||
f->type == TypeShapeFilename ||
|
||||
f->type == TypeSoundFilename)
|
||||
{
|
||||
char fnBuf[1024];
|
||||
Con::collapseScriptFilename(fnBuf, 1024, value);
|
||||
|
||||
updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, fnBuf, true);
|
||||
newLines.push_back(createNewProperty(f->pFieldname, fnBuf, f->elementCount > 1, j));
|
||||
}
|
||||
else if (f->type == TypeCommand || f->type == TypeString || f->type == TypeRealString)
|
||||
else if (f->type == TypeCommand)
|
||||
{
|
||||
char cmdBuf[1024];
|
||||
expandEscape(cmdBuf, value);
|
||||
|
||||
updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, cmdBuf, true);
|
||||
newLines.push_back(createNewProperty(f->pFieldname, cmdBuf, f->elementCount > 1, j));
|
||||
}
|
||||
else
|
||||
updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, value, true);
|
||||
newLines.push_back(createNewProperty(f->pFieldname, value, f->elementCount > 1, j));
|
||||
}
|
||||
|
||||
if (defaultValue)
|
||||
dFree(defaultValue);
|
||||
}
|
||||
|
||||
//dFree(value);
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
for (U32 j = 0; S32(j) < f->elementCount; j++)
|
||||
{
|
||||
// No need to process a removed field that doesn't exist in the file
|
||||
if (findRemoveField(object, f->pFieldname, j) || !object->writeField(f->pFieldname, value))
|
||||
{
|
||||
dFree( value );
|
||||
const char* value = getFieldValue(object, f->pFieldname, j);
|
||||
|
||||
// Make sure we got a value
|
||||
if (!value)
|
||||
continue;
|
||||
}
|
||||
|
||||
bool mustUpdate = false;
|
||||
|
||||
// If we didn't find the property in the ParsedObject
|
||||
// then we need to compare against the default value
|
||||
// for this property and save it out if it is different
|
||||
// Let's see if this field is already in the file
|
||||
S32 propertyIndex = getPropertyIndex(parsedObject, f->pFieldname, j);
|
||||
|
||||
const char* defaultValue = getFieldValue(defaultObject, f->pFieldname, j);
|
||||
if( !defaultValue || dStricmp( value, defaultValue ) != 0 )
|
||||
if (propertyIndex > -1)
|
||||
{
|
||||
// Value differs. Check whether it also differs from the
|
||||
// value in the copy source if there is one.
|
||||
|
||||
if( object->getCopySource() )
|
||||
ParsedProperty& prop = parsedObject->properties[propertyIndex];
|
||||
|
||||
// If this field is on the remove list then remove it and continue
|
||||
if (findRemoveField(object, f->pFieldname, j) || !object->writeField(f->pFieldname, value))
|
||||
{
|
||||
const char* copySourceValue = getFieldValue( object->getCopySource(), f->pFieldname, j );
|
||||
if( !copySourceValue || dStricmp( copySourceValue, value ) != 0 )
|
||||
mustUpdate = true;
|
||||
|
||||
if( copySourceValue )
|
||||
dFree( copySourceValue );
|
||||
removeField(parsedObject->properties[propertyIndex]);
|
||||
dFree(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Run the parsed value through the console system conditioners so
|
||||
// that it will better match the data we got back from the object.
|
||||
const char* evalue = Con::getFormattedData(f->type, prop.value, f->table, f->flag);
|
||||
|
||||
// If our data doesn't match then we get to update it.
|
||||
//
|
||||
// As for copy-sources, we just assume here that if a property setting
|
||||
// is there in the file, the user does not want it inherited from the copy-source
|
||||
// even in the case the actual values are identical.
|
||||
|
||||
if (dStricmp(value, evalue) != 0)
|
||||
{
|
||||
if (value[0] == '\0' &&
|
||||
dStricmp(getFieldValue(defaultObject, f->pFieldname, j), value) == 0 &&
|
||||
(!object->getCopySource() || dStricmp(getFieldValue(object->getCopySource(), f->pFieldname, j), value) == 0))
|
||||
{
|
||||
removeField(prop);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: This should be wrapped in a helper method... probably.
|
||||
// Detect and collapse relative path information
|
||||
if (f->type == TypeFilename ||
|
||||
f->type == TypeStringFilename ||
|
||||
f->type == TypeImageFilename ||
|
||||
f->type == TypePrefabFilename ||
|
||||
f->type == TypeShapeFilename ||
|
||||
f->type == TypeSoundFilename)
|
||||
{
|
||||
char fnBuf[1024];
|
||||
Con::collapseScriptFilename(fnBuf, 1024, value);
|
||||
|
||||
updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, fnBuf, true);
|
||||
}
|
||||
else if (f->type == TypeCommand || f->type == TypeString || f->type == TypeRealString)
|
||||
{
|
||||
char cmdBuf[1024];
|
||||
expandEscape(cmdBuf, value);
|
||||
|
||||
updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, cmdBuf, true);
|
||||
}
|
||||
else
|
||||
updateToken(prop.valueLine, prop.valuePosition, prop.endPosition - prop.valuePosition, value, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
mustUpdate = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Value does not differ. If it differs from the copy source's value,
|
||||
// though, we still want to write it out as otherwise we'll see the
|
||||
// copy source's value override us.
|
||||
|
||||
if( object->getCopySource() )
|
||||
// No need to process a removed field that doesn't exist in the file
|
||||
if (findRemoveField(object, f->pFieldname, j) || !object->writeField(f->pFieldname, value))
|
||||
{
|
||||
const char* copySourceValue = getFieldValue( object->getCopySource(), f->pFieldname, j );
|
||||
if( copySourceValue && dStricmp( copySourceValue, value ) != 0 )
|
||||
dFree(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool mustUpdate = false;
|
||||
|
||||
// If we didn't find the property in the ParsedObject
|
||||
// then we need to compare against the default value
|
||||
// for this property and save it out if it is different
|
||||
|
||||
const char* defaultValue = getFieldValue(defaultObject, f->pFieldname, j);
|
||||
if (!defaultValue || dStricmp(value, defaultValue) != 0)
|
||||
{
|
||||
// Value differs. Check whether it also differs from the
|
||||
// value in the copy source if there is one.
|
||||
|
||||
if (object->getCopySource())
|
||||
{
|
||||
const char* copySourceValue = getFieldValue(object->getCopySource(), f->pFieldname, j);
|
||||
if (!copySourceValue || dStricmp(copySourceValue, value) != 0)
|
||||
mustUpdate = true;
|
||||
|
||||
if (copySourceValue)
|
||||
dFree(copySourceValue);
|
||||
}
|
||||
else
|
||||
mustUpdate = true;
|
||||
|
||||
if( copySourceValue )
|
||||
dFree( copySourceValue );
|
||||
}
|
||||
}
|
||||
|
||||
// The default value for most string type fields is
|
||||
// NULL so we can't just continue here or we'd never ever
|
||||
// write them out...
|
||||
//
|
||||
//if (!defaultValue)
|
||||
// continue;
|
||||
|
||||
// If the object's value is different from the default
|
||||
// value then add it to the ParsedObject's newLines
|
||||
if ( mustUpdate )
|
||||
{
|
||||
// TODO: This should be wrapped in a helper method... probably.
|
||||
// Detect and collapse relative path information
|
||||
if (f->type == TypeFilename ||
|
||||
f->type == TypeStringFilename ||
|
||||
f->type == TypeImageFilename ||
|
||||
f->type == TypePrefabFilename ||
|
||||
f->type == TypeShapeFilename ||
|
||||
f->type == TypeSoundFilename )
|
||||
{
|
||||
char fnBuf[1024];
|
||||
Con::collapseScriptFilename(fnBuf, 1024, value);
|
||||
|
||||
newLines.push_back(createNewProperty(f->pFieldname, fnBuf, f->elementCount > 1, j));
|
||||
}
|
||||
else if (f->type == TypeCommand)
|
||||
{
|
||||
char cmdBuf[1024];
|
||||
expandEscape(cmdBuf, value);
|
||||
|
||||
newLines.push_back(createNewProperty(f->pFieldname, cmdBuf, f->elementCount > 1, j));
|
||||
}
|
||||
else
|
||||
newLines.push_back(createNewProperty(f->pFieldname, value, f->elementCount > 1, j));
|
||||
{
|
||||
// Value does not differ. If it differs from the copy source's value,
|
||||
// though, we still want to write it out as otherwise we'll see the
|
||||
// copy source's value override us.
|
||||
|
||||
if (object->getCopySource())
|
||||
{
|
||||
const char* copySourceValue = getFieldValue(object->getCopySource(), f->pFieldname, j);
|
||||
if (copySourceValue && dStricmp(copySourceValue, value) != 0)
|
||||
mustUpdate = true;
|
||||
|
||||
if (copySourceValue)
|
||||
dFree(copySourceValue);
|
||||
}
|
||||
}
|
||||
|
||||
// The default value for most string type fields is
|
||||
// NULL so we can't just continue here or we'd never ever
|
||||
// write them out...
|
||||
//
|
||||
//if (!defaultValue)
|
||||
// continue;
|
||||
|
||||
// If the object's value is different from the default
|
||||
// value then add it to the ParsedObject's newLines
|
||||
if (mustUpdate)
|
||||
{
|
||||
// TODO: This should be wrapped in a helper method... probably.
|
||||
// Detect and collapse relative path information
|
||||
if (f->type == TypeFilename ||
|
||||
f->type == TypeStringFilename ||
|
||||
f->type == TypeImageFilename ||
|
||||
f->type == TypePrefabFilename ||
|
||||
f->type == TypeShapeFilename ||
|
||||
f->type == TypeSoundFilename)
|
||||
{
|
||||
char fnBuf[1024];
|
||||
Con::collapseScriptFilename(fnBuf, 1024, value);
|
||||
|
||||
newLines.push_back(createNewProperty(f->pFieldname, fnBuf, f->elementCount > 1, j));
|
||||
}
|
||||
else if (f->type == TypeCommand)
|
||||
{
|
||||
char cmdBuf[1024];
|
||||
expandEscape(cmdBuf, value);
|
||||
|
||||
newLines.push_back(createNewProperty(f->pFieldname, cmdBuf, f->elementCount > 1, j));
|
||||
}
|
||||
else
|
||||
newLines.push_back(createNewProperty(f->pFieldname, value, f->elementCount > 1, j));
|
||||
}
|
||||
|
||||
if (defaultValue)
|
||||
dFree(defaultValue);
|
||||
}
|
||||
|
||||
if (defaultValue)
|
||||
dFree( defaultValue );
|
||||
dFree(value);
|
||||
}
|
||||
|
||||
dFree( value );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -221,6 +221,12 @@ protected:
|
|||
// Attempts to look up the property in the ParsedObject
|
||||
S32 getPropertyIndex(ParsedObject* parsedObject, const char* fieldName, U32 arrayPos = 0);
|
||||
|
||||
// Attempts to look up the special array property in the ParsedObject
|
||||
// This is distinct from getPropertyIndex because while that assumes it's an array'd field
|
||||
// This figures the property in question is one that is specially tagged for implicit, arbitrarily sized lists
|
||||
// Like ConvexShape's 'surfaces' or a spline's 'node' properties
|
||||
S32 getSpecialPropertyAtOffset(ParsedObject* parsedObject, const char* fieldName, U32 offsetPos);
|
||||
|
||||
// Gets the amount of indent on the ParsedObject.
|
||||
char* getObjectIndent(ParsedObject* object);
|
||||
|
||||
|
|
@ -320,4 +326,4 @@ public:
|
|||
DECLARE_CONOBJECT(PersistenceManager);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ SimObjectId SimObject::smForcedId = 0;
|
|||
bool SimObject::preventNameChanging = false;
|
||||
|
||||
IMPLEMENT_CALLBACK(SimObject, onInspectPostApply, void, (SimObject* obj), (obj), "Generic callback for when an object is edited");
|
||||
IMPLEMENT_CALLBACK(SimObject, onSelected, void, (SimObject* obj), (obj), "Generic callback for when an object is selected");
|
||||
IMPLEMENT_CALLBACK(SimObject, onUnselected, void, (SimObject* obj), (obj), "Generic callback for when an object is un-selected");
|
||||
|
||||
namespace Sim
|
||||
{
|
||||
|
|
@ -527,6 +529,14 @@ bool SimObject::save(const char *pcFileName, bool bOnlySelected, const char *pre
|
|||
|
||||
}
|
||||
|
||||
bool SimObject::saveAppend(const char* pcFileName, bool bOnlySelected, const char* preappend)
|
||||
{
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
SimPersistID* SimObject::getOrCreatePersistentId()
|
||||
|
|
@ -2207,11 +2217,13 @@ void SimObject::setSelected( bool sel )
|
|||
{
|
||||
mFlags.set( Selected );
|
||||
_onSelected();
|
||||
onSelected_callback(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
mFlags.clear( Selected );
|
||||
_onUnselected();
|
||||
onUnselected_callback(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -530,6 +530,9 @@ class SimObject: public ConsoleObject, public TamlCallbacks
|
|||
void setDataFieldType(const U32 fieldTypeId, StringTableEntry slotName, const char *array);
|
||||
void setDataFieldType(const char *typeName, StringTableEntry slotName, const char *array);
|
||||
|
||||
virtual U32 getSpecialFieldSize(StringTableEntry fieldName) { return 0; }
|
||||
virtual const char* getSpecialFieldOut(StringTableEntry fieldName, const U32& index) { return NULL; }
|
||||
|
||||
/// Get reference to the dictionary containing dynamic fields.
|
||||
///
|
||||
/// See @ref simobject_console "here" for a detailed discussion of what this
|
||||
|
|
@ -579,6 +582,7 @@ class SimObject: public ConsoleObject, public TamlCallbacks
|
|||
|
||||
/// Save object as a TorqueScript File.
|
||||
virtual bool save( const char* pcFilePath, bool bOnlySelected = false, const char *preappend = NULL );
|
||||
virtual bool saveAppend(const char* pcFilePath, bool bOnlySelected = false, const char* preappend = NULL);
|
||||
|
||||
/// Check if a method exists in the objects current namespace.
|
||||
virtual bool isMethod( const char* methodName );
|
||||
|
|
@ -981,6 +985,8 @@ class SimObject: public ConsoleObject, public TamlCallbacks
|
|||
|
||||
DECLARE_CONOBJECT( SimObject );
|
||||
DECLARE_CALLBACK(void, onInspectPostApply, (SimObject* obj));
|
||||
DECLARE_CALLBACK(void, onSelected, (SimObject* obj));
|
||||
DECLARE_CALLBACK(void, onUnselected, (SimObject* obj));
|
||||
|
||||
static SimObject* __findObject( const char* id ) { return Sim::findObject( id ); }
|
||||
static const char* __getObjectId( ConsoleObject* object )
|
||||
|
|
|
|||
|
|
@ -372,6 +372,13 @@ class GuiControl : public SimGroup
|
|||
|
||||
inline const S32 getHorizSizing() const { return mHorizSizing; }
|
||||
inline const S32 getVertSizing() const { return mVertSizing; }
|
||||
|
||||
void setHorizSizing(horizSizingOptions horizSizing) {
|
||||
mHorizSizing = horizSizing;
|
||||
}
|
||||
void setVertSizing(vertSizingOptions vertSizing) {
|
||||
mVertSizing = vertSizing;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ GuiInspectorField* GuiInspectorGroup::constructField( S32 fieldType )
|
|||
|
||||
// return our new datablock field with correct datablock type enumeration info
|
||||
return dbFieldClass;
|
||||
}
|
||||
}
|
||||
|
||||
// Nope, not a datablock. So maybe it has a valid inspector field override we can use?
|
||||
if(!cbt->getInspectorFieldType())
|
||||
|
|
@ -641,40 +641,50 @@ void GuiInspectorGroup::addInspectorField(StringTableEntry name, StringTableEntr
|
|||
{
|
||||
S32 fieldType = -1;
|
||||
|
||||
if (typeName == StringTable->insert("int"))
|
||||
fieldType = TypeS32;
|
||||
else if (typeName == StringTable->insert("float"))
|
||||
fieldType = TypeF32;
|
||||
else if (typeName == StringTable->insert("vector"))
|
||||
fieldType = TypePoint3F;
|
||||
else if (typeName == StringTable->insert("vector2"))
|
||||
fieldType = TypePoint2F;
|
||||
else if (typeName == StringTable->insert("material"))
|
||||
fieldType = TypeMaterialAssetId;
|
||||
else if (typeName == StringTable->insert("image"))
|
||||
fieldType = TypeImageAssetId;
|
||||
else if (typeName == StringTable->insert("shape"))
|
||||
fieldType = TypeShapeAssetId;
|
||||
else if (typeName == StringTable->insert("sound"))
|
||||
fieldType = TypeSoundAssetId;
|
||||
else if (typeName == StringTable->insert("bool"))
|
||||
fieldType = TypeBool;
|
||||
else if (typeName == StringTable->insert("object"))
|
||||
fieldType = TypeSimObjectPtr;
|
||||
else if (typeName == StringTable->insert("string"))
|
||||
fieldType = TypeString;
|
||||
else if (typeName == StringTable->insert("colorI"))
|
||||
fieldType = TypeColorI;
|
||||
else if (typeName == StringTable->insert("colorF"))
|
||||
fieldType = TypeColorF;
|
||||
else if (typeName == StringTable->insert("ease"))
|
||||
fieldType = TypeEaseF;
|
||||
else if (typeName == StringTable->insert("command"))
|
||||
fieldType = TypeCommand;
|
||||
else if (typeName == StringTable->insert("filename"))
|
||||
fieldType = TypeStringFilename;
|
||||
String typeNameTyped = typeName;
|
||||
if (!typeNameTyped.startsWith("Type"))
|
||||
typeNameTyped = String("Type") + typeNameTyped;
|
||||
|
||||
ConsoleBaseType* typeRef = AbstractClassRep::getTypeByName(typeNameTyped.c_str());
|
||||
if(typeRef)
|
||||
{
|
||||
fieldType = typeRef->getTypeID();
|
||||
}
|
||||
else
|
||||
fieldType = -1;
|
||||
{
|
||||
if (typeName == StringTable->insert("int"))
|
||||
fieldType = TypeS32;
|
||||
else if (typeName == StringTable->insert("float"))
|
||||
fieldType = TypeF32;
|
||||
else if (typeName == StringTable->insert("vector"))
|
||||
fieldType = TypePoint3F;
|
||||
else if (typeName == StringTable->insert("vector2"))
|
||||
fieldType = TypePoint2F;
|
||||
else if (typeName == StringTable->insert("material"))
|
||||
fieldType = TypeMaterialAssetId;
|
||||
else if (typeName == StringTable->insert("image"))
|
||||
fieldType = TypeImageAssetId;
|
||||
else if (typeName == StringTable->insert("shape"))
|
||||
fieldType = TypeShapeAssetId;
|
||||
else if (typeName == StringTable->insert("sound"))
|
||||
fieldType = TypeSoundAssetId;
|
||||
else if (typeName == StringTable->insert("bool"))
|
||||
fieldType = TypeBool;
|
||||
else if (typeName == StringTable->insert("object"))
|
||||
fieldType = TypeSimObjectPtr;
|
||||
else if (typeName == StringTable->insert("string"))
|
||||
fieldType = TypeString;
|
||||
else if (typeName == StringTable->insert("colorI"))
|
||||
fieldType = TypeColorI;
|
||||
else if (typeName == StringTable->insert("colorF"))
|
||||
fieldType = TypeColorF;
|
||||
else if (typeName == StringTable->insert("ease"))
|
||||
fieldType = TypeEaseF;
|
||||
else if (typeName == StringTable->insert("command"))
|
||||
fieldType = TypeCommand;
|
||||
else if (typeName == StringTable->insert("filename"))
|
||||
fieldType = TypeStringFilename;
|
||||
}
|
||||
|
||||
GuiInspectorField* fieldGui;
|
||||
|
||||
|
|
|
|||
|
|
@ -176,38 +176,53 @@ void GuiVariableInspector::addField(const char* name, const char* label, const c
|
|||
//find the field type
|
||||
S32 fieldTypeMask = -1;
|
||||
|
||||
if (newField->mFieldTypeName == StringTable->insert("int"))
|
||||
fieldTypeMask = TypeS32;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("float"))
|
||||
fieldTypeMask = TypeF32;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("vector"))
|
||||
fieldTypeMask = TypePoint3F;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("vector2"))
|
||||
fieldTypeMask = TypePoint2F;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("material"))
|
||||
fieldTypeMask = TypeMaterialAssetId;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("image"))
|
||||
fieldTypeMask = TypeImageAssetId;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("shape"))
|
||||
fieldTypeMask = TypeShapeAssetId;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("bool"))
|
||||
fieldTypeMask = TypeBool;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("object"))
|
||||
fieldTypeMask = TypeSimObjectPtr;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("string"))
|
||||
fieldTypeMask = TypeString;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("colorI"))
|
||||
fieldTypeMask = TypeColorI;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("colorF"))
|
||||
fieldTypeMask = TypeColorF;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("ease"))
|
||||
fieldTypeMask = TypeEaseF;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("command"))
|
||||
fieldTypeMask = TypeCommand;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("filename"))
|
||||
fieldTypeMask = TypeStringFilename;
|
||||
String typeNameTyped = typeName;
|
||||
if (!typeNameTyped.startsWith("Type"))
|
||||
typeNameTyped = String("Type") + typeNameTyped;
|
||||
|
||||
ConsoleBaseType* typeRef = AbstractClassRep::getTypeByName(typeNameTyped.c_str());
|
||||
if (typeRef)
|
||||
{
|
||||
fieldTypeMask = typeRef->getTypeID();
|
||||
|
||||
if (!typeRef->getInspectorFieldType())
|
||||
fieldTypeMask = TypeString;
|
||||
|
||||
newField->mFieldTypeName = StringTable->insert(typeRef->getTypeName());
|
||||
}
|
||||
else
|
||||
fieldTypeMask = -1;
|
||||
{
|
||||
if (newField->mFieldTypeName == StringTable->insert("int"))
|
||||
fieldTypeMask = TypeS32;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("float"))
|
||||
fieldTypeMask = TypeF32;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("vector"))
|
||||
fieldTypeMask = TypePoint3F;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("vector2"))
|
||||
fieldTypeMask = TypePoint2F;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("material"))
|
||||
fieldTypeMask = TypeMaterialAssetId;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("image"))
|
||||
fieldTypeMask = TypeImageAssetId;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("shape"))
|
||||
fieldTypeMask = TypeShapeAssetId;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("bool"))
|
||||
fieldTypeMask = TypeBool;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("object"))
|
||||
fieldTypeMask = TypeSimObjectPtr;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("string"))
|
||||
fieldTypeMask = TypeString;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("colorI"))
|
||||
fieldTypeMask = TypeColorI;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("colorF"))
|
||||
fieldTypeMask = TypeColorF;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("ease"))
|
||||
fieldTypeMask = TypeEaseF;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("command"))
|
||||
fieldTypeMask = TypeCommand;
|
||||
else if (newField->mFieldTypeName == StringTable->insert("filename"))
|
||||
fieldTypeMask = TypeStringFilename;
|
||||
}
|
||||
|
||||
newField->mFieldType = fieldTypeMask;
|
||||
//
|
||||
|
|
|
|||
|
|
@ -1724,7 +1724,7 @@ void SceneObject::updateRenderChangesByParent(){
|
|||
MatrixF offset;
|
||||
offset.mul(renderXform, xform);
|
||||
|
||||
MatrixF mat;
|
||||
MatrixF mat;
|
||||
|
||||
//add the "offset" caused by the parents change, and add it to it's own
|
||||
// This is needed by objects that update their own render transform thru interpolate tick
|
||||
|
|
@ -2013,3 +2013,8 @@ void SceneObject::onNewParent(SceneObject *newParent) { if (isServerObject()) on
|
|||
void SceneObject::onLostParent(SceneObject *oldParent) { if (isServerObject()) onLostParent_callback(oldParent); }
|
||||
void SceneObject::onNewChild(SceneObject *newKid) { if (isServerObject()) onNewChild_callback(newKid); }
|
||||
void SceneObject::onLostChild(SceneObject *lostKid) { if (isServerObject()) onLostChild_callback(lostKid); }
|
||||
|
||||
IMPLEMENT_CALLBACK(SceneObject, onSaving, void, (const char* fileName), (fileName),
|
||||
"@brief Called when a saving is occuring to allow objects to special-handle prepwork for saving if required.\n\n"
|
||||
|
||||
"@param fileName The level file being saved\n");
|
||||
|
|
|
|||
|
|
@ -913,6 +913,8 @@ class SceneObject : public NetObject, public ProcessObject
|
|||
DECLARE_CALLBACK(void, onLostChild, (SceneObject *subObject));
|
||||
// PATHSHAPE END
|
||||
|
||||
DECLARE_CALLBACK(void, onSaving, (const char* fileName));
|
||||
|
||||
virtual void getUtilizedAssets(Vector<StringTableEntry>* usedAssetsList) {}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue