mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 04:34:48 +00:00
Merge branch 'SubScenes_Gamemode_PR' of https://github.com/Areloch/Torque3D into development
This commit is contained in:
commit
dde0ffe32f
|
|
@ -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
|
||||
|
|
@ -175,12 +166,58 @@ void Scene::removeDynamicObject(SceneObject* 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)
|
||||
|
|
@ -257,6 +294,38 @@ bool Scene::saveScene(StringTableEntry fileName)
|
|||
fileName = getOriginatingFile();
|
||||
}
|
||||
|
||||
//Inform our objects we're saving, so if they do any special stuff
|
||||
//they can do it before the actual write-out
|
||||
for (SimGroup::iterator itr = begin(); itr != end(); itr++)
|
||||
{
|
||||
SimGroup* sg = dynamic_cast<SimGroup*>(*itr);
|
||||
if (sg)
|
||||
{
|
||||
ConsoleValue vars[3];
|
||||
vars[2].setString(fileName);
|
||||
sg->callOnChildren("onSaving", 3, vars);
|
||||
}
|
||||
|
||||
SceneObject* sO = dynamic_cast<SceneObject*>(*itr);
|
||||
if (sO)
|
||||
{
|
||||
sO->onSaving_callback(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
/*for (U32 i = 0; i < mPermanentObjects.size(); i++)
|
||||
{
|
||||
SceneObject* obj = mPermanentObjects[i];
|
||||
obj->onSaving_callback(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 +355,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 +386,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 +500,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,14 +27,11 @@ 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;
|
||||
|
||||
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;
|
||||
|
|
@ -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
|
||||
|
|
|
|||
352
Engine/source/T3D/SceneGroup.cpp
Normal file
352
Engine/source/T3D/SceneGroup.cpp
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
#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("SceneGroup"));
|
||||
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)
|
||||
{
|
||||
//transform difference
|
||||
MatrixF oldTransform = getTransform();
|
||||
|
||||
Parent::setTransform(mat);
|
||||
|
||||
// Calculate the delta transformation
|
||||
MatrixF deltaTransform;
|
||||
oldTransform.inverse();
|
||||
deltaTransform.mul(oldTransform, getTransform());
|
||||
|
||||
if (isServerObject())
|
||||
{
|
||||
setMaskBits(TransformMask);
|
||||
|
||||
// Update all child transforms
|
||||
for (SimSetIterator itr(this); *itr; ++itr)
|
||||
{
|
||||
SceneObject* child = dynamic_cast<SceneObject*>(*itr);
|
||||
if (child)
|
||||
{
|
||||
MatrixF childTransform = child->getTransform();
|
||||
MatrixF relativeTransform;
|
||||
relativeTransform.mul(deltaTransform, childTransform);
|
||||
child->setTransform(relativeTransform);
|
||||
child->setScale(childTransform.getScale()); //we don't modify scale
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneGroup::setRenderTransform(const MatrixF& mat)
|
||||
{
|
||||
//transform difference
|
||||
MatrixF oldTransform = getRenderTransform();
|
||||
|
||||
Parent::setRenderTransform(mat);
|
||||
|
||||
// Calculate the delta transformation
|
||||
MatrixF deltaTransform;
|
||||
oldTransform.inverse();
|
||||
deltaTransform.mul(oldTransform, getRenderTransform());
|
||||
|
||||
// Update all child transforms
|
||||
for (SimSetIterator itr(this); *itr; ++itr)
|
||||
{
|
||||
SceneObject* child = dynamic_cast<SceneObject*>(*itr);
|
||||
if (child)
|
||||
{
|
||||
MatrixF childTransform = child->getRenderTransform();
|
||||
MatrixF relativeTransform;
|
||||
relativeTransform.mul(deltaTransform, childTransform);
|
||||
child->setRenderTransform(relativeTransform);
|
||||
child->setScale(childTransform.getScale()); //we don't modify scale
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
446
Engine/source/T3D/SubScene.cpp
Normal file
446
Engine/source/T3D/SubScene.cpp
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
#include "SubScene.h"
|
||||
|
||||
#include "gameMode.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"
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(SubScene);
|
||||
|
||||
S32 SubScene::mUnloadTimeoutMs = 5000;
|
||||
|
||||
SubScene::SubScene() :
|
||||
mLevelAssetId(StringTable->EmptyString()),
|
||||
mGameModesNames(StringTable->EmptyString()),
|
||||
mScopeDistance(-1),
|
||||
mLoaded(false),
|
||||
mGlobalLayer(false)
|
||||
{
|
||||
mNetFlags.set(Ghostable | ScopeAlways);
|
||||
|
||||
mTypeMask |= StaticObjectType;
|
||||
}
|
||||
|
||||
SubScene::~SubScene()
|
||||
{
|
||||
}
|
||||
|
||||
bool SubScene::onAdd()
|
||||
{
|
||||
if (!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SubScene::onRemove()
|
||||
{
|
||||
if (isClientObject())
|
||||
removeFromScene();
|
||||
|
||||
Parent::onRemove();
|
||||
}
|
||||
|
||||
void SubScene::initPersistFields()
|
||||
{
|
||||
addGroup("SubScene");
|
||||
addField("isGlobalLayer", TypeBool, Offset(mGlobalLayer, SubScene), "");
|
||||
INITPERSISTFIELD_LEVELASSET(Level, SubScene, "The level asset to load.");
|
||||
addField("loadIf", TypeCommand, Offset(mLoadIf, SubScene), "evaluation condition (true/false)");
|
||||
addField("gameModes", TypeGameModeList, Offset(mGameModesNames, SubScene), "The game modes that this subscene is associated with.");
|
||||
endGroup("SubScene");
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool SubScene::testBox(const Box3F& testBox)
|
||||
{
|
||||
if (mGlobalLayer)
|
||||
return true;
|
||||
|
||||
bool passes = getWorldBox().isOverlapped(testBox);
|
||||
if (passes && !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());
|
||||
passes = Con::getBoolVariable(resVar.c_str());
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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::_closeFile(bool removeFileNotify)
|
||||
{
|
||||
AssertFatal(isServerObject(), "Trying to close out a subscene file on the client is bad!");
|
||||
|
||||
U32 count = size();
|
||||
|
||||
for (SimSetIterator itr(this); *itr; ++itr)
|
||||
{
|
||||
SimObject* child = dynamic_cast<SimObject*>(*itr);
|
||||
|
||||
if (child)
|
||||
child->safeDeleteObject();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
_loadFile(true);
|
||||
mLoaded = true;
|
||||
|
||||
GameMode::findGameModes(mGameModesNames, &mGameModesList);
|
||||
|
||||
for (U32 i = 0; i < mGameModesList.size(); i++)
|
||||
{
|
||||
mGameModesList[i]->onSubsceneLoaded_callback();
|
||||
}
|
||||
}
|
||||
|
||||
void SubScene::unload()
|
||||
{
|
||||
if (!mLoaded)
|
||||
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 (SimSetIterator itr(this); *itr; ++itr)
|
||||
{
|
||||
SimGroup* childGrp = dynamic_cast<SimGroup*>(*itr);
|
||||
if (childGrp && childGrp->isSelected())
|
||||
{
|
||||
mStartUnloadTimerMS = Sim::getCurrentTime();
|
||||
return; //if a child is selected, then we don't want to unload
|
||||
}
|
||||
|
||||
for (SimSetIterator 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_closeFile(true);
|
||||
mLoaded = false;
|
||||
|
||||
for (U32 i = 0; i < mGameModesList.size(); i++)
|
||||
{
|
||||
mGameModesList[i]->onSubsceneUnloaded_callback();
|
||||
}
|
||||
}
|
||||
|
||||
bool SubScene::save()
|
||||
{
|
||||
//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();
|
||||
|
||||
StringTableEntry levelPath = mLevelAsset->getLevelPath();
|
||||
|
||||
for (SimGroup::iterator itr = begin(); itr != end(); itr++)
|
||||
{
|
||||
//Inform our objects we're saving, so if they do any special stuff
|
||||
//they can do it before the actual write-out
|
||||
SimGroup* sg = dynamic_cast<SimGroup*>(*itr);
|
||||
if (sg)
|
||||
{
|
||||
ConsoleValue vars[3];
|
||||
vars[2].setString(mLevelAssetId);
|
||||
sg->callOnChildren("onSaving", 3, vars);
|
||||
}
|
||||
|
||||
SceneObject* scO = dynamic_cast<SceneObject*>(*itr);
|
||||
if (scO)
|
||||
{
|
||||
scO->onSaving_callback(mLevelAssetId);
|
||||
}
|
||||
|
||||
SimObject* sO = static_cast<SimObject*>(*itr);
|
||||
if (!sO->save(levelPath))
|
||||
{
|
||||
Con::errorf("SubScene::save() - error, failed to write object %s to file: %s", sO->getIdString(), levelPath);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//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();
|
||||
}
|
||||
109
Engine/source/T3D/SubScene.h
Normal file
109
Engine/source/T3D/SubScene.h
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
#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
|
||||
#ifndef GAME_MODE_H
|
||||
#include "gameMode.h"
|
||||
#endif
|
||||
|
||||
class SubScene : public SceneGroup
|
||||
{
|
||||
typedef SceneGroup Parent;
|
||||
|
||||
public:
|
||||
enum MaskBits
|
||||
{
|
||||
NextFreeMask = Parent::NextFreeMask << 0
|
||||
};
|
||||
|
||||
void onLevelChanged() {}
|
||||
|
||||
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;
|
||||
String mLoadIf;
|
||||
|
||||
bool mGlobalLayer;
|
||||
public:
|
||||
SubScene();
|
||||
virtual ~SubScene();
|
||||
|
||||
DECLARE_CONOBJECT(SubScene);
|
||||
DECLARE_CATEGORY("Object \t Collection");
|
||||
|
||||
static void initPersistFields();
|
||||
static void consoleInit();
|
||||
|
||||
// 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;
|
||||
|
||||
bool testBox(const Box3F& testBox);
|
||||
|
||||
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 _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_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_
|
||||
|
||||
|
|
|
|||
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, (), (),
|
||||
"@brief Called when a subScene has been loaded and has game mode implications.\n\n");
|
||||
IMPLEMENT_CALLBACK(GameMode, onSubsceneUnloaded, void, (), (),
|
||||
"@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
|
||||
114
Engine/source/T3D/gameMode.h
Normal file
114
Engine/source/T3D/gameMode.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#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
|
||||
|
||||
|
||||
#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, ());
|
||||
DECLARE_CALLBACK(void, onSubsceneUnloaded, ());
|
||||
};
|
||||
|
||||
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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -325,6 +325,8 @@ function replaceInFile(%fileName, %fromWord, %toWord)
|
|||
//Go through our scriptfile and replace the old namespace with the new
|
||||
%editedFileContents = "";
|
||||
|
||||
%lineArray = new ArrayObject(){};
|
||||
|
||||
%file = new FileObject();
|
||||
if ( %file.openForRead( %fileName ) )
|
||||
{
|
||||
|
|
@ -334,6 +336,8 @@ function replaceInFile(%fileName, %fromWord, %toWord)
|
|||
%line = trim( %line );
|
||||
|
||||
%editedFileContents = %editedFileContents @ strreplace(%line, %fromWord, %toWord) @ "\n";
|
||||
|
||||
%lineArray.add(strreplace(%line, %fromWord, %toWord));
|
||||
}
|
||||
|
||||
%file.close();
|
||||
|
|
@ -341,12 +345,18 @@ function replaceInFile(%fileName, %fromWord, %toWord)
|
|||
|
||||
if(%editedFileContents !$= "")
|
||||
{
|
||||
%file.openForWrite(%fileName);
|
||||
|
||||
%file.writeline(%editedFileContents);
|
||||
|
||||
%file.close();
|
||||
if( %file.openForWrite(%fileName) )
|
||||
{
|
||||
for(%i=0; %i < %lineArray.getCount(); %i++)
|
||||
{
|
||||
%file.writeline(%lineArray.getKey(%i));
|
||||
}
|
||||
|
||||
%file.close();
|
||||
}
|
||||
}
|
||||
|
||||
%lineArray.delete();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -1,52 +1,22 @@
|
|||
function callGamemodeFunction(%gameModeFuncName, %arg0, %arg1, %arg2, %arg3, %arg4, %arg5, %arg6)
|
||||
{
|
||||
%activeSceneCount = getSceneCount();
|
||||
|
||||
%hasGameMode = 0;
|
||||
for(%i=0; %i < %activeSceneCount; %i++)
|
||||
%validGameModeCall = false;
|
||||
%gamemodeList = getGameModesList();
|
||||
%gameModeCount = %gamemodeList.count();
|
||||
for(%i=0; %i < %gameModeCount; %i++)
|
||||
{
|
||||
%gamemodeName = getScene(%i).gameModeName;
|
||||
if(%gamemodeName !$= "")
|
||||
%gameModeObj = %gamemodeList.getKey(%i);
|
||||
%active = %gamemodeList.getValue(%i);
|
||||
|
||||
if(!isObject(%gameModeObj) || !%active)
|
||||
continue;
|
||||
|
||||
if(%gameModeObj.isMethod(%gameModeFuncName))
|
||||
{
|
||||
//if the scene defines a game mode, go ahead and envoke it here
|
||||
if(isObject(%gamemodeName) && %gamemodeName.isMethod(%gameModeFuncName))
|
||||
{
|
||||
eval(%gamemodeName @ "."@%gameModeFuncName@"(\""@%arg0@"\", \""@%arg1@"\", \""@%arg2@"\", \""@%arg3@"\", \""@%arg4@"\", \""@%arg5@"\", \""@%arg6@"\");" );
|
||||
%hasGameMode = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if we don't have an object, attempt the static call
|
||||
if(isMethod(%gamemodeName, %gameModeFuncName))
|
||||
{
|
||||
eval(%gamemodeName @ "::"@%gameModeFuncName@"(\""@%arg0@"\", \""@%arg1@"\", \""@%arg2@"\", \""@%arg3@"\", \""@%arg4@"\", \""@%arg5@"\", \""@%arg6@"\");" );
|
||||
%hasGameMode = 1;
|
||||
}
|
||||
}
|
||||
eval(%gameModeObj @ "."@%gameModeFuncName@"(\""@%arg0@"\", \""@%arg1@"\", \""@%arg2@"\", \""@%arg3@"\", \""@%arg4@"\", \""@%arg5@"\", \""@%arg6@"\");" );
|
||||
%validGameModeCall = true;
|
||||
}
|
||||
}
|
||||
|
||||
//if none of our scenes have gamemodes, we need to kick off a default
|
||||
if(%hasGameMode == 0)
|
||||
{
|
||||
%defaultModeName = ProjectSettings.value("Gameplay/GameModes/defaultModeName");
|
||||
if(%defaultModeName !$= "")
|
||||
{
|
||||
if(isObject(%defaultModeName) && %defaultModeName.isMethod(%gameModeFuncName))
|
||||
{
|
||||
eval(%defaultModeName @ "."@%gameModeFuncName@"(\""@%arg0@"\", \""@%arg1@"\", \""@%arg2@"\", \""@%arg3@"\", \""@%arg4@"\", \""@%arg5@"\", \""@%arg6@"\");" );
|
||||
%hasGameMode = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isMethod(%defaultModeName, %gameModeFuncName))
|
||||
{
|
||||
eval(%defaultModeName @ "::"@%gameModeFuncName@"(\""@%arg0@"\", \""@%arg1@"\", \""@%arg2@"\", \""@%arg3@"\", \""@%arg4@"\", \""@%arg5@"\", \""@%arg6@"\");" );
|
||||
%hasGameMode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return %hasGameMode;
|
||||
return %validGameModeCall;
|
||||
}
|
||||
|
|
@ -9,25 +9,12 @@ function ExampleModule::onDestroy(%this)
|
|||
//This is called when the server is initially set up by the game application
|
||||
function ExampleModule::initServer(%this)
|
||||
{
|
||||
%this.queueExec("./scripts/server/ExampleGameMode");
|
||||
%this.queueExec("./scripts/shared/ExampleGameMode");
|
||||
}
|
||||
|
||||
//This is called when the server is created for an actual game/map to be played
|
||||
function ExampleModule::onCreateGameServer(%this)
|
||||
{
|
||||
//These are common managed data files. For any datablock-based stuff that gets generated by the editors
|
||||
//(that doesn't have a specific associated file, like data for a player class) will go into these.
|
||||
//So we'll register them now if they exist.
|
||||
if(isFile("./scripts/managedData/managedDatablocks." @ $TorqueScriptFileExtension))
|
||||
%this.registerDatablock("./scripts/managedData/managedDatablocks");
|
||||
if(isFile("./scripts/managedData/managedForestItemData." @ $TorqueScriptFileExtension))
|
||||
%this.registerDatablock("./scripts/managedData/managedForestItemData");
|
||||
if(isFile("./scripts/managedData/managedForestBrushData." @ $TorqueScriptFileExtension))
|
||||
%this.registerDatablock("./scripts/managedData/managedForestBrushData");
|
||||
if(isFile("./scripts/managedData/managedParticleData." @ $TorqueScriptFileExtension))
|
||||
%this.registerDatablock("./scripts/managedData/managedParticleData");
|
||||
if(isFile("./scripts/managedData/managedParticleEmitterData." @ $TorqueScriptFileExtension))
|
||||
%this.registerDatablock("./scripts/managedData/managedParticleEmitterData");
|
||||
}
|
||||
|
||||
//This is called when the server is shut down due to the game/map being exited
|
||||
|
|
@ -38,7 +25,7 @@ function ExampleModule::onDestroyGameServer(%this)
|
|||
//This is called when the client is initially set up by the game application
|
||||
function ExampleModule::initClient(%this)
|
||||
{
|
||||
%this.queueExec("./scripts/client/inputCommands");
|
||||
%this.queueExec("./scripts/client/inputCommands");
|
||||
|
||||
//client scripts
|
||||
exec("./scripts/client/defaultkeybinds");
|
||||
|
|
@ -46,6 +33,8 @@ function ExampleModule::initClient(%this)
|
|||
%prefPath = getPrefpath();
|
||||
if(isScriptFile(%prefPath @ "/keybinds"))
|
||||
exec(%prefPath @ "/keybinds");
|
||||
|
||||
%this.queueExec("./scripts/shared/ExampleGameMode");
|
||||
}
|
||||
|
||||
//This is called when a client connects to a server
|
||||
|
|
|
|||
|
|
@ -8,4 +8,5 @@
|
|||
ForestFile="@assetFile=ExampleLevel.forest"
|
||||
NavmeshFile="@assetFile=ExampleLevel.nav"
|
||||
staticObjectAssetDependency0="@asset=Prototyping:FloorGray"
|
||||
gameModesNames="ExampleGameMode;"
|
||||
VersionId="1"/>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
function ExampleGameMode::onCreateGame()
|
||||
{
|
||||
// Note: The Game object will be cleaned up by MissionCleanup. Therefore its lifetime is
|
||||
// limited to that of the mission.
|
||||
new ScriptObject(ExampleGameMode){};
|
||||
|
||||
return ExampleGameMode;
|
||||
}
|
||||
if(!isObject(ExampleGameMode))
|
||||
new GameMode(ExampleGameMode){};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The server has started up so do some game start up
|
||||
|
|
@ -159,6 +153,30 @@ function ExampleGameMode::onInitialControlSet(%this)
|
|||
|
||||
}
|
||||
|
||||
function ExampleGameMode::onSceneLoaded(%this)
|
||||
{
|
||||
echo("===================================");
|
||||
echo("ExampleGameMode - Scene is loaded");
|
||||
}
|
||||
|
||||
function ExampleGameMode::onSceneUnloaded(%this)
|
||||
{
|
||||
echo("===================================");
|
||||
echo("ExampleGameMode - Scene is unloaded");
|
||||
}
|
||||
|
||||
function ExampleGameMode::onSubsceneLoaded(%this)
|
||||
{
|
||||
echo("===================================");
|
||||
echo("ExampleGameMode - Subscene is loaded");
|
||||
}
|
||||
|
||||
function ExampleGameMode::onSubsceneUnloaded(%this)
|
||||
{
|
||||
echo("===================================");
|
||||
echo("ExampleGameMode - Subscene is unloaded");
|
||||
}
|
||||
|
||||
function ExampleGameMode::spawnCamera(%this, %client, %spawnPoint)
|
||||
{
|
||||
// Set the control object to the default camera
|
||||
|
|
@ -9,8 +9,8 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
|
|||
tooltipProfile = "GuiToolTipProfile";
|
||||
isContainer = "1";
|
||||
canSaveDynamicFields = "1";
|
||||
currentMenuIdx = "0";
|
||||
launchInEditor = "0";
|
||||
previewButtonSize = "445 120";
|
||||
|
||||
new GuiInputCtrl(ChooseLevelInputHandler) {
|
||||
ignoreMouseEvents = "1";
|
||||
|
|
@ -43,39 +43,50 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
|
|||
extent = "310 41";
|
||||
horizSizing = "center";
|
||||
profile = "GuiDefaultProfile";
|
||||
visible = "0";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
hidden = "1";
|
||||
|
||||
new GuiButtonCtrl() {
|
||||
text = "Level";
|
||||
text = "Game Mode";
|
||||
groupNum = "1";
|
||||
extent = "150 41";
|
||||
profile = "GuiMenuButtonProfile";
|
||||
command = "ChooseLevelMenu.openMenu(0);";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
internalName = "GameModeBtn";
|
||||
class = "ChooseLevelMenuButton";
|
||||
};
|
||||
new GuiButtonCtrl() {
|
||||
text = "Server Config";
|
||||
text = "Level";
|
||||
groupNum = "1";
|
||||
position = "160 0";
|
||||
extent = "150 41";
|
||||
profile = "GuiMenuButtonProfile";
|
||||
command = "ChooseLevelMenu.openMenu(1);";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
internalName = "LevelBtn";
|
||||
class = "ChooseLevelMenuButton";
|
||||
};
|
||||
new GuiButtonCtrl() {
|
||||
text = "Server Config";
|
||||
groupNum = "1";
|
||||
position = "320 0";
|
||||
extent = "150 41";
|
||||
profile = "GuiMenuButtonProfile";
|
||||
visible = "0";
|
||||
command = "ChooseLevelMenu.openMenu(2);";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
internalName = "ConfigBtn";
|
||||
class = "ChooseLevelMenuButton";
|
||||
hidden = "1";
|
||||
};
|
||||
};
|
||||
new GuiControl(ChooseLevelMenuNavButtonOverlay) {
|
||||
position = "0 61";
|
||||
extent = "1281 60";
|
||||
horizSizing = "width";
|
||||
profile = "GuiNonModalDefaultProfile";
|
||||
visible = "0";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
isContainer = "1";
|
||||
hidden = "1";
|
||||
|
||||
new GuiBitmapCtrl(ChooseLevelMenuPrevNavIcon) {
|
||||
BitmapAsset = "UI:Keyboard_Black_Q_image";
|
||||
|
|
@ -94,13 +105,67 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
|
|||
tooltipProfile = "GuiToolTipProfile";
|
||||
};
|
||||
};
|
||||
new GuiContainer(LevelSelectContainer) {
|
||||
new GuiContainer(GameModeSelectContainer) {
|
||||
position = "196 119";
|
||||
extent = "888 566";
|
||||
horizSizing = "center";
|
||||
profile = "GuiNonModalDefaultProfile";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
|
||||
new GuiScrollCtrl(GameModePreviewScroll) {
|
||||
hScrollBar = "alwaysOff";
|
||||
vScrollBar = "dynamic";
|
||||
extent = "445 562";
|
||||
vertSizing = "height";
|
||||
profile = "GuiMenuScrollProfile";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
|
||||
new GuiStackControl(GameModePreviewArray) {
|
||||
padding = "5";
|
||||
position = "1 1";
|
||||
extent = "443 60";
|
||||
horizSizing = "width";
|
||||
vertSizing = "height";
|
||||
profile = "GuiMenuDefaultProfile";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
};
|
||||
};
|
||||
new GuiBitmapCtrl(GameModePreviewBitmap) {
|
||||
position = "448 0";
|
||||
extent = "440 440";
|
||||
horizSizing = "left";
|
||||
profile = "GuiNonModalDefaultProfile";
|
||||
visible = "0";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
hidden = "1";
|
||||
};
|
||||
new GuiTextCtrl(GameModeNameText) {
|
||||
text = "DeathMatchGame";
|
||||
position = "448 445";
|
||||
extent = "440 20";
|
||||
horizSizing = "left";
|
||||
profile = "MenuSubHeaderText";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
internalName = "GameModeNameTxt";
|
||||
};
|
||||
new GuiMLTextCtrl(GameModeDescriptionText) {
|
||||
position = "448 473";
|
||||
extent = "440 19";
|
||||
horizSizing = "left";
|
||||
profile = "GuiMLTextProfile";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
internalName = "GameModeDescTxt";
|
||||
};
|
||||
};
|
||||
new GuiContainer(LevelSelectContainer) {
|
||||
position = "196 119";
|
||||
extent = "888 566";
|
||||
horizSizing = "center";
|
||||
profile = "GuiNonModalDefaultProfile";
|
||||
visible = "0";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
hidden = "1";
|
||||
|
||||
new GuiScrollCtrl(LevelPreviewScroll) {
|
||||
hScrollBar = "alwaysOff";
|
||||
vScrollBar = "dynamic";
|
||||
|
|
@ -112,7 +177,7 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
|
|||
new GuiStackControl(LevelPreviewArray) {
|
||||
padding = "5";
|
||||
position = "0 1";
|
||||
extent = "445 120";
|
||||
extent = "445 60";
|
||||
horizSizing = "width";
|
||||
vertSizing = "height";
|
||||
profile = "GuiMenuDefaultProfile";
|
||||
|
|
@ -120,7 +185,7 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
|
|||
};
|
||||
};
|
||||
new GuiBitmapCtrl(LevelPreviewBitmap) {
|
||||
BitmapAsset = "";
|
||||
BitmapAsset = "UI:no_preview_image";
|
||||
position = "448 0";
|
||||
extent = "440 440";
|
||||
horizSizing = "left";
|
||||
|
|
@ -128,7 +193,7 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
|
|||
tooltipProfile = "GuiToolTipProfile";
|
||||
};
|
||||
new GuiTextCtrl(LevelNameText) {
|
||||
text = "";
|
||||
text = "Example Level";
|
||||
position = "448 445";
|
||||
extent = "440 20";
|
||||
horizSizing = "left";
|
||||
|
|
@ -214,7 +279,7 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
|
|||
tooltipProfile = "GuiToolTipProfile";
|
||||
};
|
||||
new GuiTextEditCtrl(serverNameCTRL) {
|
||||
text = "";
|
||||
text = "Torque 3D Server";
|
||||
position = "606 4";
|
||||
extent = "295 22";
|
||||
horizSizing = "left";
|
||||
|
|
@ -240,7 +305,6 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
|
|||
tooltipProfile = "GuiToolTipProfile";
|
||||
};
|
||||
new GuiTextEditCtrl(serverPassCTRL) {
|
||||
text = "";
|
||||
position = "606 4";
|
||||
extent = "295 22";
|
||||
horizSizing = "left";
|
||||
|
|
@ -313,8 +377,8 @@ $guiContent = new GuiControl(ChooseLevelMenu) {
|
|||
profile = "GuiMenuPanelProfile";
|
||||
tooltipProfile = "GuiToolTipProfile";
|
||||
|
||||
new GuiIconButtonCtrl(ChooseLevelStartBtn) {
|
||||
BitmapAsset = "UI:Keyboard_Black_Return_image";
|
||||
new GuiIconButtonCtrl(ChooseLevelNextBtn) {
|
||||
BitmapAsset = "UI:Keyboard_Black_Blank_image";
|
||||
sizeIconToButton = "1";
|
||||
makeIconSquare = "1";
|
||||
textLocation = "Center";
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ function ChooseLevelMenu::onAdd( %this )
|
|||
if(!isObject(ChooseLevelAssetQuery))
|
||||
new AssetQuery(ChooseLevelAssetQuery);
|
||||
|
||||
%this.previewButtonSize = "445 120";
|
||||
$LevelPreviewButtonSize = "445 60";
|
||||
}
|
||||
|
||||
function ChooseLevelMenu::fillPrefEntries( %this )
|
||||
|
|
@ -40,8 +40,85 @@ function ChooseLevelMenu::fillPrefEntries( %this )
|
|||
function ChooseLevelMenu::onWake(%this)
|
||||
{
|
||||
%this.fillPrefEntries();
|
||||
|
||||
refreshGameModesList();
|
||||
refreshLevelsList();
|
||||
|
||||
if(!$pref::HostMultiPlayer)
|
||||
ChooseLevelTitleText.setText("SINGLE PLAYER");
|
||||
else
|
||||
ChooseLevelTitleText.setText("CREATE SERVER");
|
||||
|
||||
ChooseLevelMenuTabList-->ConfigBtn.visible = $pref::HostMultiPlayer;
|
||||
|
||||
ChooseLevelMenuTabList.visible = true;//$pref::HostMultiPlayer;
|
||||
ChooseLevelMenuNavButtonOverlay.visible = true;//$pref::HostMultiPlayer;
|
||||
|
||||
%this.schedule(32, openMenu, 0);
|
||||
}
|
||||
|
||||
function refreshGameModesList()
|
||||
{
|
||||
GameModePreviewArray.clear();
|
||||
|
||||
$pref::Server::GameMode = "";
|
||||
ChooseLevelMenuTabList-->LevelBtn.active = false;
|
||||
|
||||
//popilate the gamemodes list first
|
||||
%gamemodeList = getGameModesList();
|
||||
%gameModeCount = %gamemodeList.count();
|
||||
|
||||
for (%i=0; %i<%gameModeCount; %i++)
|
||||
{
|
||||
%gameModeObj = %gamemodeList.getKey(%i);
|
||||
if(isObject(%gameModeObj))
|
||||
{
|
||||
%gameModeName = %gameModeObj.gameModeName;
|
||||
if(%gameModeName $= "")
|
||||
%gameModeName = %gameModeObj.getName();
|
||||
|
||||
%preview = new GuiContainer() {
|
||||
position = "0 0";
|
||||
extent = $LevelPreviewButtonSize;
|
||||
horizSizing = "right";
|
||||
vertSizing = "bottom";
|
||||
gameModeObj = %gameModeObj;
|
||||
gameModeDesc = %gameModeObj.description;
|
||||
previewImage = %gameModeObj.previewImage;
|
||||
cansave = false;
|
||||
|
||||
new GuiToggleButtonCtrl() {
|
||||
position = $LevelPreviewButtonSize.y SPC 0;
|
||||
extent = $LevelPreviewButtonSize.x - $LevelPreviewButtonSize.y - 5 SPC $LevelPreviewButtonSize.y;
|
||||
profile = GuiMenuButtonProfile;
|
||||
horizSizing = "right";
|
||||
vertSizing = "bottom";
|
||||
internalName = "button";
|
||||
class = "GameModePreviewButton";
|
||||
text = %gameModeName;
|
||||
command = "ToggleGameMode(" @ %i @ ");"; //allow doubleclick to quick action it
|
||||
textMargin = 120;
|
||||
};
|
||||
|
||||
new GuiBitmapCtrl() {
|
||||
position = "0 0";
|
||||
extent = $LevelPreviewButtonSize.y SPC $LevelPreviewButtonSize.y;
|
||||
internalName = "checkbox";
|
||||
bitmapAsset = "UI:toggleMarker_image";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
GameModePreviewArray.add(%preview);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function refreshLevelsList()
|
||||
{
|
||||
LevelPreviewArray.clear();
|
||||
|
||||
//fetch the levelAssets
|
||||
ChooseLevelAssetQuery.clear();
|
||||
AssetDatabase.findAssetType(ChooseLevelAssetQuery, "LevelAsset");
|
||||
|
||||
|
|
@ -57,6 +134,8 @@ function ChooseLevelMenu::onWake(%this)
|
|||
return;
|
||||
}
|
||||
|
||||
//filter the levelAssets by the gamemode selected
|
||||
%filteredIndex = 0;
|
||||
for(%i=0; %i < %count; %i++)
|
||||
{
|
||||
%assetId = ChooseLevelAssetQuery.getAsset(%i);
|
||||
|
|
@ -71,6 +150,46 @@ function ChooseLevelMenu::onWake(%this)
|
|||
if ( !isFile(%file) )
|
||||
continue;
|
||||
|
||||
if( %levelAsset.isSubScene )
|
||||
continue;
|
||||
|
||||
//filter for selected gamemode
|
||||
%levelGameModes = %levelAsset.gameModesNames;
|
||||
|
||||
//If the level has no gamemodes defined, we just assume the default case of it being a wildcard to whatever gamemode
|
||||
//is available
|
||||
if(%levelGameModes $= "")
|
||||
{
|
||||
%foundGameModeMatch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
%foundGameModeMatch = false;
|
||||
for(%gm = 0; %gm < getTokenCount(%levelGameModes, ";"); %gm++)
|
||||
{
|
||||
%gameModeName = getToken(%levelGameModes, ";", %gm);
|
||||
|
||||
for(%g=0; %g < GameModePreviewArray.getCount(); %g++)
|
||||
{
|
||||
%gmb = GameModePreviewArray.getObject(%g);
|
||||
if(!isObject(%gmb.gameModeObj) || (!%gmb.gameModeObj.active && !%gmb.gameModeObj.alwaysActive))
|
||||
continue;
|
||||
|
||||
if(%gameModeName $= %gmb.gameModeObj.getName())
|
||||
{
|
||||
%foundGameModeMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(%foundGameModeMatch)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!%foundGameModeMatch)
|
||||
continue;
|
||||
|
||||
%levelPreviewImg = %levelAsset.getPreviewImagePath();
|
||||
|
||||
if (!isFile(%levelPreviewImg))
|
||||
|
|
@ -78,7 +197,7 @@ function ChooseLevelMenu::onWake(%this)
|
|||
|
||||
%preview = new GuiIconButtonCtrl() {
|
||||
position = "0 0";
|
||||
extent = %this.previewButtonSize;
|
||||
extent = $LevelPreviewButtonSize;
|
||||
buttonType = "PushButton";
|
||||
profile = GuiMenuButtonLeftJustProfile;
|
||||
horizSizing = "right";
|
||||
|
|
@ -86,7 +205,7 @@ function ChooseLevelMenu::onWake(%this)
|
|||
internalName = "button";
|
||||
class = "LevelPreviewButton";
|
||||
//command = "$selectedLevelAsset = " @ %assetId @ ";";
|
||||
altCommand = "ChooseLevelBegin(1);"; //allow doubleclick to quick action it
|
||||
altCommand = "ChooseLevelBegin(" @ %filteredIndex @ ");"; //allow doubleclick to quick action it
|
||||
text = %levelAsset.levelName;
|
||||
bitmapAsset = %levelPreviewImg;
|
||||
levelAsset = %levelAsset;
|
||||
|
|
@ -101,26 +220,19 @@ function ChooseLevelMenu::onWake(%this)
|
|||
};
|
||||
|
||||
LevelPreviewArray.add(%preview);
|
||||
|
||||
%filteredIndex++;
|
||||
}
|
||||
|
||||
|
||||
GameModePreviewArray.listPosition = 0;
|
||||
LevelPreviewArray.listPosition = 0;
|
||||
|
||||
// Also add the new level mission as defined in the world editor settings
|
||||
// if we are choosing a level to launch in the editor.
|
||||
if ( %this.launchInEditor )
|
||||
if ( ChooseLevelMenu.launchInEditor )
|
||||
{
|
||||
%this.addMissionFile( "tools/levels/DefaultEditorLevel.mis" );
|
||||
ChooseLevelMenu.addMissionFile( "tools/levels/DefaultEditorLevel.mis" );
|
||||
}
|
||||
|
||||
if(!$pref::HostMultiPlayer)
|
||||
ChooseLevelTitleText.setText("SINGLE PLAYER");
|
||||
else
|
||||
ChooseLevelTitleText.setText("CREATE SERVER");
|
||||
|
||||
ChooseLevelMenuTabList.visible = $pref::HostMultiPlayer;
|
||||
ChooseLevelMenuNavButtonOverlay.visible = $pref::HostMultiPlayer;
|
||||
|
||||
%this.schedule(32, openMenu, 0);
|
||||
}
|
||||
|
||||
if(!isObject( ChooseLevelActionMap ) )
|
||||
|
|
@ -133,8 +245,8 @@ if(!isObject( ChooseLevelActionMap ) )
|
|||
ChooseLevelActionMap.bind( keyboard, e, ChooseLevelMenuNextMenu);
|
||||
ChooseLevelActionMap.bind( gamepad, btn_r, ChooseLevelMenuNextMenu);
|
||||
|
||||
ChooseLevelActionMap.bind( keyboard, Space, ChooseLevelBegin );
|
||||
ChooseLevelActionMap.bind( gamepad, btn_a, ChooseLevelBegin );
|
||||
ChooseLevelActionMap.bind( keyboard, Space, ChooseLevelMenuOption );
|
||||
ChooseLevelActionMap.bind( gamepad, btn_a, ChooseLevelMenuOption );
|
||||
}
|
||||
|
||||
function ChooseLevelMenu::syncGUI(%this)
|
||||
|
|
@ -155,10 +267,31 @@ function ChooseLevelMenu::syncGUI(%this)
|
|||
|
||||
ChooseLevelBackBtn.setBitmap(BaseUIActionMap.getCommandButtonBitmap(%device, "BaseUIBackOut"));
|
||||
|
||||
ChooseLevelStartBtn.setBitmap(ChooseLevelActionMap.getCommandButtonBitmap(%device, "ChooseLevelBegin"));
|
||||
if(ChooseLevelMenu.currentMenuIdx == 0)
|
||||
ChooseLevelNextBtn.text = "Toggle Mode";
|
||||
else
|
||||
ChooseLevelNextBtn.text = "Start Game";
|
||||
|
||||
ChooseLevelNextBtn.setBitmap(ChooseLevelActionMap.getCommandButtonBitmap(%device, "ChooseLevelMenuOption"));
|
||||
|
||||
ChooseLevelMenuPrevNavIcon.setBitmap(ChooseLevelActionMap.getCommandButtonBitmap(%device, "ChooseLevelMenuPrevMenu"));
|
||||
ChooseLevelMenuNextNavIcon.setBitmap(ChooseLevelActionMap.getCommandButtonBitmap(%device, "ChooseLevelMenuNextMenu"));
|
||||
|
||||
%hasActiveGameMode = false;
|
||||
for(%i=0; %i < GameModePreviewArray.getCount(); %i++)
|
||||
{
|
||||
%btn = GameModePreviewArray.getObject(%i);
|
||||
if(!isObject(%btn.gameModeObj))
|
||||
continue;
|
||||
|
||||
if((%btn.gameModeObj.isActive() || %btn.gameModeObj.isAlwaysActive()) == true)
|
||||
{
|
||||
%hasActiveGameMode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ChooseLevelMenuTabList-->LevelBtn.active = %hasActiveGameMode;
|
||||
}
|
||||
|
||||
function LevelPreviewArray::syncGUI(%this)
|
||||
|
|
@ -169,14 +302,42 @@ function LevelPreviewArray::syncGUI(%this)
|
|||
$selectedLevelAsset = %btn.levelAssetId;
|
||||
}
|
||||
|
||||
function GameModePreviewArray::syncGUI(%this)
|
||||
{
|
||||
for(%i=0; %i < %this.getCount(); %i++)
|
||||
{
|
||||
%btn = %this.getObject(%i);
|
||||
%btn-->button.setHighlighted(false);
|
||||
|
||||
%bitmapAst = (%btn.gameModeObj.active || %btn.gameModeObj.alwaysActive) ? "UI:toggleMarker_h_image" : "UI:toggleMarker_image";
|
||||
%btn-->checkbox.setBitmap(%bitmapAst);
|
||||
}
|
||||
|
||||
%btn = %this.getObject(%this.listPosition);
|
||||
%btn-->button.setHighlighted(true);
|
||||
|
||||
//$pref::Server::GameMode = %btn.gameModeObject;
|
||||
}
|
||||
|
||||
function ChooseLevelMenuPrevMenu(%val)
|
||||
{
|
||||
if(%val && $pref::HostMultiPlayer)
|
||||
if(%val)
|
||||
{
|
||||
%currentIdx = ChooseLevelMenu.currentMenuIdx;
|
||||
ChooseLevelMenu.currentMenuIdx -= 1;
|
||||
|
||||
ChooseLevelMenu.currentMenuIdx = mClamp(ChooseLevelMenu.currentMenuIdx, 0, 1);
|
||||
%endIndex = 1;
|
||||
if($pref::HostMultiPlayer)
|
||||
%endIndex = 2;
|
||||
|
||||
ChooseLevelMenu.currentMenuIdx = mClamp(ChooseLevelMenu.currentMenuIdx, 0, %endIndex);
|
||||
|
||||
//bail if we're trying to step into a hidden or disabled menu
|
||||
if(!ChooseLevelMenu.isMenuAvailable(ChooseLevelMenu.currentMenuIdx))
|
||||
{
|
||||
ChooseLevelMenu.currentMenuIdx = %currentIdx;
|
||||
return;
|
||||
}
|
||||
|
||||
if(%currentIdx == ChooseLevelMenu.currentMenuIdx)
|
||||
return;
|
||||
|
|
@ -187,12 +348,23 @@ function ChooseLevelMenuPrevMenu(%val)
|
|||
|
||||
function ChooseLevelMenuNextMenu(%val)
|
||||
{
|
||||
if(%val && $pref::HostMultiPlayer)
|
||||
if(%val)
|
||||
{
|
||||
%currentIdx = ChooseLevelMenu.currentMenuIdx;
|
||||
ChooseLevelMenu.currentMenuIdx += 1;
|
||||
|
||||
ChooseLevelMenu.currentMenuIdx = mClamp(ChooseLevelMenu.currentMenuIdx, 0, 1);
|
||||
%endIndex = 1;
|
||||
if($pref::HostMultiPlayer)
|
||||
%endIndex = 2;
|
||||
|
||||
ChooseLevelMenu.currentMenuIdx = mClamp(ChooseLevelMenu.currentMenuIdx, 0, %endIndex);
|
||||
|
||||
//bail if we're trying to step into a hidden or disabled menu
|
||||
if(!ChooseLevelMenu.isMenuAvailable(ChooseLevelMenu.currentMenuIdx))
|
||||
{
|
||||
ChooseLevelMenu.currentMenuIdx = %currentIdx;
|
||||
return;
|
||||
}
|
||||
|
||||
if(%currentIdx == ChooseLevelMenu.currentMenuIdx)
|
||||
return;
|
||||
|
|
@ -201,15 +373,17 @@ function ChooseLevelMenuNextMenu(%val)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
function ChooseLevelMenu::openMenu(%this, %menuIdx)
|
||||
{
|
||||
LevelSelectContainer.setVisible(%menuIdx == 0);
|
||||
ServerConfigContainer.setVisible(%menuIdx == 1);
|
||||
|
||||
GameModeSelectContainer.setVisible(%menuIdx == 0);
|
||||
LevelSelectContainer.setVisible(%menuIdx == 1);
|
||||
ServerConfigContainer.setVisible(%menuIdx == 2);
|
||||
|
||||
if(%menuIdx == 0)
|
||||
$MenuList = LevelPreviewArray;
|
||||
$MenuList = GameModePreviewArray;
|
||||
else if(%menuIdx == 1)
|
||||
$MenuList = LevelPreviewArray;
|
||||
else if(%menuIdx == 2)
|
||||
$MenuList = ServerConfigList;
|
||||
|
||||
%this.currentMenuIdx = %menuIdx;
|
||||
|
|
@ -220,37 +394,78 @@ function ChooseLevelMenu::openMenu(%this, %menuIdx)
|
|||
%this.syncGui();
|
||||
}
|
||||
|
||||
function ChooseLevelBegin(%val)
|
||||
function ChooseLevelMenu::isMenuAvailable(%this, %menuIdx)
|
||||
{
|
||||
if(%menuIdx == 0)
|
||||
%btn = %this-->GameModeBtn;
|
||||
else if(%menuIdx == 1)
|
||||
%btn = %this-->LevelBtn;
|
||||
else if(%menuIdx == 2)
|
||||
%btn = %this-->ConfigBtn;
|
||||
|
||||
return %btn.isActive() && %btn.isVisible();
|
||||
}
|
||||
|
||||
function ChooseLevelMenuOption(%val)
|
||||
{
|
||||
if(%val)
|
||||
{
|
||||
// So we can't fire the button when loading is in progress.
|
||||
if ( isObject( ServerGroup ) )
|
||||
return;
|
||||
|
||||
Canvas.popDialog();
|
||||
|
||||
%entry = LevelPreviewArray.getObject(LevelPreviewArray.listPosition);
|
||||
|
||||
if(!AssetDatabase.isDeclaredAsset(%entry.levelAssetId))
|
||||
{
|
||||
MessageBoxOK("Error", "Selected level preview does not have a valid level asset!");
|
||||
return;
|
||||
}
|
||||
|
||||
$selectedLevelAsset = %entry.levelAssetId;
|
||||
if(ChooseLevelMenu.currentMenuIdx == 0)
|
||||
ToggleGameMode(ChooseLevelMenu.listPosition);
|
||||
else if(ChooseLevelMenu.currentMenuIdx == 1)
|
||||
ChooseLevelBegin(ChooseLevelMenu.listPosition);
|
||||
}
|
||||
}
|
||||
|
||||
// Launch the chosen level with the editor open?
|
||||
if ( ChooseLevelMenu.launchInEditor )
|
||||
{
|
||||
activatePackage( "BootEditor" );
|
||||
ChooseLevelMenu.launchInEditor = false;
|
||||
StartGame(%entry.levelAssetId, "SinglePlayer");
|
||||
}
|
||||
else
|
||||
{
|
||||
StartGame(%entry.levelAssetId);
|
||||
}
|
||||
function ToggleGameMode(%index)
|
||||
{
|
||||
if(%index $= "")
|
||||
%index = $MenuList.listPosition;
|
||||
|
||||
%entry = GameModePreviewArray.getObject(%index);
|
||||
if(!isObject(%entry) || !isObject(%entry.gameModeObj))
|
||||
{
|
||||
MessageBoxOK("Error", "Selected game mode does not have a valid mode");
|
||||
return;
|
||||
}
|
||||
|
||||
%entry.gameModeObj.active = !%entry.gameModeObj.active;
|
||||
|
||||
refreshLevelsList();
|
||||
|
||||
$MenuList.syncGui();
|
||||
ChooseLevelMenu.syncGui();
|
||||
|
||||
}
|
||||
|
||||
function ChooseLevelBegin(%index)
|
||||
{
|
||||
// So we can't fire the button when loading is in progress.
|
||||
if ( isObject( ServerGroup ) )
|
||||
return;
|
||||
|
||||
Canvas.popDialog();
|
||||
|
||||
%entry = LevelPreviewArray.getObject(%index);
|
||||
|
||||
if(!AssetDatabase.isDeclaredAsset(%entry.levelAssetId))
|
||||
{
|
||||
MessageBoxOK("Error", "Selected level preview does not have a valid level asset!");
|
||||
return;
|
||||
}
|
||||
|
||||
$selectedLevelAsset = %entry.levelAssetId;
|
||||
|
||||
// Launch the chosen level with the editor open?
|
||||
if ( ChooseLevelMenu.launchInEditor )
|
||||
{
|
||||
activatePackage( "BootEditor" );
|
||||
ChooseLevelMenu.launchInEditor = false;
|
||||
StartGame(%entry.levelAssetId, "SinglePlayer");
|
||||
}
|
||||
else
|
||||
{
|
||||
StartGame(%entry.levelAssetId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -270,6 +485,23 @@ function ChooseLevelMenu::onSleep( %this )
|
|||
}
|
||||
}
|
||||
|
||||
function GameModePreviewButton::onHighlighted(%this, %highlighted)
|
||||
{
|
||||
if(%highlighted)
|
||||
{
|
||||
$MenuList.listPosition = $MenuList.getObjectIndex(%this.getParent());
|
||||
|
||||
GameModePreviewBitmap.bitmapAsset = %this.previewImage;
|
||||
|
||||
GameModePreviewBitmap.visible = (%this.previewImage !$= "");
|
||||
|
||||
GameModeNameText.text = %this.text;
|
||||
GameModeDescriptionText.setText(%this.gameModeDesc);
|
||||
|
||||
GameModePreviewScroll.scrollToObject(%this);
|
||||
}
|
||||
}
|
||||
|
||||
function LevelPreviewButton::onHighlighted(%this, %highlighted)
|
||||
{
|
||||
if(%highlighted)
|
||||
|
|
|
|||
BIN
Templates/BaseGame/game/data/UI/images/toggleMarker.png
Normal file
BIN
Templates/BaseGame/game/data/UI/images/toggleMarker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
BIN
Templates/BaseGame/game/data/UI/images/toggleMarker_h.png
Normal file
BIN
Templates/BaseGame/game/data/UI/images/toggleMarker_h.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
|
|
@ -0,0 +1,3 @@
|
|||
<ImageAsset
|
||||
AssetName="toggleMarker_h_image"
|
||||
imageFile="@assetFile=toggleMarker_h.png"/>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<ImageAsset
|
||||
AssetName="toggleMarker_image"
|
||||
imageFile="@assetFile=toggleMarker.png"/>
|
||||
|
|
@ -87,6 +87,7 @@ function initializeAssetBrowser()
|
|||
exec("./scripts/looseFileAudit." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/creator." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/setAssetTarget." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/utils." @ $TorqueScriptFileExtension);
|
||||
|
||||
//Processing for the different asset types
|
||||
exec("./scripts/assetTypes/component." @ $TorqueScriptFileExtension);
|
||||
|
|
@ -110,6 +111,7 @@ function initializeAssetBrowser()
|
|||
exec("./scripts/assetTypes/looseFiles." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/assetTypes/prefab." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/assetTypes/creatorObj." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/assetTypes/gameMode." @ $TorqueScriptFileExtension);
|
||||
|
||||
new ScriptObject( AssetBrowserPlugin )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -79,7 +79,6 @@ function AssetBrowser_addModuleWindow::CreateNewModule(%this)
|
|||
%line = strreplace( %line, "@@", %newModuleName );
|
||||
|
||||
%file.writeline(%line);
|
||||
echo(%line);
|
||||
}
|
||||
|
||||
%file.close();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
AssetBrowser::registerObjectType("GameModeType", "Gamemode Objects", "Gamemode");
|
||||
|
||||
function GameModeType::setupCreateNew()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
function GameModeType::onCreateNew()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
function GameModeType::buildBrowserElement(%this, %className, %previewData)
|
||||
{
|
||||
//echo("DatablockObjectType::buildBrowserElement() - " @ %datablock @ ", " @ %name @ ", " @ %previewData);
|
||||
%previewData.assetName = %this.getName();
|
||||
%previewData.assetPath = %this.getFileName();
|
||||
|
||||
%previewData.previewImage = "ToolsModule:genericAssetIcon_image";
|
||||
|
||||
//Lets see if we have a icon for specifically for this datablock type
|
||||
%dataClass = %this.getClassName();
|
||||
%dataClass = strreplace(%dataClass, "Data", "");
|
||||
|
||||
%previewImage = "tools/classIcons/" @ %dataClass @ ".png";
|
||||
if(isFile(%previewImage))
|
||||
{
|
||||
%previewData.previewImage = %previewImage;
|
||||
}
|
||||
|
||||
//%previewData.assetFriendlyName = %assetDef.assetName;
|
||||
%previewData.assetDesc = %this;
|
||||
%previewData.tooltip = "\nGameMode Name: " @ %previewData.assetName @
|
||||
"\nPath: " @ %previewData.assetPath;
|
||||
}
|
||||
|
|
@ -3,6 +3,8 @@ function AssetBrowser::setupCreateNewLevelAsset(%this)
|
|||
NewAssetPropertiesInspector.startGroup("Level");
|
||||
NewAssetPropertiesInspector.addField("LevelName", "Level Name", "String", "Human-readable name of new level", "", "", %this.newAssetSettings);
|
||||
NewAssetPropertiesInspector.addField("levelPreviewImage", "Level Preview Image", "Image", "Preview Image for the level", "", "", %this.newAssetSettings);
|
||||
|
||||
NewAssetPropertiesInspector.addField("isSubScene", "Is SubScene", "bool", "Is this levelAsset intended as a subScene", "", "", %this.newAssetSettings);
|
||||
|
||||
NewAssetPropertiesInspector.endGroup();
|
||||
}
|
||||
|
|
@ -20,14 +22,16 @@ function AssetBrowser::createLevelAsset(%this)
|
|||
|
||||
%assetPath = NewAssetTargetAddress.getText() @ "/";
|
||||
|
||||
%misExtension = AssetBrowser.newAssetSettings.isSubScene ? ".subMis" : ".mis";
|
||||
|
||||
%tamlpath = %assetPath @ %assetName @ ".asset.taml";
|
||||
%levelPath = %assetPath @ %assetName @ ".mis";
|
||||
%levelPath = %assetPath @ %assetName @ %misExtension;
|
||||
|
||||
%asset = new LevelAsset()
|
||||
{
|
||||
AssetName = %assetName;
|
||||
versionId = 1;
|
||||
LevelFile = %assetName @ ".mis";
|
||||
LevelFile = %assetName @ %misExtension;
|
||||
DecalsFile = %assetName @ ".mis.decals";
|
||||
PostFXPresetFile = %assetName @ ".postfxpreset." @ $TorqueScriptFileExtension;
|
||||
ForestFile = %assetName @ ".forest";
|
||||
|
|
@ -35,6 +39,7 @@ function AssetBrowser::createLevelAsset(%this)
|
|||
LevelName = AssetBrowser.newAssetSettings.levelName;
|
||||
AssetDescription = AssetBrowser.newAssetSettings.description;
|
||||
PreviewImage = AssetBrowser.newAssetSettings.levelPreviewImage;
|
||||
isSubScene = AssetBrowser.newAssetSettings.isSubScene;
|
||||
};
|
||||
|
||||
TamlWrite(%asset, %tamlpath);
|
||||
|
|
@ -58,15 +63,32 @@ function AssetBrowser::createLevelAsset(%this)
|
|||
|
||||
%moduleDef = ModuleDatabase.findModule(%moduleName, 1);
|
||||
%addSuccess = AssetDatabase.addDeclaredAsset(%moduleDef, %tamlpath);
|
||||
|
||||
if(!%addSuccess)
|
||||
{
|
||||
error("AssetBrowser::createLevelAsset() - failed to add declared asset: " @ %tamlpath @ " for module: " @ %moduleDef);
|
||||
}
|
||||
|
||||
AssetBrowser.refresh();
|
||||
|
||||
return %tamlpath;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
//SubScene derivative
|
||||
//==============================================================================
|
||||
function AssetBrowser::setupCreateNewSubScene(%this)
|
||||
{
|
||||
%this.newAssetSettings.isSubScene = true;
|
||||
%this.newAssetSettings.assetType = "LevelAsset";
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
function AssetBrowser::editLevelAsset(%this, %assetDef)
|
||||
{
|
||||
schedule( 1, 0, "EditorOpenMission", %assetDef);
|
||||
if(!%assetDef.isSubScene)
|
||||
schedule( 1, 0, "EditorOpenMission", %assetDef);
|
||||
}
|
||||
|
||||
//Renames the asset
|
||||
|
|
@ -150,4 +172,100 @@ function AssetBrowser::buildLevelAssetPreview(%this, %assetDef, %previewData)
|
|||
"Asset Type: Level Asset\n" @
|
||||
"Asset Definition ID: " @ %assetDef @ "\n" @
|
||||
"Level File path: " @ %assetDef.getLevelPath();
|
||||
}
|
||||
|
||||
function createAndAssignLevelAsset(%moduleName, %assetName)
|
||||
{
|
||||
$createAndAssignField.apply(%moduleName @ ":" @ %assetName);
|
||||
}
|
||||
|
||||
function EWorldEditor::createSelectedAsSubScene( %this, %object )
|
||||
{
|
||||
//create new level asset here
|
||||
AssetBrowser.setupCreateNewAsset("SubScene", AssetBrowser.selectedModule, "finishCreateSelectedAsSubScene");
|
||||
%this.contextActionObject = %object;
|
||||
}
|
||||
|
||||
function finishCreateSelectedAsSubScene(%assetId)
|
||||
{
|
||||
echo("finishCreateSelectedAsSubScene");
|
||||
|
||||
%subScene = new SubScene() {
|
||||
levelAsset = %assetId;
|
||||
};
|
||||
|
||||
%levelAssetDef = AssetDatabase.acquireAsset(%assetId);
|
||||
%levelFilePath = %levelAssetDef.getLevelPath();
|
||||
|
||||
//write out to file
|
||||
EWorldEditor.contextActionObject.save(%levelFilePath);
|
||||
|
||||
AssetDatabase.releaseAsset(%assetId);
|
||||
|
||||
getRootScene().add(%subScene);
|
||||
|
||||
EWorldEditor.contextActionObject.delete();
|
||||
|
||||
%subScene.load();
|
||||
|
||||
%subScene.recalculateBounds();
|
||||
|
||||
%scalar = $SubScene::createScalar;
|
||||
if(%scalar $= "")
|
||||
%scalar = 1.5;
|
||||
|
||||
//pad for loading boundary
|
||||
%subScene.scale = VectorScale(%subScene.scale, %scalar);
|
||||
}
|
||||
|
||||
function GuiInspectorTypeLevelAssetPtr::onControlDropped( %this, %payload, %position )
|
||||
{
|
||||
Canvas.popDialog(EditorDragAndDropLayer);
|
||||
|
||||
// Make sure this is a color swatch drag operation.
|
||||
if( !%payload.parentGroup.isInNamespaceHierarchy( "AssetPreviewControlType_AssetDrop" ) )
|
||||
return;
|
||||
|
||||
%assetType = %payload.assetType;
|
||||
%module = %payload.moduleName;
|
||||
%assetName = %payload.assetName;
|
||||
|
||||
if(%assetType $= "LevelAsset")
|
||||
{
|
||||
%cmd = %this @ ".apply(\""@ %module @ ":" @ %assetName @ "\");";
|
||||
eval(%cmd);
|
||||
}
|
||||
|
||||
EWorldEditor.isDirty = true;
|
||||
}
|
||||
|
||||
function AssetBrowser::onLevelAssetEditorDropped(%this, %assetDef, %position)
|
||||
{
|
||||
%assetId = %assetDef.getAssetId();
|
||||
|
||||
if(!%assetDef.isSubScene)
|
||||
{
|
||||
errorf("Cannot drag-and-drop LevelAsset into WorldEditor");
|
||||
return;
|
||||
}
|
||||
|
||||
%newSubScene = new SubScene()
|
||||
{
|
||||
position = %position;
|
||||
levelAsset = %assetId;
|
||||
};
|
||||
|
||||
getScene(0).add(%newSubScene);
|
||||
|
||||
%newSubScene.load();
|
||||
%newSubScene.recalculateBounds();
|
||||
|
||||
EWorldEditor.clearSelection();
|
||||
EWorldEditor.selectObject(%newSubScene);
|
||||
|
||||
EWorldEditor.dropSelection();
|
||||
|
||||
EWorldEditor.isDirty = true;
|
||||
|
||||
MECreateUndoAction::submit(%newSubScene );
|
||||
}
|
||||
|
|
@ -176,6 +176,31 @@ function AssetBrowser::performRenameAsset(%this, %originalAssetName, %newName)
|
|||
%buildCommand = %this @ ".rename" @ EditAssetPopup.assetType @ "(" @ %assetDef @ "," @ %newName @ ");";
|
||||
eval(%buildCommand);
|
||||
}
|
||||
else
|
||||
{
|
||||
//do generic action here
|
||||
%oldAssetId = %moduleName @ ":" @ %originalAssetName;
|
||||
%assetDef = AssetDatabase.acquireAsset(%oldAssetId);
|
||||
|
||||
%assetFileName = fileName(%assetDef.getFileName());
|
||||
%assetFilePath = filePath(%assetDef.getFileName());
|
||||
|
||||
%pattern = %assetFilePath @ "/" @ %assetFileName @ ".*";
|
||||
|
||||
echo("Searching for matches of asset files following pattern: " @ %pattern);
|
||||
|
||||
//get list of files that match the name in the same dir
|
||||
//do a rename on them
|
||||
for (%file = findFirstFileMultiExpr(%pattern); %file !$= ""; %file = findNextFileMultiExpr(%pattern))
|
||||
{
|
||||
if(%file !$= %assetFileName)
|
||||
renameAssetLooseFile(%file, %newName);
|
||||
}
|
||||
|
||||
//update the assetDef
|
||||
replaceInFile(%assetDef.getFileName(), %originalAssetName, %newName);
|
||||
renameAssetFile(%assetDef, %newName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -117,7 +117,8 @@ function AssetBrowser::buildPopupMenus(%this)
|
|||
//item[ 0 ] = "Create Component" TAB AddNewComponentAssetPopup;
|
||||
item[ 0 ] = "Create Script" TAB "" TAB "AssetBrowser.setupCreateNewAsset(\"ScriptAsset\", AssetBrowser.selectedModule);";
|
||||
item[ 1 ] = "Create State Machine" TAB "" TAB "AssetBrowser.setupCreateNewAsset(\"StateMachineAsset\", AssetBrowser.selectedModule);";
|
||||
//item[ 3 ] = "-";
|
||||
item[ 2 ] = "-";
|
||||
item[ 3 ] = "Create Game Mode" TAB "" TAB "AssetBrowser.setupCreateNewAsset(\"GameMode\", AssetBrowser.selectedModule);";
|
||||
//item[ 3 ] = "Create Game Object" TAB "" TAB "AssetBrowser.createNewGameObjectAsset(\"NewGameObject\", AssetBrowser.selectedModule);";
|
||||
};
|
||||
//%this.AddNewScriptAssetPopup.insertSubMenu(0, "Create Component", AddNewComponentAssetPopup);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,176 @@
|
|||
//This file implements game mode logic for an Example gamemode. The primary functions:
|
||||
//@@::onMissionStart
|
||||
//@@::onMissionReset
|
||||
//@@::onMissionEnd
|
||||
//Are the primary hooks for the server to start, restart and end any active gamemodes
|
||||
//onMissionStart, for example is called from core/clientServer/scripts/server/levelLoad.cs
|
||||
//It's called once the server has successfully loaded the level, and has parsed
|
||||
//through any active scenes to get GameModeNames defined by them. It then iterates
|
||||
//over them and calls these callbacks to envoke gamemode behaviors. This allows multiple
|
||||
//gamemodes to be in effect at one time. Modules can implement as many gamemodes as you want.
|
||||
//
|
||||
//For levels that can be reused for multiple gammodes, the general setup would be a primary level file
|
||||
//with the Scene in it having the main geometry, weapons, terrain, etc. You would then have subScenes that
|
||||
//each contain what's necessary for the given gamemode, such as a subScene that just adds the flags and capture
|
||||
//triggers for a CTF mode. The subscene would then have it's GameModeName defined to run the CTF gamemode logic
|
||||
//and the levelLoad code will execute it.
|
||||
|
||||
if(!isObject(@@))
|
||||
{
|
||||
new GameMode(@@){};
|
||||
}
|
||||
|
||||
//This function is called when the level finishes loading. It sets up the initial configuration, variables and
|
||||
//spawning and dynamic objects, timers or rules needed for the gamemode to run
|
||||
function @@::onMissionStart(%this)
|
||||
{
|
||||
//set up the game and game variables
|
||||
%this.initGameVars();
|
||||
|
||||
if (%this.isActive())
|
||||
{
|
||||
error("@@::onMissionStart: End the game first!");
|
||||
return;
|
||||
}
|
||||
|
||||
%this.setActive(true);
|
||||
}
|
||||
|
||||
//This function is called when the level ends. It can be envoked due to the gamemode ending
|
||||
//but is also kicked off when the game server is shut down as a form of cleanup for anything the gamemode
|
||||
//created or is managing like the above mentioned dynamic objects or timers
|
||||
function @@::onMissionEnded(%this)
|
||||
{
|
||||
if (!%this.isActive())
|
||||
{
|
||||
error("@@::onMissionEnded: No game running!");
|
||||
return;
|
||||
}
|
||||
|
||||
%this.setActive(false);
|
||||
}
|
||||
|
||||
//This function is called in the event the server resets and is used to re-initialize the gamemode
|
||||
function @@::onMissionReset(%this)
|
||||
{
|
||||
// Called by resetMission(), after all the temporary mission objects
|
||||
// have been deleted.
|
||||
%this.initGameVars();
|
||||
}
|
||||
|
||||
//This sets up our gamemode's duration time
|
||||
function @@::initGameVars(%this)
|
||||
{
|
||||
// Set the gameplay parameters
|
||||
%this.duration = 30 * 60;
|
||||
}
|
||||
|
||||
//This is called when the timer runs out, allowing the gamemode to end
|
||||
function @@::onGameDurationEnd(%this)
|
||||
{
|
||||
//we don't end if we're currently editing the level
|
||||
if (%this.duration && !(EditorIsActive() && GuiEditorIsActive()))
|
||||
%this.onMissionEnded();
|
||||
}
|
||||
|
||||
//This is called to actually spawn a control object for the player to utilize
|
||||
//A player character, spectator camera, etc.
|
||||
function @@::spawnControlObject(%this, %client)
|
||||
{
|
||||
//In this example, we just spawn a camera
|
||||
/*if (!isObject(%client.camera))
|
||||
{
|
||||
if(!isObject(Observer))
|
||||
{
|
||||
datablock CameraData(Observer)
|
||||
{
|
||||
mode = "Observer";
|
||||
};
|
||||
}
|
||||
|
||||
%client.camera = spawnObject("Camera", Observer);
|
||||
}
|
||||
|
||||
// If we have a camera then set up some properties
|
||||
if (isObject(%client.camera))
|
||||
{
|
||||
MissionCleanup.add( %this.camera );
|
||||
%client.camera.scopeToClient(%client);
|
||||
|
||||
%client.setControlObject(%client.camera);
|
||||
|
||||
%client.camera.setTransform("0 0 1 0 0 0 0");
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
//This is called when the client has finished loading the mission, but aren't "in" it yet
|
||||
//allowing for some last-second prepwork
|
||||
function @@::onClientMissionLoaded(%this)
|
||||
{
|
||||
$clientLoaded++;
|
||||
if ($clientLoaded == $clientConneted)
|
||||
$gameReady = true;
|
||||
}
|
||||
|
||||
//This is called when the client has initially established a connection to the game server
|
||||
//It's used for setting up anything ahead of time for the client, such as loading in client-passed
|
||||
//config stuffs, saved data or the like that should be handled BEFORE the client has actually entered
|
||||
//the game itself
|
||||
function @@::onClientConnect(%this, %client)
|
||||
{
|
||||
$clientConneted++;
|
||||
getPlayer(%client);
|
||||
}
|
||||
|
||||
|
||||
//This is called when a client enters the game server. It's used to spawn a player object
|
||||
//set up any client-specific properties such as saved configs, values, their name, etc
|
||||
//These callbacks are activated in core/clientServer/scripts/server/levelDownload.cs
|
||||
function @@::onClientEnterGame(%this, %client)
|
||||
{
|
||||
$Game::DefaultPlayerClass = "Player";
|
||||
$Game::DefaultPlayerDataBlock = "DefaultPlayerData";
|
||||
$Game::DefaultPlayerSpawnGroups = "spawn_player CameraSpawnPoints PlayerSpawnPoints PlayerDropPoints";
|
||||
|
||||
$Game::DefaultCameraClass = "Camera";
|
||||
$Game::DefaultCameraDataBlock = "Observer";
|
||||
$Game::DefaultCameraSpawnGroups = "spawn_player CameraSpawnPoints PlayerSpawnPoints PlayerDropPoints";
|
||||
|
||||
|
||||
//Spawn NPCs for the map and stuff here?
|
||||
|
||||
// This function currently relies on some helper functions defined in
|
||||
// core/scripts/spawn.cs. For custom spawn behaviors one can either
|
||||
// override the properties on the SpawnSphere's or directly override the
|
||||
// functions themselves.
|
||||
}
|
||||
|
||||
function @@::onSceneLoaded(%this)
|
||||
{
|
||||
}
|
||||
|
||||
function @@::onSceneUnloaded(%this)
|
||||
{
|
||||
}
|
||||
|
||||
function @@::onSubsceneLoaded(%this)
|
||||
{
|
||||
}
|
||||
|
||||
function @@::onSubsceneUnloaded(%this)
|
||||
{
|
||||
}
|
||||
|
||||
//This is called when the player leaves the game server. It's used to clean up anything that
|
||||
//was spawned or setup for the client when it connected, in onClientEnterGame
|
||||
//These callbacks are activated in core/clientServer/scripts/server/levelDownload.cs
|
||||
function @@::onClientLeaveGame(%this, %client)
|
||||
{
|
||||
// Cleanup the camera
|
||||
if (isObject(%this.camera))
|
||||
%this.camera.delete();
|
||||
// Cleanup the player
|
||||
if (isObject(%this.player))
|
||||
%this.player.delete();
|
||||
}
|
||||
|
|
@ -9,24 +9,23 @@ function @@::onDestroy(%this)
|
|||
//This is called when the server is initially set up by the game application
|
||||
function @@::initServer(%this)
|
||||
{
|
||||
//--FILE EXEC BEGIN--
|
||||
//--FILE EXEC END--
|
||||
}
|
||||
|
||||
//This is called when the server is created for an actual game/map to be played
|
||||
function @@::onCreateGameServer(%this)
|
||||
{
|
||||
//--DATABLOCK EXEC BEGIN--
|
||||
//These are common managed data files. For any datablock-based stuff that gets generated by the editors
|
||||
//(that doesn't have a specific associated file, like data for a player class) will go into these.
|
||||
//So we'll register them now if they exist.
|
||||
if(isFile("./scripts/managedData/managedDatablocks." @ $TorqueScriptFileExtension))
|
||||
%this.registerDatablock("./scripts/managedData/managedDatablocks");
|
||||
if(isFile("./scripts/managedData/managedForestItemData." @ $TorqueScriptFileExtension))
|
||||
%this.registerDatablock("./scripts/managedData/managedForestItemData");
|
||||
if(isFile("./scripts/managedData/managedForestBrushData." @ $TorqueScriptFileExtension))
|
||||
%this.registerDatablock("./scripts/managedData/managedForestBrushData");
|
||||
if(isFile("./scripts/managedData/managedParticleEmitterData." @ $TorqueScriptFileExtension))
|
||||
%this.registerDatablock("./scripts/managedData/managedParticleEmitterData");
|
||||
if(isFile("./scripts/managedData/managedParticleData." @ $TorqueScriptFileExtension))
|
||||
%this.registerDatablock("./scripts/managedData/managedParticleData");
|
||||
%this.registerDatablock("./scripts/managedData/managedDatablocks");
|
||||
%this.registerDatablock("./scripts/managedData/managedForestItemData");
|
||||
%this.registerDatablock("./scripts/managedData/managedForestBrushData");
|
||||
%this.registerDatablock("./scripts/managedData/managedParticleEmitterData");
|
||||
%this.registerDatablock("./scripts/managedData/managedParticleData");
|
||||
//--DATABLOCK EXEC END--
|
||||
}
|
||||
|
||||
//This is called when the server is shut down due to the game/map being exited
|
||||
|
|
@ -37,6 +36,8 @@ function @@::onDestroyGameServer(%this)
|
|||
//This is called when the client is initially set up by the game application
|
||||
function @@::initClient(%this)
|
||||
{
|
||||
//--FILE EXEC BEGIN--
|
||||
//--FILE EXEC END--
|
||||
}
|
||||
|
||||
//This is called when a client connects to a server
|
||||
|
|
|
|||
253
Templates/BaseGame/game/tools/assetBrowser/scripts/utils.tscript
Normal file
253
Templates/BaseGame/game/tools/assetBrowser/scripts/utils.tscript
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
function testRpl()
|
||||
{
|
||||
ToolUtilityScripts::appendLineToFunction("data/prototyping/prototyping.tscript", "Prototyping", "onDestroyGameServer", "//AAAAAAAAAAAAAAAAAAAAA");
|
||||
}
|
||||
|
||||
function Tools::appendLineToFunction(%file, %nameSpace, %functionName, %appendLine)
|
||||
{
|
||||
%fileOutput = new ArrayObject(){};
|
||||
%fileObj = new FileObject(){};
|
||||
|
||||
%insideFunction = false;
|
||||
%scopeDepth = 0;
|
||||
|
||||
if ( %fileObj.openForRead( %file ) )
|
||||
{
|
||||
while ( !%fileObj.isEOF() )
|
||||
{
|
||||
%line = %fileObj.readLine();
|
||||
|
||||
if(strIsMatchExpr("*function *(*)*", %line))
|
||||
{
|
||||
%fileOutput.add(%line);
|
||||
|
||||
%start = strpos(%line, "function ");
|
||||
%end = strpos(%line, "(", %start);
|
||||
|
||||
%scannedFunctionName = "";
|
||||
|
||||
if(%start != -1 && %end != -1)
|
||||
{
|
||||
%scannedFunctionName = getSubStr(%line, %start + 9, %end-%start-9);
|
||||
}
|
||||
|
||||
%matchesFunctionSig = false;
|
||||
if(%nameSpace !$= "")
|
||||
{
|
||||
if(%scannedFunctionName $= (%nameSpace @ "::" @ %functionName))
|
||||
%matchesFunctionSig = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(%scannedFunctionName $= %functionName)
|
||||
%matchesFunctionSig = true;
|
||||
}
|
||||
|
||||
if(!%matchesFunctionSig)
|
||||
continue;
|
||||
|
||||
%insideFunction = true;
|
||||
|
||||
if(strIsMatchExpr("*{*", %line))
|
||||
{
|
||||
%scopeDepth++;
|
||||
}
|
||||
if(strIsMatchExpr("*}*", %line))
|
||||
{
|
||||
%scopeDepth--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(%insideFunction && strIsMatchExpr("*{*", %line))
|
||||
{
|
||||
%scopeDepth++;
|
||||
}
|
||||
if(%insideFunction && strIsMatchExpr("*}*", %line))
|
||||
{
|
||||
%scopeDepth--;
|
||||
|
||||
if(%scopeDepth == 0) //we've fully backed out of the function scope, so resolve back to the parent
|
||||
{
|
||||
%insideFunction = false;
|
||||
|
||||
%fileOutput.add(%appendLine);
|
||||
}
|
||||
}
|
||||
|
||||
%fileOutput.add(%line);
|
||||
}
|
||||
}
|
||||
%fileObj.close();
|
||||
}
|
||||
|
||||
if ( %fileObj.openForWrite( %file ) )
|
||||
{
|
||||
for(%i=0; %i < %fileOutput.count(); %i++)
|
||||
{
|
||||
%line = %fileOutput.getKey(%i);
|
||||
|
||||
%fileObj.writeLine(%line);
|
||||
}
|
||||
%fileObj.close();
|
||||
}
|
||||
}
|
||||
|
||||
function Tools::findInFile(%file, %findText, %startingLineId)
|
||||
{
|
||||
if(%startingLineId $= "")
|
||||
%startingLineId = 0;
|
||||
|
||||
%fileObj = new FileObject(){};
|
||||
|
||||
if ( %fileObj.openForRead( %file ) )
|
||||
{
|
||||
%lineId = 0;
|
||||
while ( !%fileObj.isEOF() )
|
||||
{
|
||||
if(%lineId >= %startingLineId)
|
||||
{
|
||||
%line = %fileObj.readLine();
|
||||
|
||||
if(strIsMatchExpr(%findText, %line))
|
||||
{
|
||||
return %lineId;
|
||||
}
|
||||
}
|
||||
|
||||
%lineId++;
|
||||
}
|
||||
%fileObj.close();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
function Tools::findInFunction(%file, %nameSpace, %functionName, %findText)
|
||||
{
|
||||
%fileObj = new FileObject(){};
|
||||
|
||||
%insideFunction = false;
|
||||
%scopeDepth = 0;
|
||||
|
||||
if ( %fileObj.openForRead( %file ) )
|
||||
{
|
||||
%lineId = -1;
|
||||
while ( !%fileObj.isEOF() )
|
||||
{
|
||||
%line = %fileObj.readLine();
|
||||
%lineId++;
|
||||
|
||||
if(strIsMatchExpr("*function *(*)*", %line))
|
||||
{
|
||||
%start = strpos(%line, "function ");
|
||||
%end = strpos(%line, "(", %start);
|
||||
|
||||
%scannedFunctionName = "";
|
||||
|
||||
if(%start != -1 && %end != -1)
|
||||
{
|
||||
%scannedFunctionName = getSubStr(%line, %start + 9, %end-%start-9);
|
||||
}
|
||||
|
||||
%matchesFunctionSig = false;
|
||||
if(%nameSpace !$= "")
|
||||
{
|
||||
if(%scannedFunctionName $= (%nameSpace @ "::" @ %functionName))
|
||||
%matchesFunctionSig = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(%scannedFunctionName $= %functionName)
|
||||
%matchesFunctionSig = true;
|
||||
}
|
||||
|
||||
if(!%matchesFunctionSig)
|
||||
continue;
|
||||
|
||||
%insideFunction = true;
|
||||
|
||||
if(strIsMatchExpr("*{*", %line))
|
||||
{
|
||||
%scopeDepth++;
|
||||
}
|
||||
if(strIsMatchExpr("*}*", %line))
|
||||
{
|
||||
%scopeDepth--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(%insideFunction && strIsMatchExpr("*{*", %line))
|
||||
{
|
||||
%scopeDepth++;
|
||||
}
|
||||
if(%insideFunction && strIsMatchExpr("*}*", %line))
|
||||
{
|
||||
%scopeDepth--;
|
||||
|
||||
if(%scopeDepth == 0) //we've fully backed out of the function scope, so resolve back to the parent
|
||||
{
|
||||
%insideFunction = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(%insideFunction && strIsMatchExpr(%findText, %line))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
%fileObj.close();
|
||||
}
|
||||
|
||||
return %lineId;
|
||||
}
|
||||
|
||||
function Tools::insertInFile(%file, %insertLineId, %insertText, %insertBefore)
|
||||
{
|
||||
%fileOutput = new ArrayObject(){};
|
||||
%fileObj = new FileObject(){};
|
||||
|
||||
if ( %fileObj.openForRead( %file ) )
|
||||
{
|
||||
%lineId = 0;
|
||||
while ( !%fileObj.isEOF() )
|
||||
{
|
||||
%line = %fileObj.readLine();
|
||||
|
||||
if(%insertLineId == %lineId)
|
||||
{
|
||||
if(!%insertBefore || %insertBefore $= "")
|
||||
{
|
||||
%fileOutput.add(%line);
|
||||
%fileOutput.add(%insertText);
|
||||
}
|
||||
else
|
||||
{
|
||||
%fileOutput.add(%insertText);
|
||||
%fileOutput.add(%line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
%fileOutput.add(%line);
|
||||
}
|
||||
|
||||
%lineId++;
|
||||
}
|
||||
%fileObj.close();
|
||||
}
|
||||
|
||||
if ( %fileObj.openForWrite( %file ) )
|
||||
{
|
||||
for(%i=0; %i < %fileOutput.count(); %i++)
|
||||
{
|
||||
%line = %fileOutput.getKey(%i);
|
||||
|
||||
%fileObj.writeLine(%line);
|
||||
}
|
||||
%fileObj.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -301,6 +301,10 @@ function ESettingsWindow::getGeneralSettings(%this)
|
|||
SettingsInspector.addSettingsField("WorldEditor/AutosaveInterval", "Autosave Interval(in minutes)", "int", "");
|
||||
SettingsInspector.endGroup();
|
||||
|
||||
SettingsInspector.startGroup("SubScenes");
|
||||
SettingsInspector.addSettingsField("WorldEditor/subSceneCreateScalar", "SubScene Creation Scalar", "float", "Amount to scale SubScene's bounds by when creating from scene objects.", "1.5");
|
||||
SettingsInspector.endGroup();
|
||||
|
||||
SettingsInspector.startGroup("Paths");
|
||||
//SettingsInspector.addSettingsField("WorldEditor/torsionPath", "Torsion Path", "filename", "");
|
||||
SettingsInspector.endGroup();
|
||||
|
|
|
|||
|
|
@ -375,6 +375,8 @@
|
|||
name="orthoShowGrid">1</Setting>
|
||||
<Setting
|
||||
name="startupMode">Blank Level</Setting>
|
||||
<Setting
|
||||
name="subSceneCreateScalar">2</Setting>
|
||||
<Setting
|
||||
name="torsionPath">AssetWork_Debug.exe</Setting>
|
||||
<Setting
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ $guiContent = new GuiControl() {
|
|||
Profile = "ToolsGuiButtonProfile";
|
||||
HorizSizing = "left";
|
||||
VertSizing = "bottom";
|
||||
Position = "290 22";
|
||||
Position = "269 22";
|
||||
Extent = "16 16";
|
||||
MinExtent = "8 2";
|
||||
canSave = "1";
|
||||
|
|
@ -496,7 +496,7 @@ $guiContent = new GuiControl() {
|
|||
Profile = "ToolsGuiButtonProfile";
|
||||
HorizSizing = "left";
|
||||
VertSizing = "bottom";
|
||||
Position = "311 22";
|
||||
Position = "290 22";
|
||||
Extent = "16 16";
|
||||
MinExtent = "8 2";
|
||||
canSave = "1";
|
||||
|
|
@ -512,6 +512,30 @@ $guiContent = new GuiControl() {
|
|||
useModifiers = "1";
|
||||
};
|
||||
|
||||
new GuiBitmapButtonCtrl(EWAddSceneGroupButton) {
|
||||
canSaveDynamicFields = "0";
|
||||
internalName = "AddSceneGroup";
|
||||
Enabled = "1";
|
||||
isContainer = "0";
|
||||
Profile = "ToolsGuiButtonProfile";
|
||||
HorizSizing = "left";
|
||||
VertSizing = "bottom";
|
||||
Position = "311 22";
|
||||
Extent = "16 16";
|
||||
MinExtent = "8 2";
|
||||
canSave = "1";
|
||||
Visible = "1";
|
||||
tooltipprofile = "ToolsGuiToolTipProfile";
|
||||
ToolTip = "Add Scene Group";
|
||||
hovertime = "1000";
|
||||
bitmapAsset = "ToolsModule:add_simgroup_btn_n_image";
|
||||
buttonType = "PushButton";
|
||||
groupNum = "-1";
|
||||
text = "";
|
||||
useMouseEvents = "0";
|
||||
useModifiers = "1";
|
||||
};
|
||||
|
||||
new GuiBitmapButtonCtrl() {
|
||||
canSaveDynamicFields = "0";
|
||||
internalName = "DeleteSelection";
|
||||
|
|
|
|||
|
|
@ -2026,7 +2026,7 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj )
|
|||
%popup.item[ 0 ] = "Delete" TAB "" TAB "EditorMenuEditDelete();";
|
||||
%popup.item[ 1 ] = "Group" TAB "" TAB "EWorldEditor.addSimGroup( true );";
|
||||
%popup.item[ 2 ] = "-";
|
||||
%popup.item[ 3 ] = "Make select a Sub-Level" TAB "" TAB "MakeSelectionASublevel();";
|
||||
%popup.item[ 3 ] = "Make selected a Sub-Level" TAB "" TAB "MakeSelectionASublevel();";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2122,6 +2122,14 @@ function EditorTree::onRightMouseUp( %this, %itemId, %mouse, %obj )
|
|||
%popup.enableItem(15, true);
|
||||
}
|
||||
}
|
||||
else if(%obj.getClassName() $= "SimGroup" ||
|
||||
%obj.getClassName() $= "SceneGroup")
|
||||
{
|
||||
//if it's ACTUALLY a SimGroup or SceneGroup, have the ability to
|
||||
//upconvert to SubScene
|
||||
%popup.item[ 12 ] = "-";
|
||||
%popup.item[ 13 ] = "Convert to SubScene" TAB "" TAB "EWorldEditor.createSelectedAsSubScene( " @ %popup.object @ " );";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2161,7 +2169,7 @@ function EditorTree::isValidDragTarget( %this, %id, %obj )
|
|||
if( %obj.name $= "CameraBookmarks" )
|
||||
return EWorldEditor.areAllSelectedObjectsOfType( "CameraBookmark" );
|
||||
else
|
||||
return ( %obj.getClassName() $= "SimGroup" || %obj.isMemberOfClass("Scene"));
|
||||
return ( %obj.getClassName() $= "SimGroup" || %obj.isMemberOfClass("Scene") || %obj.isMemberOfClass("SceneGroup"));
|
||||
}
|
||||
|
||||
function EditorTree::onBeginReparenting( %this )
|
||||
|
|
@ -2602,6 +2610,77 @@ function EWorldEditor::addSimGroup( %this, %groupCurrentSelection )
|
|||
%this.syncGui();
|
||||
}
|
||||
|
||||
function EWorldEditor::addSceneGroup( %this, %groupCurrentSelection )
|
||||
{
|
||||
%activeSelection = %this.getActiveSelection();
|
||||
if ( %groupCurrentSelection && %activeSelection.getObjectIndex( getScene(0) ) != -1 )
|
||||
{
|
||||
toolsMessageBoxOK( "Error", "Cannot add Scene to a new SceneGroup" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Find our parent.
|
||||
|
||||
%parent = getScene(0);
|
||||
if( !%groupCurrentSelection && isObject( %activeSelection ) && %activeSelection.getCount() > 0 )
|
||||
{
|
||||
%firstSelectedObject = %activeSelection.getObject( 0 );
|
||||
if( %firstSelectedObject.isMemberOfClass( "SimGroup" ) )
|
||||
%parent = %firstSelectedObject;
|
||||
else if( %firstSelectedObject.getId() != getScene(0).getId() )
|
||||
%parent = %firstSelectedObject.parentGroup;
|
||||
}
|
||||
|
||||
// If we are about to do a group-selected as well,
|
||||
// starting recording an undo compound.
|
||||
|
||||
if( %groupCurrentSelection )
|
||||
Editor.getUndoManager().pushCompound( "Group Selected" );
|
||||
|
||||
// Create the SimGroup.
|
||||
|
||||
%object = new SceneGroup()
|
||||
{
|
||||
parentGroup = %parent;
|
||||
};
|
||||
MECreateUndoAction::submit( %object );
|
||||
|
||||
// Put selected objects into the group, if requested.
|
||||
|
||||
if( %groupCurrentSelection && isObject( %activeSelection ) )
|
||||
{
|
||||
%undo = UndoActionReparentObjects::create( EditorTree );
|
||||
|
||||
%numObjects = %activeSelection.getCount();
|
||||
for( %i = 0; %i < %numObjects; %i ++ )
|
||||
{
|
||||
%sel = %activeSelection.getObject( %i );
|
||||
%undo.add( %sel, %sel.parentGroup, %object );
|
||||
%object.add( %sel );
|
||||
}
|
||||
|
||||
%undo.addToManager( Editor.getUndoManager() );
|
||||
}
|
||||
|
||||
// Stop recording for group-selected.
|
||||
|
||||
if( %groupCurrentSelection )
|
||||
Editor.getUndoManager().popCompound();
|
||||
|
||||
// When not grouping selection, make the newly created SimGroup the
|
||||
// current selection.
|
||||
|
||||
if( !%groupCurrentSelection )
|
||||
{
|
||||
EWorldEditor.clearSelection();
|
||||
EWorldEditor.selectObject( %object );
|
||||
}
|
||||
|
||||
// Refresh the Gui.
|
||||
|
||||
%this.syncGui();
|
||||
}
|
||||
|
||||
function EWorldEditor::toggleLockChildren( %this, %simGroup )
|
||||
{
|
||||
foreach( %child in %simGroup )
|
||||
|
|
@ -2869,6 +2948,16 @@ function EWAddSimGroupButton::onCtrlClick( %this )
|
|||
EWorldEditor.addSimGroup( true );
|
||||
}
|
||||
|
||||
function EWAddSceneGroupButton::onDefaultClick( %this )
|
||||
{
|
||||
EWorldEditor.addSceneGroup();
|
||||
}
|
||||
|
||||
function EWAddSceneGroupButton::onCtrlClick( %this )
|
||||
{
|
||||
EWorldEditor.addSceneGroup( true );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
function EWToolsToolbar::reset( %this )
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ EditorSettings.setDefaultValue( "orthoFOV", "50" );
|
|||
EditorSettings.setDefaultValue( "orthoShowGrid", "1" );
|
||||
EditorSettings.setDefaultValue( "AutosaveInterval", "5" );
|
||||
EditorSettings.setDefaultValue( "forceSidebarToSide", "1" );
|
||||
EditorSettings.setDefaultValue( "subSceneCreateScalar", $SubScene::createScalar );
|
||||
|
||||
if( isFile( "C:/Program Files/Torsion/Torsion.exe" ) )
|
||||
EditorSettings.setDefaultValue( "torsionPath", "C:/Program Files/Torsion/Torsion.exe" );
|
||||
|
|
|
|||
|
|
@ -554,3 +554,77 @@ function simGroup::onInspectPostApply(%this)
|
|||
%this.callOnChildren("setHidden",%this.hidden);
|
||||
%this.callOnChildren("setLocked",%this.locked);
|
||||
}
|
||||
|
||||
function simGroup::SelectFiteredObjects(%this, %min, %max)
|
||||
{
|
||||
EWorldEditor.clearSelection();
|
||||
%this.callOnChildren("filteredSelect", %min, %max );
|
||||
}
|
||||
|
||||
function SceneObject::filteredSelect(%this, %min, %max)
|
||||
{
|
||||
%box = %this.getWorldBox();
|
||||
%xlength = mAbs(getWord(%box,0) - getWord(%box,3));
|
||||
%ylength = mAbs(getWord(%box,1) - getWord(%box,4));
|
||||
%Zlength = mAbs(getWord(%box,2) - getWord(%box,5));
|
||||
%diagSq = mPow(%xlength,2)+mPow(%ylength,2)+mPow(%Zlength,2);
|
||||
if (%diagSq > mPow(%min,2) && %diagSq < mPow(%max,2))
|
||||
{
|
||||
EWorldEditor.selectObject(%this);
|
||||
}
|
||||
}
|
||||
|
||||
function simGroup::onInspect(%obj, %inspector)
|
||||
{
|
||||
//Find the 'Editing' group in the inspector
|
||||
%group = %inspector.findExistentGroup("Editing");
|
||||
if(isObject(%group))
|
||||
{
|
||||
//We add a field of the type 'SimGroupSelectionButton'. This isn't a 'real' type, so when the inspector group tries to add it
|
||||
//it will route down through GuiInspectorGroup(the namespace of %group) and call onConstructField in an attemp to see if there's any
|
||||
//script defined functions that can build a field of that type.
|
||||
//We happen to define the required 'build @ <fieldTypeName> @ Field()' function below, allowing us to build out the custom field type
|
||||
%group.addField("minSize", "F32", "min diagonal size of objects");
|
||||
%group.addField("maxSize", "F32", "max diagonal size of objects");
|
||||
%group.addField("select", "SimGroupSelectionButton", "Select filtered objects");
|
||||
}
|
||||
}
|
||||
|
||||
function GuiInspectorGroup::buildSimGroupSelectionButtonField(%this, %fieldName, %fieldLabel, %fieldDesc,
|
||||
%fieldDefaultVal, %fieldDataVals, %callback, %ownerObj)
|
||||
{
|
||||
%container = new GuiControl() {
|
||||
canSaveDynamicFields = "0";
|
||||
Profile = "EditorContainerProfile";
|
||||
HorizSizing = "right";
|
||||
VertSizing = "bottom";
|
||||
Position = "0 0";
|
||||
Extent = "300 18";
|
||||
MinExtent = "8 2";
|
||||
canSave = "0";
|
||||
Visible = "1";
|
||||
hovertime = "100";
|
||||
tooltip = "";// %tooltip;
|
||||
tooltipProfile = "EditorToolTipProfile";
|
||||
|
||||
new GuiButtonCtrl() {
|
||||
canSaveDynamicFields = "0";
|
||||
Profile = "ToolsGuiButtonProfile";
|
||||
HorizSizing = "right";
|
||||
VertSizing = "bottom";
|
||||
Position = "16 3";
|
||||
Extent = "300 18";
|
||||
MinExtent = "8 2";
|
||||
canSave = "0";
|
||||
Visible = "1";
|
||||
hovertime = "100";
|
||||
tooltip = ""; //%tooltip;
|
||||
tooltipProfile = "EditorToolTipProfile";
|
||||
text = %fieldName;
|
||||
maxLength = "1024";
|
||||
command = %ownerObj @ ".SelectFiteredObjects("@ %ownerObj.minSize @","@ %ownerObj.maxSize @");";
|
||||
};
|
||||
};
|
||||
|
||||
%this-->stack.add(%container);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -329,9 +329,6 @@ function EditorSaveMission()
|
|||
|
||||
if(EWorldEditor.isDirty || ETerrainEditor.isMissionDirty)
|
||||
{
|
||||
//Inform objects a save is happening, in case there is any special pre-save behavior a class needs to do
|
||||
getScene(0).callOnChildren("onSaving", $Server::MissionFile);
|
||||
|
||||
getScene(0).save($Server::MissionFile);
|
||||
|
||||
}
|
||||
|
|
@ -604,18 +601,20 @@ function EditorOpenSceneAppend(%levelAsset)
|
|||
|
||||
function MakeSelectionASublevel()
|
||||
{
|
||||
/*%size = EWorldEditor.getSelectionSize();
|
||||
%size = EWorldEditor.getSelectionSize();
|
||||
if ( %size == 0 )
|
||||
return;
|
||||
|
||||
//Make a new Scene object
|
||||
|
||||
//Make a group for the objects to go into to be processed as into a
|
||||
//subscene
|
||||
%group = new SimGroup();
|
||||
for(%i=0; %i < %size; %i++)
|
||||
{
|
||||
|
||||
%group.add(EWorldEditor.getSelectedObject(%i));
|
||||
}
|
||||
%a = EWorldEditor.getSelectedObject(0);
|
||||
%b = EWorldEditor.getSelectedObject(1);*/
|
||||
|
||||
//Now that we have a group, process it into a subscene
|
||||
EWorldEditor.createSelectedAsSubScene(%group);
|
||||
}
|
||||
|
||||
function updateEditorRecentLevelsList(%levelAssetId)
|
||||
|
|
|
|||
Loading…
Reference in a new issue