Merge pull request #1325 from Areloch/Standardized_AB_AssetManagement

Updates most of the handling of asset types to follow a more standardized type-registration system.
This commit is contained in:
Brian Roberts 2025-04-29 13:19:50 -05:00 committed by GitHub
commit 798936ebd2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
45 changed files with 2369 additions and 3703 deletions

View file

@ -24,7 +24,7 @@ IMPLEMENT_CALLBACK(SubScene, onUnloaded, void, (), (),
"@brief Called when a subScene has been unloaded and has game mode implications.\n\n");
SubScene::SubScene() :
mLevelAssetId(StringTable->EmptyString()),
mSubSceneAssetId(StringTable->EmptyString()),
mGameModesNames(StringTable->EmptyString()),
mScopeDistance(-1),
mLoaded(false),
@ -67,7 +67,7 @@ void SubScene::initPersistFields()
{
addGroup("SubScene");
addField("isGlobalLayer", TypeBool, Offset(mGlobalLayer, SubScene), "");
INITPERSISTFIELD_LEVELASSET(Level, SubScene, "The level asset to load.");
INITPERSISTFIELD_SUBSCENEASSET(SubScene, SubScene, "The subscene asset to load.");
addField("tickPeriodMS", TypeS32, Offset(mTickPeriodMS, SubScene), "evaluation rate (ms)");
addField("gameModes", TypeGameModeList, Offset(mGameModesNames, SubScene), "The game modes that this subscene is associated with.");
endGroup("SubScene");
@ -265,13 +265,13 @@ void SubScene::processTick(const Move* move)
void SubScene::_onFileChanged(const Torque::Path& path)
{
if(mLevelAsset.isNull() || Torque::Path(mLevelAsset->getLevelPath()) != path)
if(mSubSceneAsset.isNull() || Torque::Path(mSubSceneAsset->getLevelPath()) != path)
return;
if (mSaving)
return;
AssertFatal(path == mLevelAsset->getLevelPath(), "Prefab::_onFileChanged - path does not match filename.");
AssertFatal(path == mSubSceneAsset->getLevelPath(), "SubScene::_onFileChanged - path does not match filename.");
_closeFile(false);
_loadFile(false);
@ -307,9 +307,9 @@ void SubScene::_closeFile(bool removeFileNotify)
_removeContents(SimGroupIterator(this));
if (removeFileNotify && mLevelAsset.notNull() && mLevelAsset->getLevelPath() != StringTable->EmptyString())
if (removeFileNotify && mSubSceneAsset.notNull() && mSubSceneAsset->getLevelPath() != StringTable->EmptyString())
{
Torque::FS::RemoveChangeNotification(mLevelAsset->getLevelPath(), this, &SubScene::_onFileChanged);
Torque::FS::RemoveChangeNotification(mSubSceneAsset->getLevelPath(), this, &SubScene::_onFileChanged);
}
mGameModesList.clear();
@ -319,18 +319,18 @@ 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())
if(mSubSceneAsset.isNull() || mSubSceneAsset->getLevelPath() == StringTable->EmptyString())
return;
String evalCmd = String::ToString("exec(\"%s\");", mLevelAsset->getLevelPath());
String evalCmd = String::ToString("exec(\"%s\");", mSubSceneAsset->getLevelPath());
String instantGroup = Con::getVariable("InstantGroup");
Con::setIntVariable("InstantGroup", this->getId());
Con::evaluate((const char*)evalCmd.c_str(), false, mLevelAsset->getLevelPath());
Con::evaluate((const char*)evalCmd.c_str(), false, mSubSceneAsset->getLevelPath());
Con::setVariable("InstantGroup", instantGroup.c_str());
if (addFileNotify)
Torque::FS::AddChangeNotification(mLevelAsset->getLevelPath(), this, &SubScene::_onFileChanged);
Torque::FS::AddChangeNotification(mSubSceneAsset->getLevelPath(), this, &SubScene::_onFileChanged);
}
void SubScene::load()
@ -432,7 +432,7 @@ bool SubScene::save()
if (size() == 0 || !isLoaded())
return false;
if (mLevelAsset.isNull())
if (mSubSceneAsset.isNull())
return false;
if (mSaving)
@ -446,7 +446,7 @@ bool SubScene::save()
PersistenceManager prMger;
StringTableEntry levelPath = mLevelAsset->getLevelPath();
StringTableEntry levelPath = mSubSceneAsset->getLevelPath();
FileStream fs;
fs.open(levelPath, Torque::FS::File::Write);
@ -460,7 +460,7 @@ bool SubScene::save()
{
if ((*itr)->isMethod("onSaving"))
{
Con::executef((*itr), "onSaving", mLevelAssetId);
Con::executef((*itr), "onSaving", mSubSceneAssetId);
}
if (childObj->getGroup() == this)
@ -481,14 +481,14 @@ bool SubScene::save()
bool saveSuccess = false;
//Get the level asset
if (mLevelAsset.isNull())
if (mSubSceneAsset.isNull())
return saveSuccess;
//update the gamemode list as well
mLevelAsset->setDataField(StringTable->insert("gameModesNames"), NULL, StringTable->insert(mGameModesNames));
mSubSceneAsset->setDataField(StringTable->insert("gameModesNames"), NULL, StringTable->insert(mGameModesNames));
//Finally, save
saveSuccess = mLevelAsset->saveAsset();
saveSuccess = mSubSceneAsset->saveAsset();
mSaving = false;

View file

@ -5,8 +5,8 @@
#ifndef SCENE_GROUP_H
#include "SceneGroup.h"
#endif
#ifndef LEVEL_ASSET_H
#include "assets/LevelAsset.h"
#ifndef SUBSCENE_ASSET_H
#include "assets/SubSceneAsset.h"
#endif
class GameMode;
@ -21,13 +21,13 @@ public:
NextFreeMask = Parent::NextFreeMask << 0
};
void onLevelChanged() {}
void onSubSceneChanged() {}
protected:
static bool smTransformChildren;
private:
DECLARE_LEVELASSET(SubScene, Level, onLevelChanged);
DECLARE_SUBSCENEASSET(SubScene, SubScene, onSubSceneChanged);
StringTableEntry mGameModesNames;
Vector<GameMode*> mGameModesList;
@ -61,7 +61,7 @@ public:
static void initPersistFields();
static void consoleInit();
StringTableEntry getTypeHint() const override { return (getLevelAsset()) ? getLevelAsset()->getAssetName() : StringTable->EmptyString(); }
StringTableEntry getTypeHint() const override { return (getSubSceneAsset()) ? getSubSceneAsset()->getAssetName() : StringTable->EmptyString(); }
// SimObject
bool onAdd() override;
@ -122,6 +122,6 @@ public:
DECLARE_CALLBACK(void, onLoaded, ());
DECLARE_CALLBACK(void, onUnloaded, ());
DECLARE_ASSET_SETGET(SubScene, Level);
DECLARE_ASSET_SETGET(SubScene, SubScene);
};
#endif

View file

@ -178,3 +178,17 @@ void CppAsset::onAssetRefresh(void)
mHeaderPath = getOwned() ? expandAssetFilePath(mHeaderFile) : mHeaderPath;
}
DefineEngineMethod(CppAsset, getCodePath, const char*, (), ,
"Gets the code file filepath of this asset.\n"
"@return File path of the code file.")
{
return object->getCppFilePath();
}
DefineEngineMethod(CppAsset, getHeaderPath, const char*, (), ,
"Gets the header file filepath of this asset.\n"
"@return File path of the header file.")
{
return object->getHeaderFilePath();
}

View file

@ -66,6 +66,9 @@ public:
void setHeaderFile(const char* pHeaderFile);
inline StringTableEntry getHeaderFile(void) const { return mHeaderFile; };
inline StringTableEntry getCppFilePath(void) const { return mCodePath; };
inline StringTableEntry getHeaderFilePath(void) const { return mHeaderPath; };
protected:
void initializeAsset(void) override;
void onAssetRefresh(void) override;
@ -73,9 +76,6 @@ protected:
static bool setCppFile(void *obj, const char *index, const char *data) { static_cast<CppAsset*>(obj)->setCppFile(data); return false; }
static const char* getCppFile(void* obj, const char* data) { return static_cast<CppAsset*>(obj)->getCppFile(); }
inline StringTableEntry getCppFilePath(void) const { return mCodePath; };
inline StringTableEntry getHeaderFilePath(void) const { return mHeaderPath; };
static bool setHeaderFile(void *obj, const char *index, const char *data) { static_cast<CppAsset*>(obj)->setHeaderFile(data); return false; }
static const char* getHeaderFile(void* obj, const char* data) { return static_cast<CppAsset*>(obj)->getHeaderFile(); }
};

View file

@ -101,7 +101,7 @@ ConsoleSetType(TypeLevelAssetId)
}
//-----------------------------------------------------------------------------
LevelAsset::LevelAsset() : AssetBase(), mIsSubLevel(false)
LevelAsset::LevelAsset() : AssetBase()
{
mLevelName = StringTable->EmptyString();
mLevelFile = StringTable->EmptyString();
@ -117,7 +117,6 @@ LevelAsset::LevelAsset() : AssetBase(), mIsSubLevel(false)
mNavmeshPath = StringTable->EmptyString();
mGameModesNames = StringTable->EmptyString();
mMainLevelAsset = StringTable->EmptyString();
mEditorFile = StringTable->EmptyString();
mBakedSceneFile = StringTable->EmptyString();
@ -158,7 +157,6 @@ void LevelAsset::initPersistFields()
addProtectedField("BakedSceneFile", TypeAssetLooseFilePath, Offset(mBakedSceneFile, LevelAsset),
&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("gameModesNames", TypeString, Offset(mGameModesNames, LevelAsset), "Name of the Game Mode to be used with this level");
}
@ -481,15 +479,8 @@ GuiControl* GuiInspectorTypeLevelAssetPtr::constructEditControl()
// Create "Open in Editor" button
mEditButton = new GuiBitmapButtonCtrl();
String setSubSceneValue = "$createLevelAssetIsSubScene = \"\";";
if(dynamic_cast<SubScene*>(mInspector->getInspectObject()) != NULL)
{
setSubSceneValue = "$createLevelAssetIsSubScene = true;";
}
dSprintf(szBuffer, sizeof(szBuffer), "$createAndAssignField = %s; %s AssetBrowser.setupCreateNewAsset(\"LevelAsset\", AssetBrowser.selectedModule, \"createAndAssignLevelAsset\");",
getIdString(),
setSubSceneValue.c_str());
dSprintf(szBuffer, sizeof(szBuffer), "$createAndAssignField = %s; AssetBrowser.setupCreateNewAsset(\"LevelAsset\", AssetBrowser.selectedModule, \"createAndAssignLevelAsset\");",
getIdString());
mEditButton->setField("Command", szBuffer);
char bitmapName[512] = "ToolsModule:iconAdd_image";

View file

@ -66,9 +66,6 @@ class LevelAsset : public AssetBase
StringTableEntry mEditorFile;
StringTableEntry mBakedSceneFile;
bool mIsSubLevel;
StringTableEntry mMainLevelAsset;
StringTableEntry mGameModesNames;
Vector<AssetBase*> mAssetDependencies;

View file

@ -0,0 +1,166 @@
#include "SubSceneAsset.h"
#include "T3D/SubScene.h"
IMPLEMENT_CONOBJECT(SubSceneAsset);
ConsoleType(SubSceneAssetPtr, TypeSubSceneAssetPtr, const char*, "")
//-----------------------------------------------------------------------------
ConsoleGetType(TypeSubSceneAssetPtr)
{
// Fetch asset Id.
return *((const char**)(dptr));
}
//-----------------------------------------------------------------------------
ConsoleSetType(TypeSubSceneAssetPtr)
{
// Was a single argument specified?
if (argc == 1)
{
// Yes, so fetch field value.
*((const char**)dptr) = StringTable->insert(argv[0]);
return;
}
// Warn.
Con::warnf("(TypeSubSceneAssetPtr) - Cannot set multiple args to a single asset.");
}
//-----------------------------------------------------------------------------
ConsoleType(assetIdString, TypeSubSceneAssetId, const char*, "")
ConsoleGetType(TypeSubSceneAssetId)
{
// Fetch asset Id.
return *((const char**)(dptr));
}
ConsoleSetType(TypeSubSceneAssetId)
{
// Was a single argument specified?
if (argc == 1)
{
*((const char**)dptr) = StringTable->insert(argv[0]);
return;
}
// Warn.
Con::warnf("(TypeSubSceneAssetId) - Cannot set multiple args to a single asset.");
}
SubSceneAsset::SubSceneAsset() : LevelAsset()
{
}
SubSceneAsset::~SubSceneAsset()
{
}
void SubSceneAsset::initPersistFields()
{
docsURL;
Parent::initPersistFields();
}
//-----------------------------------------------------------------------------
// GuiInspectorTypeAssetId
//-----------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiInspectorTypeSubSceneAssetPtr);
ConsoleDocClass(GuiInspectorTypeSubSceneAssetPtr,
"@brief Inspector field type for Shapes\n\n"
"Editor use only.\n\n"
"@internal"
);
void GuiInspectorTypeSubSceneAssetPtr::consoleInit()
{
Parent::consoleInit();
ConsoleBaseType::getType(TypeSubSceneAssetPtr)->setInspectorFieldType("GuiInspectorTypeSubSceneAssetPtr");
}
GuiControl* GuiInspectorTypeSubSceneAssetPtr::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(\"SubSceneAsset\", \"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(\"SubSceneAsset\", AssetBrowser.selectedModule);",
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 GuiInspectorTypeSubSceneAssetPtr::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(GuiInspectorTypeSubSceneAssetId);
ConsoleDocClass(GuiInspectorTypeSubSceneAssetId,
"@brief Inspector field type for SubScene\n\n"
"Editor use only.\n\n"
"@internal"
);
void GuiInspectorTypeSubSceneAssetId::consoleInit()
{
Parent::consoleInit();
ConsoleBaseType::getType(TypeSubSceneAssetId)->setInspectorFieldType("GuiInspectorTypeSubSceneAssetId");
}

View file

@ -0,0 +1,113 @@
#pragma once
#ifndef SUBSCENE_ASSET_H
#define SUBSCENE_ASSET_H
#ifndef LEVEL_ASSET_H
#include "LevelAsset.h"
#endif
#ifndef _ASSET_DEFINITION_H_
#include "assets/assetDefinition.h"
#endif
#ifndef _GUI_INSPECTOR_TYPES_H_
#include "gui/editor/guiInspectorTypes.h"
#endif
class SubSceneAsset : public LevelAsset
{
typedef LevelAsset Parent;
public:
SubSceneAsset();
virtual ~SubSceneAsset();
/// Engine.
static void initPersistFields();
/// Declare Console Object.
DECLARE_CONOBJECT(SubSceneAsset);
};
#ifdef TORQUE_TOOLS
class GuiInspectorTypeSubSceneAssetPtr : public GuiInspectorTypeFileName
{
typedef GuiInspectorTypeFileName Parent;
public:
GuiBitmapButtonCtrl* mEditButton;
DECLARE_CONOBJECT(GuiInspectorTypeSubSceneAssetPtr);
static void consoleInit();
GuiControl* constructEditControl() override;
bool updateRects() override;
};
class GuiInspectorTypeSubSceneAssetId : public GuiInspectorTypeSubSceneAssetPtr
{
typedef GuiInspectorTypeSubSceneAssetPtr Parent;
public:
DECLARE_CONOBJECT(GuiInspectorTypeSubSceneAssetId);
static void consoleInit();
};
#endif
DefineConsoleType(TypeSubSceneAssetPtr, SubSceneAsset)
DefineConsoleType(TypeSubSceneAssetId, String)
#pragma region Singular Asset Macros
//Singular assets
/// <Summary>
/// Declares an SubScene asset
/// This establishes the assetId, asset and legacy filepath fields, along with supplemental getter and setter functions
/// </Summary>
#define DECLARE_SUBSCENEASSET(className, name, changeFunc) public: \
StringTableEntry m##name##AssetId;\
AssetPtr<SubSceneAsset> m##name##Asset;\
public: \
const AssetPtr<SubSceneAsset> & get##name##Asset() const { return m##name##Asset; }\
void set##name##Asset(const AssetPtr<SubSceneAsset> &_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_SUBSCENEASSET(name, consoleClass, docs) \
addProtectedField(assetText(name, Asset), TypeSubSceneAssetId, Offset(m##name##AssetId, consoleClass), _set##name##Data, &defaultProtectedGetFn, assetDoc(name, asset docs.));
#pragma endregion
#endif // SUBSCENE_ASSET_H

View file

@ -1563,6 +1563,53 @@ bool AssetManager::restoreAssetTags( void )
//-----------------------------------------------------------------------------
const char* AssetManager::getAssetLooseFiles(const char* pAssetId)
{
// Debug Profiling.
PROFILE_SCOPE(AssetManager_getAssetLooseFIles);
// Sanity!
AssertFatal(pAssetId != NULL, "Cannot look up NULL asset Id.");
// Find asset.
AssetDefinition* pAssetDefinition = findAsset(pAssetId);
// Did we find the asset?
if (pAssetDefinition == NULL)
{
// No, so warn.
Con::warnf("Asset Manager: Failed to find asset Id '%s' as it does not exist.", pAssetId);
return String::EmptyString;
}
// Info.
if (mEchoInfo)
{
Con::printSeparator();
Con::printf("Asset Manager: Started getting loose files of Asset Id '%s'...", pAssetId);
}
String looseFileList = "";
Vector<StringTableEntry>& assetLooseFiles = pAssetDefinition->mAssetLooseFiles;
for (Vector<StringTableEntry>::iterator looseFileItr = assetLooseFiles.begin(); looseFileItr != assetLooseFiles.end(); ++looseFileItr)
{
// Fetch loose file.
StringTableEntry looseFile = *looseFileItr;
looseFileList += looseFile;
if (looseFileItr != assetLooseFiles.end())
looseFileList += "\t";
}
char* ret = Con::getReturnBuffer(1024);
dSprintf(ret, 1024, "%s", looseFileList.c_str());
return ret;
}
//-----------------------------------------------------------------------------
S32 QSORT_CALLBACK descendingAssetDefinitionLoadCount(const void* a, const void* b)
{
// Debug Profiling.

View file

@ -341,6 +341,9 @@ public:
bool restoreAssetTags( void );
inline AssetTagsManifest* getAssetTags( void ) const { return mAssetTagsManifest; }
/// Loose File management
const char* getAssetLooseFiles(const char* pAssetId);
/// Info.
inline U32 getDeclaredAssetCount( void ) const { return (U32)mDeclaredAssets.size(); }
inline U32 getReferencedAssetCount( void ) const { return (U32)mReferencedAssets.size(); }

View file

@ -432,6 +432,20 @@ DefineEngineMethod(AssetManager, getAssetTags, S32, (), ,
//-----------------------------------------------------------------------------
DefineEngineMethod(AssetManager, getAssetLooseFiles, const char*, (const char* assetId), (""),
"Finds the specified asset Id and gets a list of its loose files.\n"
"@param assetId The selected asset Id.\n"
"@return A tab-delinated list of loose files associated to the assetId.\n")
{
// Fetch asset Id.
const char* pAssetId = assetId;
// Delete asset.
return object->getAssetLooseFiles(pAssetId);
}
//-----------------------------------------------------------------------------
DefineEngineMethod(AssetManager, findAllAssets, S32, (const char* assetQuery, bool ignoreInternal, bool ignorePrivate), ("", true, true),
"Performs an asset query searching for all assets optionally ignoring internal assets.\n"
"@param assetQuery The asset query object that will be populated with the results.\n"