From 98a4e7fb12a918a35b258661c9a235b6798a7762 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Tue, 14 Sep 2021 17:49:27 -0500 Subject: [PATCH 1/9] dedicated gfx device surpression augments $Video::forceDisplayAdapter = -1; to force usage of GFXAdapterType::NullDevice skips trying to open a splash window for dedicated servers bypasses guicanvas window display if window does not exist --- Engine/source/gfx/gfxInit.cpp | 2 +- Engine/source/gui/core/guiCanvas.cpp | 14 ++++++++------ Templates/BaseGame/game/main.tscript.in | 14 +++++++++----- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Engine/source/gfx/gfxInit.cpp b/Engine/source/gfx/gfxInit.cpp index b5d67206d..0a5c66466 100644 --- a/Engine/source/gfx/gfxInit.cpp +++ b/Engine/source/gfx/gfxInit.cpp @@ -290,7 +290,7 @@ GFXAdapter *GFXInit::getBestAdapterChoice() { S32 adapterIdx = dAtoi(adapterDevice.c_str()); if (adapterIdx == -1) - adapter = chooseAdapter(adapterType, outputDevice.c_str()); + adapter = chooseAdapter(NullDevice, outputDevice.c_str()); else adapter = chooseAdapter(adapterType, adapterIdx); } diff --git a/Engine/source/gui/core/guiCanvas.cpp b/Engine/source/gui/core/guiCanvas.cpp index 7cbea6d64..967c3e7d7 100644 --- a/Engine/source/gui/core/guiCanvas.cpp +++ b/Engine/source/gui/core/guiCanvas.cpp @@ -258,17 +258,19 @@ bool GuiCanvas::onAdd() // Make sure we're able to render. newDevice->setAllowRender( true ); - if(mDisplayWindow) + // NULL device returns a nullptr for getPlatformWindow + PlatformWindow* window = getPlatformWindow(); + if (mDisplayWindow && window) { - getPlatformWindow()->show(); + window->show(); WindowManager->setDisplayWindow(true); - getPlatformWindow()->setDisplayWindow(true); + window->setDisplayWindow(true); } - else + else if (window) { - getPlatformWindow()->hide(); + window->hide(); WindowManager->setDisplayWindow(false); - getPlatformWindow()->setDisplayWindow(false); + window->setDisplayWindow(false); } // Propagate add to parents. diff --git a/Templates/BaseGame/game/main.tscript.in b/Templates/BaseGame/game/main.tscript.in index 5d5569e7d..4e83ff2b2 100644 --- a/Templates/BaseGame/game/main.tscript.in +++ b/Templates/BaseGame/game/main.tscript.in @@ -1,10 +1,6 @@ $Core::windowIcon = "data/icon.png"; $Core::splashWindowImage = "data/splash.png"; -// Display a splash window immediately to improve app responsiveness before -// engine is initialized and main window created. -displaySplashWindow($Core::splashWindowImage); - // Console does something. setLogMode(6); @@ -20,6 +16,13 @@ ModuleDatabase.setModuleExtension("module"); ModuleDatabase.scanModules( "core", false ); ModuleDatabase.LoadExplicit( "CoreModule" ); +// Display a splash window immediately to improve app responsiveness before +// engine is initialized and main window created. +if ($Server::Dedicated == false) + displaySplashWindow($Core::splashWindowImage); +else + $Video::forceDisplayAdapter = -1; + //----------------------------------------------------------------------------- // Load any gameplay modules ModuleDatabase.scanModules( "data", false ); @@ -42,6 +45,7 @@ else } } -closeSplashWindow(); +if ($Server::Dedicated == false) + closeSplashWindow(); echo("Engine initialized..."); \ No newline at end of file From 17d1253ba29b97d74686e5f3eccb34755ebe1758 Mon Sep 17 00:00:00 2001 From: Areloch Date: Wed, 15 Sep 2021 00:41:23 -0500 Subject: [PATCH 2/9] Converts precipitationData to use sound asset macros Adds handling for soundProfile fields and lookups of sound assets by SFXProfile name in project importer --- Engine/source/T3D/fx/precipitation.cpp | 17 ++++---- Engine/source/T3D/fx/precipitation.h | 39 ++++++++++--------- .../pre40/T3Dpre4ProjectImporter.tscript | 2 +- .../scripts/projectImporter.tscript | 28 ++++++++++++- 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/Engine/source/T3D/fx/precipitation.cpp b/Engine/source/T3D/fx/precipitation.cpp index caebe48cd..91249fe2b 100644 --- a/Engine/source/T3D/fx/precipitation.cpp +++ b/Engine/source/T3D/fx/precipitation.cpp @@ -127,7 +127,7 @@ ConsoleDocClass( PrecipitationData, //---------------------------------------------------------- PrecipitationData::PrecipitationData() { - soundProfile = NULL; + INIT_SOUNDASSET(Sound); INIT_IMAGEASSET(Drop); @@ -143,8 +143,7 @@ PrecipitationData::PrecipitationData() void PrecipitationData::initPersistFields() { - addField( "soundProfile", TYPEID< SFXTrack >(), Offset(soundProfile, PrecipitationData), - "Looping SFXProfile effect to play while Precipitation is active." ); + INITPERSISTFIELD_SOUNDASSET(Sound, PrecipitationData, "Looping SFXProfile effect to play while Precipitation is active."); addProtectedField( "dropTexture", TypeFilename, Offset(mDropName, PrecipitationData), &_setDropData, &defaultProtectedGetFn, "@brief Texture filename for drop particles.\n\n" @@ -190,7 +189,7 @@ bool PrecipitationData::preload( bool server, String &errorStr ) if( Parent::preload( server, errorStr) == false) return false; - if( !server && !sfxResolve( &soundProfile, errorStr ) ) + if (!server && (mSoundAsset.isNull() || !mSoundAsset->getSfxProfile())) return false; return true; @@ -200,7 +199,8 @@ void PrecipitationData::packData(BitStream* stream) { Parent::packData(stream); - sfxWrite( stream, soundProfile ); + PACKDATA_SOUNDASSET(Sound); + //sfxWrite( stream, soundProfile ); PACKDATA_IMAGEASSET(Drop); @@ -217,7 +217,8 @@ void PrecipitationData::unpackData(BitStream* stream) { Parent::unpackData(stream); - sfxRead( stream, &soundProfile ); + UNPACKDATA_SOUNDASSET(Sound); + //sfxRead( stream, &soundProfile ); UNPACKDATA_IMAGEASSET(Drop); @@ -598,9 +599,9 @@ bool Precipitation::onNewDataBlock( GameBaseData *dptr, bool reload ) { SFX_DELETE( mAmbientSound ); - if ( mDataBlock->soundProfile ) + if ( mDataBlock->mSoundAsset && mDataBlock->mSoundAsset->getSfxProfile() ) { - mAmbientSound = SFX->createSource( mDataBlock->soundProfile, &getTransform() ); + mAmbientSound = SFX->createSource(mDataBlock->mSoundAsset->getSfxProfile(), &getTransform() ); if ( mAmbientSound ) mAmbientSound->play(); } diff --git a/Engine/source/T3D/fx/precipitation.h b/Engine/source/T3D/fx/precipitation.h index 58c8c44dd..0bb06e0f2 100644 --- a/Engine/source/T3D/fx/precipitation.h +++ b/Engine/source/T3D/fx/precipitation.h @@ -34,8 +34,9 @@ #endif #include "T3D/assets/ImageAsset.h" +#include "T3D/assets/SoundAsset.h" -class SFXTrack; +//class SFXTrack; class SFXSource; //-------------------------------------------------------------------------- @@ -45,30 +46,32 @@ class PrecipitationData : public GameBaseData typedef GameBaseData Parent; public: - SFXTrack* soundProfile; + //SFXTrack* soundProfile; + DECLARE_SOUNDASSET(PrecipitationData, Sound); + DECLARE_SOUNDASSET_SETGET(PrecipitationData, Sound); - DECLARE_IMAGEASSET(PrecipitationData, Drop, onDropChanged, GFXStaticTextureSRGBProfile); ///< Texture for drop particles - DECLARE_IMAGEASSET_SETGET(PrecipitationData, Drop); + DECLARE_IMAGEASSET(PrecipitationData, Drop, onDropChanged, GFXStaticTextureSRGBProfile); ///< Texture for drop particles + DECLARE_IMAGEASSET_SETGET(PrecipitationData, Drop); - StringTableEntry mDropShaderName; ///< The name of the shader used for raindrops + StringTableEntry mDropShaderName; ///< The name of the shader used for raindrops - DECLARE_IMAGEASSET(PrecipitationData, Splash, onSplashChanged, GFXStaticTextureSRGBProfile); ///< Texture for splash particles - DECLARE_IMAGEASSET_SETGET(PrecipitationData, Splash); + DECLARE_IMAGEASSET(PrecipitationData, Splash, onSplashChanged, GFXStaticTextureSRGBProfile); ///< Texture for splash particles + DECLARE_IMAGEASSET_SETGET(PrecipitationData, Splash); - StringTableEntry mSplashShaderName; ///< The name of the shader used for raindrops + StringTableEntry mSplashShaderName; ///< The name of the shader used for raindrops - S32 mDropsPerSide; ///< How many drops are on a side of the raindrop texture. - S32 mSplashesPerSide; ///< How many splash are on a side of the splash texture. + S32 mDropsPerSide; ///< How many drops are on a side of the raindrop texture. + S32 mSplashesPerSide; ///< How many splash are on a side of the splash texture. - PrecipitationData(); - DECLARE_CONOBJECT(PrecipitationData); - bool preload( bool server, String& errorStr ); - static void initPersistFields(); - virtual void packData(BitStream* stream); - virtual void unpackData(BitStream* stream); + PrecipitationData(); + DECLARE_CONOBJECT(PrecipitationData); + bool preload( bool server, String& errorStr ); + static void initPersistFields(); + virtual void packData(BitStream* stream); + virtual void unpackData(BitStream* stream); - void onDropChanged() {} - void onSplashChanged() {} + void onDropChanged() {} + void onSplashChanged() {} }; struct Raindrop diff --git a/Templates/BaseGame/game/tools/projectImporter/scripts/pre40/T3Dpre4ProjectImporter.tscript b/Templates/BaseGame/game/tools/projectImporter/scripts/pre40/T3Dpre4ProjectImporter.tscript index d996182dd..645bd38ca 100644 --- a/Templates/BaseGame/game/tools/projectImporter/scripts/pre40/T3Dpre4ProjectImporter.tscript +++ b/Templates/BaseGame/game/tools/projectImporter/scripts/pre40/T3Dpre4ProjectImporter.tscript @@ -919,7 +919,7 @@ T3Dpre4ProjectImporter::genProcessor("DebrisData", "shape shapeAsset shapeFile s T3Dpre4ProjectImporter::genProcessor("DecalData", "material materialAsset"); T3Dpre4ProjectImporter::genProcessor("ExplosionData", "explosionShape explosionShapeAsset"); T3Dpre4ProjectImporter::genProcessor("ParticleData", "texture textureAsset textureName textureAsset textureExt textureExtAsset textureExtName textureExtAsset"); -T3Dpre4ProjectImporter::genProcessor("PrecipitationData", "drop dropAsset dropTexture dropAsset splash splashAsset splashTexture splashAsset"); +T3Dpre4ProjectImporter::genProcessor("PrecipitationData", "drop dropAsset dropTexture dropAsset splash splashAsset splashTexture splashAsset soundProfile soundAsset"); T3Dpre4ProjectImporter::genProcessor("SplashData", "texture textureAsset"); T3Dpre4ProjectImporter::genProcessor("LightFlareData", "flareTexture flareTextureAsset"); T3Dpre4ProjectImporter::genProcessor("PhysicsDebrisData", "shape shapeAsset shapeFile shapeAsset"); diff --git a/Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript b/Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript index ab62befb8..073a7a6bf 100644 --- a/Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript +++ b/Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript @@ -556,23 +556,49 @@ function processLegacyField(%line, %originalFieldName, %newFieldName) %targetFilename = sanitizeFilename(%value); if(isObject(%targetFilename)) + { + if(%originalFieldName $= "soundProfile") + { + $ProjectImporter::assetQuery.clear(); + %foundAssets = AssetDatabase.findAssetName($ProjectImporter::assetQuery, %targetFilename); + if(%foundAssets != 0) + { + %assetId = $ProjectImporter::assetQuery.getAsset(0); + } + } + else { //likely a material name, so handle it that way %assetId = MaterialAsset::getAssetIdByMaterialName(%targetFilename); } + } else { if(!isFile(%targetFilename)) { + if(%originalFieldName $= "soundProfile") + { + $ProjectImporter::assetQuery.clear(); + %foundAssets = AssetDatabase.findAssetName($ProjectImporter::assetQuery, %targetFilename); + if(%foundAssets != 0) + { + %assetId = $ProjectImporter::assetQuery.getAsset(0); + } + } + else + { error("Legacy Project Importer - file described in line could not be found/is not valid"); return %line; } - + } + else + { $ProjectImporter::assetQuery.clear(); %foundAssets = AssetDatabase.findAssetLooseFile($ProjectImporter::assetQuery, %targetFilename); if(%foundAssets != 0) { %assetId = $ProjectImporter::assetQuery.getAsset(0); + } } } From f9b78597f768595d88cf757e1b7ac3b03db51305 Mon Sep 17 00:00:00 2001 From: Robert MacGregor Date: Thu, 16 Sep 2021 21:21:04 -0400 Subject: [PATCH 3/9] * BugFix: Correct an error that causes the engine to crash when calling non-namespaced engine functions incorrectly. --- Engine/source/console/compiledEval.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/source/console/compiledEval.cpp b/Engine/source/console/compiledEval.cpp index f4c48ef68..561e1f04a 100644 --- a/Engine/source/console/compiledEval.cpp +++ b/Engine/source/console/compiledEval.cpp @@ -734,7 +734,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa SimObject* curObject = NULL; SimObject* saveObject = NULL; Namespace::Entry* nsEntry; - Namespace* ns; + Namespace* ns = NULL; const char* curFNDocBlock = NULL; const char* curNSDocBlock = NULL; const S32 nsDocLength = 128; From c8a5ccb191b22d0d974778a8c98a789923528218 Mon Sep 17 00:00:00 2001 From: Robert MacGregor Date: Fri, 17 Sep 2021 17:37:19 -0400 Subject: [PATCH 4/9] * [OpenGL] BugFix: Correct shader errors being thrown during the load phase due to direct use of glUseProgram causing desync with GFXGLDevice. --- Engine/source/gfx/gl/gfxGLDevice.cpp | 2 +- Engine/source/gfx/gl/gfxGLShader.cpp | 8 +++++--- Engine/source/gfx/gl/gfxGLShader.h | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Engine/source/gfx/gl/gfxGLDevice.cpp b/Engine/source/gfx/gl/gfxGLDevice.cpp index 6179bd618..1c82b4e74 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.cpp +++ b/Engine/source/gfx/gl/gfxGLDevice.cpp @@ -933,7 +933,7 @@ void GFXGLDevice::setupGenericShaders( GenericShaderType type ) } GFXShader* GFXGLDevice::createShader() { - GFXGLShader* shader = new GFXGLShader(); + GFXGLShader* shader = new GFXGLShader(this); shader->registerResourceWithDevice( this ); return shader; } diff --git a/Engine/source/gfx/gl/gfxGLShader.cpp b/Engine/source/gfx/gl/gfxGLShader.cpp index d2f2edd22..ce8e7c855 100644 --- a/Engine/source/gfx/gl/gfxGLShader.cpp +++ b/Engine/source/gfx/gl/gfxGLShader.cpp @@ -382,10 +382,11 @@ void GFXGLShaderConstBuffer::onShaderReload( GFXGLShader *shader ) mWasLost = true; } -GFXGLShader::GFXGLShader() : +GFXGLShader::GFXGLShader(GFXGLDevice* device) : mVertexShader(0), mPixelShader(0), mProgram(0), + mDevice(device), mConstBufferSize(0), mConstBuffer(NULL) { @@ -706,7 +707,8 @@ void GFXGLShader::initHandles() dMemset(mConstBuffer, 0, mConstBufferSize); // Set our program so uniforms are assigned properly. - glUseProgram(mProgram); + mDevice->setShader(this, false); + // Iterate through uniforms to set sampler numbers. for (HandleMap::Iterator iter = mHandles.begin(); iter != mHandles.end(); ++iter) { @@ -723,7 +725,6 @@ void GFXGLShader::initHandles() dMemcpy(mConstBuffer + handle->mOffset, &handle->mSamplerNum, handle->getSize()); } } - glUseProgram(0); //instancing if (!mInstancingFormat) @@ -830,6 +831,7 @@ void GFXGLShader::setConstantsFromBuffer(GFXGLShaderConstBuffer* buffer) // Copy new value into our const buffer and set in GL. dMemcpy(mConstBuffer + handle->mOffset, buffer->mBuffer + handle->mOffset, handle->getSize()); + switch(handle->mDesc.constType) { case GFXSCT_Float: diff --git a/Engine/source/gfx/gl/gfxGLShader.h b/Engine/source/gfx/gl/gfxGLShader.h index 80fa4d9d9..e3d3bb69c 100644 --- a/Engine/source/gfx/gl/gfxGLShader.h +++ b/Engine/source/gfx/gl/gfxGLShader.h @@ -32,14 +32,15 @@ class GFXGLShaderConstHandle; class FileStream; class GFXGLShaderConstBuffer; +class GFXGLDevice; class GFXGLShader : public GFXShader { typedef Map HandleMap; public: - GFXGLShader(); + GFXGLShader(GFXGLDevice* device); virtual ~GFXGLShader(); - + /// @name GFXShader interface /// @{ virtual GFXShaderConstHandle* getShaderConstHandle(const String& name); @@ -99,6 +100,7 @@ protected: U32 mConstBufferSize; U8* mConstBuffer; HandleMap mHandles; + GFXGLDevice* mDevice; Vector mValidHandles; }; From 2a8f8c15f36a309eeb1bcdc7842881645d804bde Mon Sep 17 00:00:00 2001 From: Areloch Date: Sat, 18 Sep 2021 02:46:15 -0500 Subject: [PATCH 5/9] Shifted long-form check/fetch of sound asset's SFXProfile to a convenience function Fixed formatting on projectImporter.tscript file --- Engine/source/T3D/fx/precipitation.cpp | 8 +++--- Engine/source/T3D/fx/precipitation.h | 7 +++++ .../scripts/projectImporter.tscript | 26 +++++++++---------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/Engine/source/T3D/fx/precipitation.cpp b/Engine/source/T3D/fx/precipitation.cpp index 91249fe2b..4356cd45f 100644 --- a/Engine/source/T3D/fx/precipitation.cpp +++ b/Engine/source/T3D/fx/precipitation.cpp @@ -189,7 +189,7 @@ bool PrecipitationData::preload( bool server, String &errorStr ) if( Parent::preload( server, errorStr) == false) return false; - if (!server && (mSoundAsset.isNull() || !mSoundAsset->getSfxProfile())) + if (!server && !getSFXProfile()) return false; return true; @@ -200,7 +200,6 @@ void PrecipitationData::packData(BitStream* stream) Parent::packData(stream); PACKDATA_SOUNDASSET(Sound); - //sfxWrite( stream, soundProfile ); PACKDATA_IMAGEASSET(Drop); @@ -218,7 +217,6 @@ void PrecipitationData::unpackData(BitStream* stream) Parent::unpackData(stream); UNPACKDATA_SOUNDASSET(Sound); - //sfxRead( stream, &soundProfile ); UNPACKDATA_IMAGEASSET(Drop); @@ -599,9 +597,9 @@ bool Precipitation::onNewDataBlock( GameBaseData *dptr, bool reload ) { SFX_DELETE( mAmbientSound ); - if ( mDataBlock->mSoundAsset && mDataBlock->mSoundAsset->getSfxProfile() ) + if ( mDataBlock->getSFXProfile()) { - mAmbientSound = SFX->createSource(mDataBlock->mSoundAsset->getSfxProfile(), &getTransform() ); + mAmbientSound = SFX->createSource(mDataBlock->getSFXProfile(), &getTransform() ); if ( mAmbientSound ) mAmbientSound->play(); } diff --git a/Engine/source/T3D/fx/precipitation.h b/Engine/source/T3D/fx/precipitation.h index 0bb06e0f2..cdef0c2a8 100644 --- a/Engine/source/T3D/fx/precipitation.h +++ b/Engine/source/T3D/fx/precipitation.h @@ -72,6 +72,13 @@ class PrecipitationData : public GameBaseData void onDropChanged() {} void onSplashChanged() {} + + SFXProfile* getSFXProfile() { + if (mSoundAsset.notNull()) + return mSoundAsset->getSfxProfile(); + else + return NULL; + } }; struct Raindrop diff --git a/Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript b/Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript index 073a7a6bf..039a71238 100644 --- a/Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript +++ b/Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript @@ -556,7 +556,7 @@ function processLegacyField(%line, %originalFieldName, %newFieldName) %targetFilename = sanitizeFilename(%value); if(isObject(%targetFilename)) - { + { if(%originalFieldName $= "soundProfile") { $ProjectImporter::assetQuery.clear(); @@ -568,14 +568,14 @@ function processLegacyField(%line, %originalFieldName, %newFieldName) } else { - //likely a material name, so handle it that way - %assetId = MaterialAsset::getAssetIdByMaterialName(%targetFilename); - } + //likely a material name, so handle it that way + %assetId = MaterialAsset::getAssetIdByMaterialName(%targetFilename); + } } else { if(!isFile(%targetFilename)) - { + { if(%originalFieldName $= "soundProfile") { $ProjectImporter::assetQuery.clear(); @@ -587,17 +587,17 @@ function processLegacyField(%line, %originalFieldName, %newFieldName) } else { - error("Legacy Project Importer - file described in line could not be found/is not valid"); - return %line; - } + error("Legacy Project Importer - file described in line could not be found/is not valid"); + return %line; + } } else { - $ProjectImporter::assetQuery.clear(); - %foundAssets = AssetDatabase.findAssetLooseFile($ProjectImporter::assetQuery, %targetFilename); - if(%foundAssets != 0) - { - %assetId = $ProjectImporter::assetQuery.getAsset(0); + $ProjectImporter::assetQuery.clear(); + %foundAssets = AssetDatabase.findAssetLooseFile($ProjectImporter::assetQuery, %targetFilename); + if(%foundAssets != 0) + { + %assetId = $ProjectImporter::assetQuery.getAsset(0); } } } From adec6e7c74375bbad47bb4accc0b18f0db8965c7 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 19 Sep 2021 01:01:47 -0500 Subject: [PATCH 6/9] Adds load status to MaterialAsset for if the Script file itself has been loaded, but the material itself hasn't yet been processed. Fixed String -> StringTableEntry conversion in prefab file to correct corruption when setting the filename Cleaned up message spam from the MaterialSlot fields on TSStatics Added getter/setters for terrain file and assets Removed unneeded exec of tools profiles for MainMenuGUI Add logic to remove creators section of AB if in select mode Fixed misc. messageBox invokes that were erroneously converted to 'toolsMessageBox' Fix classname for NotesObject in AB Creator Entry Fix issue where ConvexShapeEditor toolbar would hide after being seen once Changed keybind for quick AB access from 'space' to 'shift space' to avoid input issues when typing in fields in some cases Fixed default image assignments for River objects on foam/ripple/depth Added handling for Material, Sound and Shape asset fields in Object Builder, and updated various objectBuilder class entries to utilize them now. Updated various fields' defaults for ObjectBuilder to utilize correct assetId's Fixed editor SceneTree tooltips for TSShape and GroundCovert to correctly reference assets as needed Added logic to properly check terrain asset validity when prompting to save changes, which would break saving actions before Added menubar items in the Object category to take control and release control of control objects quickly for testing --- Engine/source/T3D/assets/MaterialAsset.cpp | 27 +- Engine/source/T3D/assets/MaterialAsset.h | 6 + Engine/source/T3D/prefab.cpp | 4 +- Engine/source/T3D/prefab.h | 2 +- Engine/source/T3D/tsStatic.cpp | 4 - Engine/source/terrain/terrData.cpp | 12 + Engine/source/terrain/terrData.h | 33 ++ .../BaseGame/game/data/UI/guis/mainMenu.gui | 2 - .../assetBrowser/scripts/assetBrowser.tscript | 4 +- .../scripts/assetTypes/terrain.tscript | 2 +- .../assetBrowser/scripts/creator.tscript | 2 +- .../game/tools/convexEditor/main.tscript | 1 - .../guiEditor/scripts/guiEditor.ed.tscript | 2 +- .../scripts/guiEditorCanvas.ed.tscript | 10 +- .../scripts/guiEditorNewGuiDialog.ed.tscript | 2 +- .../tools/riverEditor/riverEditorGui.tscript | 6 +- .../worldEditor/gui/objectBuilderGui.ed.gui | 333 ++++++++++++++++-- .../worldEditor/scripts/EditorGui.ed.tscript | 10 +- .../scripts/editor.keybinds.tscript | 2 +- .../scripts/menuHandlers.ed.tscript | 42 ++- .../worldEditor/scripts/menus.ed.tscript | 8 +- 21 files changed, 436 insertions(+), 78 deletions(-) diff --git a/Engine/source/T3D/assets/MaterialAsset.cpp b/Engine/source/T3D/assets/MaterialAsset.cpp index eaafca03d..8fd2b6ecf 100644 --- a/Engine/source/T3D/assets/MaterialAsset.cpp +++ b/Engine/source/T3D/assets/MaterialAsset.cpp @@ -169,7 +169,13 @@ void MaterialAsset::initializeAsset() mScriptPath = getOwned() ? expandAssetFilePath(mScriptFile) : mScriptPath; if (Torque::FS::IsScriptFile(mScriptPath)) - Con::executeFile(mScriptPath, false, false); + { + if (!Sim::findObject(mMatDefinitionName)) + if (Con::executeFile(mScriptPath, false, false)) + mLoadedState = ScriptLoaded; + else + mLoadedState = Failed; + } loadMaterial(); } @@ -179,7 +185,22 @@ void MaterialAsset::onAssetRefresh() mScriptPath = getOwned() ? expandAssetFilePath(mScriptFile) : mScriptPath; if (Torque::FS::IsScriptFile(mScriptPath)) - Con::executeFile(mScriptPath, false, false); + { + //Since we're refreshing, we can assume that the file we're executing WILL have an existing definition. + //But that definition, whatever it is, is the 'correct' one, so we enable the Replace Existing behavior + //when the engine encounters a named object conflict. + String redefineBehaviorPrev = Con::getVariable("$Con::redefineBehavior"); + Con::setVariable("$Con::redefineBehavior", "replaceExisting"); + + if (Con::executeFile(mScriptPath, false, false)) + mLoadedState = ScriptLoaded; + else + mLoadedState = Failed; + + //And now that we've executed, switch back to the prior behavior + Con::setVariable("$Con::redefineBehavior", redefineBehaviorPrev.c_str()); + + } loadMaterial(); } @@ -206,7 +227,7 @@ void MaterialAsset::loadMaterial() if (mMaterialDefinition) SAFE_DELETE(mMaterialDefinition); - if (mMatDefinitionName != StringTable->EmptyString()) + if (mLoadedState == ScriptLoaded && mMatDefinitionName != StringTable->EmptyString()) { Material* matDef; if (!Sim::findObject(mMatDefinitionName, matDef)) diff --git a/Engine/source/T3D/assets/MaterialAsset.h b/Engine/source/T3D/assets/MaterialAsset.h index 018e2a989..07ec0227a 100644 --- a/Engine/source/T3D/assets/MaterialAsset.h +++ b/Engine/source/T3D/assets/MaterialAsset.h @@ -70,6 +70,12 @@ class MaterialAsset : public AssetBase public: static StringTableEntry smNoMaterialAssetFallback; + enum MaterialAssetErrCode + { + ScriptLoaded = AssetErrCode::Extended, + Extended + }; + public: MaterialAsset(); virtual ~MaterialAsset(); diff --git a/Engine/source/T3D/prefab.cpp b/Engine/source/T3D/prefab.cpp index 38934062f..0bebb443f 100644 --- a/Engine/source/T3D/prefab.cpp +++ b/Engine/source/T3D/prefab.cpp @@ -242,7 +242,7 @@ bool Prefab::protectedSetFile( void *object, const char *index, const char *data return false; } -void Prefab::setFile( String file ) +void Prefab::setFile( StringTableEntry file ) { AssertFatal( isServerObject(), "Prefab-bad" ); @@ -257,7 +257,7 @@ void Prefab::setFile( String file ) // be called for the client-side prefab but maybe the user did so accidentally. if ( isClientObject() ) { - Con::errorf( "Prefab::setFile( %s ) - Should not be called on a client-side Prefab.", file.c_str() ); + Con::errorf( "Prefab::setFile( %s ) - Should not be called on a client-side Prefab.", file ); return; } diff --git a/Engine/source/T3D/prefab.h b/Engine/source/T3D/prefab.h index 6ebe88b0a..def70857e 100644 --- a/Engine/source/T3D/prefab.h +++ b/Engine/source/T3D/prefab.h @@ -90,7 +90,7 @@ public: void render( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ); /// - void setFile( String file ); + void setFile(StringTableEntry file ); /// Removes all children from this Prefab and puts them into a SimGroup /// which is added to the Scene and returned to the caller. diff --git a/Engine/source/T3D/tsStatic.cpp b/Engine/source/T3D/tsStatic.cpp index 9b093f476..9028653b8 100644 --- a/Engine/source/T3D/tsStatic.cpp +++ b/Engine/source/T3D/tsStatic.cpp @@ -1675,10 +1675,6 @@ void TSStatic::onInspect(GuiInspector* inspector) { dSprintf(matFieldName, 128, "MaterialSlot%d", i); - //addComponentField(matFieldName, "A material used in the shape file", "Material", matAsset->getAssetId(), ""); - //Con::executef(this, "onConstructComponentField", mTargetComponent, field->mFieldName); - Con::printf("Added material field for MaterialSlot %d", i); - GuiInspectorField* fieldGui = materialGroup->constructField(TypeMaterialAssetPtr); fieldGui->init(inspector, materialGroup); diff --git a/Engine/source/terrain/terrData.cpp b/Engine/source/terrain/terrData.cpp index a80e350f0..be43d6638 100644 --- a/Engine/source/terrain/terrData.cpp +++ b/Engine/source/terrain/terrData.cpp @@ -1613,3 +1613,15 @@ void TerrainBlock::deleteZodiacPrimitiveBuffer() } } +DefineEngineMethod(TerrainBlock, getTerrain, String, (), , "Returns the terrain file used for this terrain block, either via the asset or the filename assigned, which ever is valid") +{ + return object->getTerrain(); +} +DefineEngineMethod(TerrainBlock, getTerrainAsset, String, (), , "Returns the assetId used for this terrain block") +{ + return object->getTerrainAssetId(); +} +DefineEngineMethod(TerrainBlock, setTerrain, bool, (const char* terrain), , "Terrain assignment.first tries asset then flat file.") +{ + return object->_setTerrain(StringTable->insert(terrain)); +} diff --git a/Engine/source/terrain/terrData.h b/Engine/source/terrain/terrData.h index 5550ea30e..cc1479004 100644 --- a/Engine/source/terrain/terrData.h +++ b/Engine/source/terrain/terrData.h @@ -488,6 +488,39 @@ public: void inspectPostApply(); virtual void getUtilizedAssets(Vector* usedAssetsList); + + const StringTableEntry getTerrain() const + { + if (mTerrainAsset && (mTerrainAsset->getTerrainFilePath() != StringTable->EmptyString())) + return mTerrainAsset->getTerrainFilePath(); + else if (mTerrainAssetId != StringTable->EmptyString()) + return mTerrainAssetId; + else if (mTerrFileName != StringTable->EmptyString()) + return mTerrFileName; + else + return StringTable->EmptyString(); + } + + const StringTableEntry getTerrainAssetId() const + { + if (mTerrainAssetId != StringTable->EmptyString()) + return mTerrainAssetId; + else + return StringTable->EmptyString(); + } + + bool _setTerrain(StringTableEntry terrain) + { + if (terrain == StringTable->EmptyString()) + return false; + + if (AssetDatabase.isDeclaredAsset(terrain)) + setTerrainAsset(terrain); + else + mTerrFileName = terrain; + + return true; + } protected: bool mUpdateBasetex; diff --git a/Templates/BaseGame/game/data/UI/guis/mainMenu.gui b/Templates/BaseGame/game/data/UI/guis/mainMenu.gui index 4cc06b26e..f33c06b1d 100644 --- a/Templates/BaseGame/game/data/UI/guis/mainMenu.gui +++ b/Templates/BaseGame/game/data/UI/guis/mainMenu.gui @@ -1,5 +1,3 @@ -exec( "tools/gui/profiles.ed.tscript" ); - //--- OBJECT WRITE BEGIN --- $guiContent = new GuiChunkedBitmapCtrl(MainMenuGui) { bitmapAsset = "UI:background_dark_image"; diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript index ec2d0db4d..747d3e86d 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript @@ -618,7 +618,9 @@ function AssetBrowser::loadDirectories( %this ) %dataItem = AssetBrowser-->filterTree.insertItem(AssetBrowser-->filterTree.modulesIdx, "data"); AssetBrowser-->filterTree.tagsIdx = AssetBrowser-->filterTree.insertItem(1, "Tags"); - AssetBrowser-->filterTree.creatorIdx = AssetBrowser-->filterTree.insertItem(1, "Creator"); + + if(!%this.selectMode) + AssetBrowser-->filterTree.creatorIdx = AssetBrowser-->filterTree.insertItem(1, "Creator"); %this.dirHandler.loadFolders("data", %dataItem); diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrain.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrain.tscript index 9081729d0..c7e8fe92e 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrain.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrain.tscript @@ -79,7 +79,7 @@ function AssetBrowser::createTerrainAsset(%this) } else { - toolsMessageBox( "Import Terrain", + MessageBox( "Import Terrain", "Terrain import failed! Check console for error messages.", "Ok", "Error" ); } diff --git a/Templates/BaseGame/game/tools/assetBrowser/scripts/creator.tscript b/Templates/BaseGame/game/tools/assetBrowser/scripts/creator.tscript index 15dc88d0a..48366f453 100644 --- a/Templates/BaseGame/game/tools/assetBrowser/scripts/creator.tscript +++ b/Templates/BaseGame/game/tools/assetBrowser/scripts/creator.tscript @@ -47,7 +47,7 @@ function AssetBrowser::loadCreatorClasses(%this) %this.addCreatorClass("LevelInfo", "Level Info" ); %this.addCreatorClass("Marker", "Path Node" ); %this.addCreatorClass("MissionArea", "Mission Area" ); - %this.addCreatorClass("Note", "Note" ); + %this.addCreatorClass("NotesObject", "Note" ); %this.addCreatorClass("Path" ); %this.addCreatorClass("SpawnSphere", "General Spawn Sphere" ); %this.addCreatorClass("SpawnSphere", "Player Spawn Sphere"/*, "PlayerDropPoint"*/ ); diff --git a/Templates/BaseGame/game/tools/convexEditor/main.tscript b/Templates/BaseGame/game/tools/convexEditor/main.tscript index 260c955ae..3930f5b11 100644 --- a/Templates/BaseGame/game/tools/convexEditor/main.tscript +++ b/Templates/BaseGame/game/tools/convexEditor/main.tscript @@ -145,7 +145,6 @@ function ConvexEditorPlugin::onDeactivated( %this ) ConvexEditorTreeWindow.setVisible( false ); ConvexEditorOptionsWindow.setVisible( false ); - ConvexEditorToolbar.setVisible( false ); %this.map.pop(); // Remove our menu. diff --git a/Templates/BaseGame/game/tools/guiEditor/scripts/guiEditor.ed.tscript b/Templates/BaseGame/game/tools/guiEditor/scripts/guiEditor.ed.tscript index e9eabea7e..823fa39b3 100644 --- a/Templates/BaseGame/game/tools/guiEditor/scripts/guiEditor.ed.tscript +++ b/Templates/BaseGame/game/tools/guiEditor/scripts/guiEditor.ed.tscript @@ -910,7 +910,7 @@ function GuiEditorTabBook::onWake( %this ) item[ 1 ] = "Categorized View" TAB "" TAB "GuiEditorToolbox.setViewType( \"Categorized\" );"; }; - GlobalActionMap.bindCmd( keyboard, space, "", "AssetBrowser.toggleDialog();" ); + GlobalActionMap.bindCmd( keyboard, "shift space", "", "AssetBrowser.toggleDialog();" ); } //--------------------------------------------------------------------------------------------- diff --git a/Templates/BaseGame/game/tools/guiEditor/scripts/guiEditorCanvas.ed.tscript b/Templates/BaseGame/game/tools/guiEditor/scripts/guiEditorCanvas.ed.tscript index 1fbe50c12..f62fe12ea 100644 --- a/Templates/BaseGame/game/tools/guiEditor/scripts/guiEditorCanvas.ed.tscript +++ b/Templates/BaseGame/game/tools/guiEditor/scripts/guiEditorCanvas.ed.tscript @@ -283,7 +283,7 @@ function GuiEditCanvas::load( %this, %filename ) // group. And, it should be the only thing in the group. if( !isObject( $guiContent ) ) { - toolsMessageBox( getEngineName(), + MessageBox( getEngineName(), "You have loaded a Gui file that was created before this version. It has been loaded but you must open it manually from the content list dropdown", "Ok", "Information" ); return 0; @@ -333,7 +333,7 @@ function GuiEditCanvas::save( %this, %selectedOnly, %noPrompt ) return; else if( %selected.getCount() > 1 ) { - toolsMessageBox( "Invalid selection", "Only a single control hierarchy can be saved to a file. Make sure you have selected only one control in the tree view." ); + MessageBox( "Invalid selection", "Only a single control hierarchy can be saved to a file. Make sure you have selected only one control in the tree view." ); return; } @@ -464,7 +464,7 @@ function GuiEditCanvas::save( %this, %selectedOnly, %noPrompt ) GuiEditorStatusBar.print( "Saved file '" @ %currentObject.getFileName() @ "'" ); } else - toolsMessageBox( "Error writing to file", "There was an error writing to file '" @ %currentFile @ "'. The file may be read-only.", "Ok", "Error" ); + MessageBox( "Error writing to file", "There was an error writing to file '" @ %currentFile @ "'. The file may be read-only.", "Ok", "Error" ); } //--------------------------------------------------------------------------------------------- @@ -490,7 +490,7 @@ function GuiEditCanvas::append( %this ) if( !isObject( $guiContent ) ) { - toolsMessageBox( "Error loading GUI file", "The GUI content controls could not be found. This function can only be used with files saved by the GUI editor.", "Ok", "Error" ); + MessageBox( "Error loading GUI file", "The GUI content controls could not be found. This function can only be used with files saved by the GUI editor.", "Ok", "Error" ); return; } @@ -519,7 +519,7 @@ function GuiEditCanvas::revert( %this ) if( %filename $= "" ) return; - if( toolsMessageBox( "Revert Gui", "Really revert the current Gui? This cannot be undone.", "OkCancel", "Question" ) == $MROk ) + if( MessageBox( "Revert Gui", "Really revert the current Gui? This cannot be undone.", "OkCancel", "Question" ) == $MROk ) %this.load( %filename ); } diff --git a/Templates/BaseGame/game/tools/guiEditor/scripts/guiEditorNewGuiDialog.ed.tscript b/Templates/BaseGame/game/tools/guiEditor/scripts/guiEditorNewGuiDialog.ed.tscript index 85fa7263e..248c0e97d 100644 --- a/Templates/BaseGame/game/tools/guiEditor/scripts/guiEditorNewGuiDialog.ed.tscript +++ b/Templates/BaseGame/game/tools/guiEditor/scripts/guiEditorNewGuiDialog.ed.tscript @@ -81,7 +81,7 @@ function GuiEditorNewGuiDialog::onOK( %this ) if( isObject( %name ) && %name.isMemberOfClass( "GuiControl" ) ) { - if( toolsMessageBox( "Warning", "Replace the existing control '" @ %name @ "'?", "OkCancel", "Question" ) == $MROk ) + if( MessageBox( "Warning", "Replace the existing control '" @ %name @ "'?", "OkCancel", "Question" ) == $MROk ) %name.delete(); else return; diff --git a/Templates/BaseGame/game/tools/riverEditor/riverEditorGui.tscript b/Templates/BaseGame/game/tools/riverEditor/riverEditorGui.tscript index 814782cb2..bb0f40037 100644 --- a/Templates/BaseGame/game/tools/riverEditor/riverEditorGui.tscript +++ b/Templates/BaseGame/game/tools/riverEditor/riverEditorGui.tscript @@ -76,9 +76,9 @@ function RiverEditorGui::createRiver( %this ) baseColor = "45 108 171 255"; - rippleTex = "core/rendering/images/ripple.dds"; - foamTex = "core/rendering/images/foam"; - depthGradientTex = "core/rendering/images/depthcolor_ramp"; + rippleTex = "Core_Rendering:ripple_image"; + foamTex = "Core_Rendering:foam_image"; + depthGradientTex = "Core_Rendering:depthcolor_ramp_image"; }; return %river; diff --git a/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui b/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui index dc757dc54..8dafe0357 100644 --- a/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui +++ b/Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui @@ -313,30 +313,6 @@ function ObjectBuilderGui::createImageAssetType(%this, %index) else %name = %this.field[%index, text]; - // - /*%this.textControls[%this.numControls] = new GuiTextCtrl() { - profile = "ToolsGuiTextRightProfile"; - internalName = "assetText"; - text = %name; - extent = %this.fieldNameExtent; - position = %this.curXPos @ " " @ %this.curYPos; - modal = "1"; - }; - - // - %this.controls[%this.numControls] = new GuiButtonCtrl() { - HorizSizing = "width"; - profile = "ToolsGuiButtonProfile"; - internalName = "assetButton"; - extent = %this.fileButtonExtent; - position = %this.curXPos + %this.columnOffset @ " " @ %this.curYPos; - modal = "1"; - command = %this @ ".getImageAsset(" @ %index @ ");"; - }; - - %val = %this.field[%index, value]; - %this.controls[%this.numControls].setText(fileBase(%val) @ fileExt(%val));*/ - %this.textControls[%this.numControls] = new GuiTextCtrl() { profile = "ToolsGuiTextRightProfile"; text = %name; @@ -375,7 +351,7 @@ function ObjectBuilderGui::createImageAssetType(%this, %index) modal = "1"; command = %this @ ".getImageAsset(" @ %index @ ");"; }; - %button.setBitmap("ToolsModule:change_material_btn_n_image"); + %button.setBitmap("ToolsModule:GameTSCtrl_image"); %this.controls[%this.numControls].addGuiControl(%button); %this.numControls++; @@ -412,6 +388,279 @@ function ObjectBuilderGui::gotImageAsset(%this, %name) // This doesn't work for button controls as getValue returns their state! //%this.controls[%this.currentControl].setValue(%name); } + +//------------------------------------------------------------------------------ +function ObjectBuilderGui::createMaterialAssetType(%this, %index) +{ + if(%index >= %this.numFields || %this.field[%index, name] $= "") + { + error("ObjectBuilderGui::createMaterialAssetType: invalid field"); + return; + } + + // + if(%this.field[%index, text] $= "") + %name = %this.field[%index, name]; + else + %name = %this.field[%index, text]; + + %this.textControls[%this.numControls] = new GuiTextCtrl() { + profile = "ToolsGuiTextRightProfile"; + text = %name; + extent = %this.fieldNameExtent; + position = %this.curXPos @ " " @ %this.curYPos; + modal = "1"; + }; + + // + %this.controls[%this.numControls] = new GuiControl() { + HorizSizing = "width"; + profile = "ToolsGuiDefaultProfile"; + extent = %this.textEditExtent; + position = %this.curXPos + %this.columnOffset @ " " @ %this.curYPos; + modal = "1"; + }; + + %text = new GuiTextEditCtrl() { + class = ObjectBuilderGuiTextEditCtrl; + internalName = "assetText"; + HorizSizing = "width"; + profile = "ToolsGuiTextEditProfile"; + extent = getWord(%this.textEditExtent,0) - getWord(%this.matButtonExtent,0) - 2 @ " " @ getWord(%this.textEditExtent,1); + text = %this.field[%index, value]; + position = "0 0"; + modal = "1"; + }; + %this.controls[%this.numControls].addGuiControl(%text); + + %button = new GuiBitmapButtonCtrl() { + internalName = "assetButton"; + HorizSizing = "left"; + profile = "ToolsGuiButtonProfile"; + extent = %this.matButtonExtent; + position = getWord(%this.textEditExtent,0) - getWord(%this.matButtonExtent,0) @ " 0"; + modal = "1"; + command = %this @ ".getMaterialAsset(" @ %index @ ");"; + }; + %button.setBitmap("ToolsModule:change_material_btn_n_image"); + %this.controls[%this.numControls].addGuiControl(%button); + + %this.numControls++; + %this.curYPos += %this.defaultFieldStep; +} + +function ObjectBuilderGui::getMaterialAsset(%this, %index) +{ + if(%index >= %this.numFields || %this.field[%index, name] $= "") + { + error("ObjectBuilderGui::getMaterialAsset: invalid field"); + return; + } + + %val = %this.field[%index, ext]; + + //%path = filePath(%val); + //%ext = fileExt(%val); + + %this.currentControl = %index; + AssetBrowser.showDialog("MaterialAsset", %this @ ".gotMaterialAsset", "", "", ""); + //getLoadFilename( %val @ "|" @ %val, %this @ ".gotFileName", %this.lastPath ); +} + +function ObjectBuilderGui::gotMaterialAsset(%this, %name) +{ + %index = %this.currentControl; + + %this.field[%index, value] = %name; + %this.controls[%this.currentControl]-->assetText.setText(%name); + + %this.lastPath = %name; + + // This doesn't work for button controls as getValue returns their state! + //%this.controls[%this.currentControl].setValue(%name); +} + +//------------------------------------------------------------------------------ +function ObjectBuilderGui::createShapeAssetType(%this, %index) +{ + if(%index >= %this.numFields || %this.field[%index, name] $= "") + { + error("ObjectBuilderGui::createShapeAssetType: invalid field"); + return; + } + + // + if(%this.field[%index, text] $= "") + %name = %this.field[%index, name]; + else + %name = %this.field[%index, text]; + + %this.textControls[%this.numControls] = new GuiTextCtrl() { + profile = "ToolsGuiTextRightProfile"; + text = %name; + extent = %this.fieldNameExtent; + position = %this.curXPos @ " " @ %this.curYPos; + modal = "1"; + }; + + // + %this.controls[%this.numControls] = new GuiControl() { + HorizSizing = "width"; + profile = "ToolsGuiDefaultProfile"; + extent = %this.textEditExtent; + position = %this.curXPos + %this.columnOffset @ " " @ %this.curYPos; + modal = "1"; + }; + + %text = new GuiTextEditCtrl() { + class = ObjectBuilderGuiTextEditCtrl; + internalName = "assetText"; + HorizSizing = "width"; + profile = "ToolsGuiTextEditProfile"; + extent = getWord(%this.textEditExtent,0) - getWord(%this.matButtonExtent,0) - 2 @ " " @ getWord(%this.textEditExtent,1); + text = %this.field[%index, value]; + position = "0 0"; + modal = "1"; + }; + %this.controls[%this.numControls].addGuiControl(%text); + + %button = new GuiBitmapButtonCtrl() { + internalName = "assetButton"; + HorizSizing = "left"; + profile = "ToolsGuiButtonProfile"; + extent = %this.matButtonExtent; + position = getWord(%this.textEditExtent,0) - getWord(%this.matButtonExtent,0) @ " 0"; + modal = "1"; + command = %this @ ".getShapeAsset(" @ %index @ ");"; + }; + %button.setBitmap("ToolsModule:shape_editor_n_image"); + %this.controls[%this.numControls].addGuiControl(%button); + + %this.numControls++; + %this.curYPos += %this.defaultFieldStep; +} + +function ObjectBuilderGui::getShapeAsset(%this, %index) +{ + if(%index >= %this.numFields || %this.field[%index, name] $= "") + { + error("ObjectBuilderGui::getShapeAsset: invalid field"); + return; + } + + %val = %this.field[%index, ext]; + + //%path = filePath(%val); + //%ext = fileExt(%val); + + %this.currentControl = %index; + AssetBrowser.showDialog("ShapeAsset", %this @ ".gotShapeAsset", "", "", ""); + //getLoadFilename( %val @ "|" @ %val, %this @ ".gotFileName", %this.lastPath ); +} + +function ObjectBuilderGui::gotShapeAsset(%this, %name) +{ + %index = %this.currentControl; + + %this.field[%index, value] = %name; + %this.controls[%this.currentControl]-->assetText.setText(%name); + + %this.lastPath = %name; + + // This doesn't work for button controls as getValue returns their state! + //%this.controls[%this.currentControl].setValue(%name); +} + +//------------------------------------------------------------------------------ +function ObjectBuilderGui::createSoundAssetType(%this, %index) +{ + if(%index >= %this.numFields || %this.field[%index, name] $= "") + { + error("ObjectBuilderGui::createSoundAssetType: invalid field"); + return; + } + + // + if(%this.field[%index, text] $= "") + %name = %this.field[%index, name]; + else + %name = %this.field[%index, text]; + + %this.textControls[%this.numControls] = new GuiTextCtrl() { + profile = "ToolsGuiTextRightProfile"; + text = %name; + extent = %this.fieldNameExtent; + position = %this.curXPos @ " " @ %this.curYPos; + modal = "1"; + }; + + // + %this.controls[%this.numControls] = new GuiControl() { + HorizSizing = "width"; + profile = "ToolsGuiDefaultProfile"; + extent = %this.textEditExtent; + position = %this.curXPos + %this.columnOffset @ " " @ %this.curYPos; + modal = "1"; + }; + + %text = new GuiTextEditCtrl() { + class = ObjectBuilderGuiTextEditCtrl; + internalName = "assetText"; + HorizSizing = "width"; + profile = "ToolsGuiTextEditProfile"; + extent = getWord(%this.textEditExtent,0) - getWord(%this.matButtonExtent,0) - 2 @ " " @ getWord(%this.textEditExtent,1); + text = %this.field[%index, value]; + position = "0 0"; + modal = "1"; + }; + %this.controls[%this.numControls].addGuiControl(%text); + + %button = new GuiBitmapButtonCtrl() { + internalName = "assetButton"; + HorizSizing = "left"; + profile = "ToolsGuiButtonProfile"; + extent = %this.matButtonExtent; + position = getWord(%this.textEditExtent,0) - getWord(%this.matButtonExtent,0) @ " 0"; + modal = "1"; + command = %this @ ".getSoundAsset(" @ %index @ ");"; + }; + %button.setBitmap("ToolsModule:SFXEmitter_image"); + %this.controls[%this.numControls].addGuiControl(%button); + + %this.numControls++; + %this.curYPos += %this.defaultFieldStep; +} + +function ObjectBuilderGui::getSoundAsset(%this, %index) +{ + if(%index >= %this.numFields || %this.field[%index, name] $= "") + { + error("ObjectBuilderGui::getSoundAsset: invalid field"); + return; + } + + %val = %this.field[%index, ext]; + + //%path = filePath(%val); + //%ext = fileExt(%val); + + %this.currentControl = %index; + AssetBrowser.showDialog("SoundAsset", %this @ ".gotSoundAsset", "", "", ""); + //getLoadFilename( %val @ "|" @ %val, %this @ ".gotFileName", %this.lastPath ); +} + +function ObjectBuilderGui::gotSoundAsset(%this, %name) +{ + %index = %this.currentControl; + + %this.field[%index, value] = %name; + %this.controls[%this.currentControl]-->assetText.setText(%name); + + %this.lastPath = %name; + + // This doesn't work for button controls as getValue returns their state! + //%this.controls[%this.currentControl].setValue(%name); +} //------------------------------------------------------------------------------ function ObjectBuilderGui::createMaterialNameType(%this, %index) { @@ -680,6 +929,15 @@ function ObjectBuilderGui::process(%this) case "TypeImageAsset": %this.createImageAssetType(%i); + case "TypeMaterialAsset": + %this.createMaterialAssetType(%i); + + case "TypeShapeAsset": + %this.createShapeAssetType(%i); + + case "TypeSoundAsset": + %this.createSoundAssetType(%i); + case "TypeMaterialName": %this.createMaterialNameType(%i); @@ -753,7 +1011,10 @@ function ObjectBuilderGui::onOK(%this) continue; } if (%this.field[%i, type] $= "TypeImageAsset" || - %this.field[%i, type] $= "TypeTerrainAsset") + %this.field[%i, type] $= "TypeTerrainAsset" || + %this.field[%i, type] $= "TypeMaterialAsset" || + %this.field[%i, type] $= "TypeShapeAsset" + ) { %this.field[%i, value] = %this.controls[%i]-->assetText.getText(); continue; @@ -861,7 +1122,6 @@ function ObjectBuilderGui::buildScatterSky( %this, %dontWarnAboutSun ) %this.addField( "moonMatAsset", "TypeMaterialAsset", "Moon Material", "Core_Rendering:moon_wglow" ); %this.addField( "nightCubemap", "TypeCubemapName", "Night Cubemap", "NightCubemap" ); %this.addField( "useNightCubemap", "TypeBool", "Use Night Cubemap", "true" ); - } function ObjectBuilderGui::buildCloudLayer(%this) @@ -954,7 +1214,7 @@ function ObjectBuilderGui::buildSun( %this, %dontWarnAboutScatterSky ) // This is a trick... any fields added after process won't show // up as controls, but will be applied to the created object. - %this.addField( "coronaMaterial", "TypeMaterialName", "Corona Material", "Corona_Mat" ); + %this.addField( "coronaMaterial", "TypeMaterialAsset", "Corona Material", "Core_Rendering:Corona_Mat" ); %this.addField( "flareType", "TypeLightFlareDataPtr", "Flare", "SunFlareExample" ); } @@ -994,9 +1254,9 @@ function ObjectBuilderGui::addWaterObjectFields(%this) %this.addField("waveSpeed[2]", "TypeFloat", "Wave Speed", "1"); %this.addField("overallWaveMagnitude", "TypeFloat", "Overall Wave Magnitude", "1.0"); - %this.addField("rippleTexAsset", "TypeImageAssetId", "Ripple Texture", "Core_Rendering:ripple_image" ); - %this.addField("depthGradientTexAsset", "TypeImageAssetId", "Depth Gradient Texture", "Core_Rendering:depthcolor_ramp_imag" ); - %this.addField("foamTexAsset", "TypeImageAssetId", "Foam Texture", "Core_Rendering:foam_image" ); + %this.addField("rippleTex", "TypeImageAsset", "Ripple Texture", "Core_Rendering:ripple_image" ); + %this.addField("depthGradientTex", "TypeImageAsset", "Depth Gradient Texture", "Core_Rendering:depthcolor_ramp_image" ); + %this.addField("foamTex", "TypeImageAsset", "Foam Texture", "Core_Rendering:foam_image" ); } function ObjectBuilderGui::buildWaterBlock(%this) @@ -1038,8 +1298,8 @@ function ObjectBuilderGui::buildTerrainBlock(%this) function ObjectBuilderGui::buildGroundCover( %this ) { %this.objectClassName = "GroundCover"; - %this.addField( "material", "TypeMaterialName", "Material Name", "" ); - %this.addField( "shapeFilename[0]", "TypeFile", "Shape File [Optional]", "", "*.*"); + %this.addField( "materialAsset", "TypeMaterialAsset", "Material Asset", "" ); + %this.addField( "shapeAsset[0]", "TypeShapeAsset", "Shape Asset [Optional]", "", ""); %this.process(); // This is a trick... any fields added after process won't show @@ -1212,6 +1472,9 @@ function ObjectBuilderGui::buildGeneralDropPoint(%this) function ObjectBuilderGui::buildNotesObject(%this) { %this.objectClassName = "NotesObject"; + %this.addField("note", "TypeString", "Note Text", ""); + %this.addField("showArrow", "TypeBool", "Show Arrow", ""); + %this.addField("arrowColor", "TypeColorI", "Arrow Color", "255 0 0 255"); %this.process(); } //------------------------------------------------------------------------------ @@ -1221,11 +1484,11 @@ function ObjectBuilderGui::buildVolumetricFog(%this) { // Change this if you want to default to another Folder // Otherwise every time you want to add a Fog you will go this. - %defShape = "core/rendering/shapes/Fog_Cube.DAE"; + %defShape = "Core_Rendering:Fog_Cube"; %this.lastPath=getMainDotCsDir() @ %defShape; OBObjectName.setValue( "" ); %this.objectClassName = "VolumetricFog"; - %this.addField( "shapeName", "TypeFile", "Shape (Fog volume)", "", "*.dts;*.dae"); + %this.addField( "shapeAsset", "TypeShapeAsset", "Shape (Fog volume)", "", ""); %this.addField("Scale", "TypePoint3", "Scale", "1 1 1"); %this.addField("FogColor", "TypeColorI", "FogColor", "200 200 200 255"); %this.process(); diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.tscript b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.tscript index e7972a4c8..dca4d1f30 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.tscript +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.tscript @@ -1826,7 +1826,10 @@ function EditorTree::update( %this ) // Tooltip for TSStatic function EditorTree::GetTooltipTSStatic( %this, %obj ) { - return "Shape: " @ %obj.shapeName; + %shapeName = %obj.shapeAsset; + if(%shapeName $= "") + %shapeName = %obj.getShape(); + return "Shape: " @ %shapeName; } // Tooltip for ShapeBase @@ -1862,7 +1865,10 @@ function EditorTree::GetTooltipPrefab( %this, %obj ) // Tooltip for GroundCover function EditorTree::GetTooltipGroundCover( %this, %obj ) { - %text = "Material: " @ %obj.material; + %matName = %obj.materialAsset; + if(%matName $= "") + %matName = %obj.getMaterial(); + %text = "Material: " @ %matName; for(%i=0; %i<8; %i++) { if(%obj.probability[%i] > 0 && %obj.shapeFilename[%i] !$= "") diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/editor.keybinds.tscript b/Templates/BaseGame/game/tools/worldEditor/scripts/editor.keybinds.tscript index a077b8611..74c681bd5 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/editor.keybinds.tscript +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/editor.keybinds.tscript @@ -79,4 +79,4 @@ GlobalActionMap.bind(keyboard, "tilde", toggleConsole); EditorMap.bind( mouse, "alt zaxis", editorWheelFadeScroll ); -EditorMap.bindCmd( keyboard, space, "", "AssetBrowser.toggleDialog();" ); +EditorMap.bindCmd( keyboard, "shift space", "", "AssetBrowser.toggleDialog();" ); diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript b/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript index a1771cdcf..4679dba92 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript @@ -204,8 +204,7 @@ function EditorNewLevel( %level ) %saveFirst = false; if ( EditorIsDirty() ) { - error(knob); - %saveFirst = toolsMessageBox("Mission Modified", "Would you like to save changes to the current mission \"" @ + %saveFirst = MessageBox("Mission Modified", "Would you like to save changes to the current mission \"" @ $Server::MissionFile @ "\" before creating a new mission?", "SaveDontSave", "Question") == $MROk; } @@ -300,7 +299,7 @@ function EditorSaveMission() // first check for dirty and read-only files: if((EWorldEditor.isDirty || ETerrainEditor.isMissionDirty) && !isWriteableFileName($Server::MissionFile)) { - toolsMessageBox("Error", "Mission file \""@ $Server::MissionFile @ "\" is read-only. Continue?", "Ok", "Stop"); + MessageBox("Error", "Mission file \""@ $Server::MissionFile @ "\" is read-only. Continue?", "Ok", "Stop"); return false; } if(ETerrainEditor.isDirty) @@ -310,9 +309,18 @@ function EditorSaveMission() while ((%terrainObject = containerSearchNext()) != 0) { - if (!isWriteableFileName(%terrainObject.terrainFile)) + %terrFile = %terrainObject.getTerrain(); + if(AssetDatabase.isDeclaredAsset(%terrFile)) { - if (toolsMessageBox("Error", "Terrain file \""@ %terrainObject.terrainFile @ "\" is read-only. Continue?", "Ok", "Stop") == $MROk) + %assetDef = AssetDatabase.acquireAsset(%terrFile); + %file = %assetDef.getTerrainFilePath(); + AssetDatabase.releaseAsset(%terrFile); + %terrFile = %file; + } + + if (!isWriteableFileName(%terrFile) && %bypass $= "") + { + if (MessageBox("Error", "Terrain file \""@ %terrainObject.terrainFile @ "\" is read-only. Continue?", "Ok", "Stop") == $MROk) continue; else return false; @@ -497,12 +505,12 @@ function EditorOpenMission(%levelAsset) if( EditorIsDirty()) { // "EditorSaveBeforeLoad();", "getLoadFilename(\"*.mis\", \"EditorDoLoadMission\");" - if(toolsMessageBox("Mission Modified", "Would you like to save changes to the current mission \"" @ + if(MessageBox("Mission Modified", "Would you like to save changes to the current mission \"" @ $Server::MissionFile @ "\" before opening a new mission?", SaveDontSave, Question) == $MROk) { - if(! EditorSaveMission()) - return; - } + if(!EditorSaveMission()) + return; + } } if(%levelAsset $= "") @@ -779,8 +787,20 @@ function makeSelectedAMesh(%assetId) function EditorTakeControlOfEntity() { %object = EWorldEditor.getSelectedObject(0); - switchCamera(localClientConnection, %object); - switchControlObject(localClientConnection, %object); + if(isObject(%object) && %object.getClassName() !$= "Camera") + { + $Editor::previousControlObject = localClientConnection.getControlObject(); + localClientConnection.setControlObject(%object); + + } +} + +function EditorReleaseControlOfEntity() +{ + if(isObject($Editor::previousControlObject)) + { + localClientConnection.setControlObject($Editor::previousControlObject); + } } function EditorMount() diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.tscript b/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.tscript index 21eaea05a..bf69e6bdb 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.tscript +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.tscript @@ -459,9 +459,11 @@ function EditorGui::buildMenus(%this) Item[18] = "Explode Selected Prefab" TAB "" TAB "EditorExplodePrefab();"; Item[19] = "-"; Item[20] = "Take control of entity" TAB "" TAB "EditorTakeControlOfEntity();"; - Item[21] = "-"; - Item[22] = "Mount Selection A to B" TAB "" TAB "EditorMount();"; - Item[23] = "Unmount Selected Object" TAB "" TAB "EditorUnmount();"; + Item[21] = "Release control of entity" TAB "" TAB "EditorReleaseControlOfEntity();"; + + Item[22] = "-"; + Item[23] = "Mount Selection A to B" TAB "" TAB "EditorMount();"; + Item[24] = "Unmount Selected Object" TAB "" TAB "EditorUnmount();"; }; } } From ef5daae77045588f054152bd325c9f2ee44e8af7 Mon Sep 17 00:00:00 2001 From: Areloch Date: Sun, 19 Sep 2021 12:55:56 -0500 Subject: [PATCH 7/9] Removed unneeded var --- .../game/tools/worldEditor/scripts/menuHandlers.ed.tscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript b/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript index 4679dba92..a2ea3b015 100644 --- a/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript +++ b/Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript @@ -318,7 +318,7 @@ function EditorSaveMission() %terrFile = %file; } - if (!isWriteableFileName(%terrFile) && %bypass $= "") + if (!isWriteableFileName(%terrFile)) { if (MessageBox("Error", "Terrain file \""@ %terrainObject.terrainFile @ "\" is read-only. Continue?", "Ok", "Stop") == $MROk) continue; From c150afebaac2a72558dcf9997138151baf8561bf Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Mon, 20 Sep 2021 13:50:47 -0500 Subject: [PATCH 8/9] particle cleanups misc dupe code cleanup bits. safeties for the varous flavors of void ParticleEmitter::setup ideally we circle back to break some of that logic on out to shared steps --- Engine/source/T3D/fx/particleEmitter.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/Engine/source/T3D/fx/particleEmitter.cpp b/Engine/source/T3D/fx/particleEmitter.cpp index 5f7b0829d..45acd1ecb 100644 --- a/Engine/source/T3D/fx/particleEmitter.cpp +++ b/Engine/source/T3D/fx/particleEmitter.cpp @@ -1551,13 +1551,10 @@ void ParticleEmitter::updateBBox() for (Particle* part = part_list_head.next; part != NULL; part = part->next) { - for (Particle* part = part_list_head.next; part != NULL; part = part->next) - { - Point3F particleSize(part->size * 0.5f); - F32 motion = getMax((part->vel.len() * part->totalLifetime / 1000.0f), 1.0f); - minPt.setMin(part->pos - particleSize - Point3F(motion)); - maxPt.setMax(part->pos + particleSize + Point3F(motion)); - } + Point3F particleSize(part->size * 0.5f); + F32 motion = getMax((part->vel.len() * part->totalLifetime / 1000.0f), 1.0f); + minPt.setMin(part->pos - particleSize - Point3F(motion)); + maxPt.setMax(part->pos + particleSize + Point3F(motion)); } mObjBox = Box3F(minPt, maxPt); @@ -1675,8 +1672,8 @@ void ParticleEmitter::addParticle(const Point3F& pos, const Point3F& axis, const } else { - U32 dBlockIndex = gRandGen.randI() % mDataBlock->particleDataBlocks.size(); - mDataBlock->particleDataBlocks[dBlockIndex]->initializeParticle(pNew, vel); + dBlockIndex = gRandGen.randI() % mDataBlock->particleDataBlocks.size(); + mDataBlock->particleDataBlocks[dBlockIndex]->initializeParticle(pNew, vel); } updateKeyData( pNew ); @@ -2220,7 +2217,7 @@ void ParticleEmitter::setupOriented( Particle *part, LinearColorF partCol = mLerp( part->color, ( part->color * ambientColor ), ambientLerp ); const ColorI color = partCol.toColorI(); // Here we deal with UVs for animated particle (oriented) - if (part->dataBlock->animateTexture) + if (part->dataBlock->animateTexture && !part->dataBlock->animTexFrames.empty()) { // Let particle compute the UV indices for current frame S32 fm = (S32)(part->currentAge*(1.0f/1000.0f)*part->dataBlock->framesPerSec); @@ -2331,7 +2328,7 @@ void ParticleEmitter::setupAligned( const Particle *part, LinearColorF partCol = mLerp( part->color, ( part->color * ambientColor ), ambientLerp ); const ColorI color = partCol.toColorI(); // Here we deal with UVs for animated particle - if (part->dataBlock->animateTexture) + if (part->dataBlock->animateTexture && !part->dataBlock->animTexFrames.empty()) { // Let particle compute the UV indices for current frame S32 fm = (S32)(part->currentAge*(1.0f/1000.0f)*part->dataBlock->framesPerSec); @@ -2520,7 +2517,7 @@ void ParticleEmitter::setupRibbon(Particle *part, ColorI pCol = partCol.toColorI(); // Here we deal with UVs for animated particle (oriented) - if (part->dataBlock->animateTexture) + if (part->dataBlock->animateTexture && !part->dataBlock->animTexFrames.empty()) { // Let particle compute the UV indices for current frame S32 fm = (S32)(part->currentAge*(1.0f / 1000.0f)*part->dataBlock->framesPerSec); From 2d50f52cf135fd8e6ebed638767dd60fd34d01c0 Mon Sep 17 00:00:00 2001 From: Jeff Hutchinson Date: Mon, 20 Sep 2021 21:00:33 -0400 Subject: [PATCH 9/9] Allow local variables to be used in eval. --- Engine/source/console/astNodes.cpp | 55 ++------------------------ Engine/source/console/codeBlock.cpp | 15 ++++++- Engine/source/console/compiledEval.cpp | 3 +- Engine/source/console/compiler.cpp | 42 ++++++++++++++++++++ Engine/source/console/compiler.h | 29 ++++++++++++++ 5 files changed, 90 insertions(+), 54 deletions(-) diff --git a/Engine/source/console/astNodes.cpp b/Engine/source/console/astNodes.cpp index 091f6cf1c..aaca1ea06 100644 --- a/Engine/source/console/astNodes.cpp +++ b/Engine/source/console/astNodes.cpp @@ -56,57 +56,7 @@ namespace Compiler using namespace Compiler; -class FuncVars -{ - struct Var - { - S32 reg; - TypeReq currentType; - StringTableEntry name; - bool isConstant; - }; - -public: - S32 assign(StringTableEntry var, TypeReq currentType, S32 lineNumber, bool isConstant = false) - { - std::unordered_map::iterator found = vars.find(var); - if (found != vars.end()) - { - AssertISV(!found->second.isConstant, avar("Reassigning variable %s when it is a constant. File: %s Line : %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); - return found->second.reg; - } - - S32 id = counter++; - vars[var] = { id, currentType, var, isConstant }; - variableNameMap[id] = var; - - return id; - } - - S32 lookup(StringTableEntry var, S32 lineNumber) - { - std::unordered_map::iterator found = vars.find(var); - AssertISV(found != vars.end(), avar("Variable %s referenced before used when compiling script. File: %s Line: %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); - return found->second.reg; - } - - TypeReq lookupType(StringTableEntry var, S32 lineNumber) - { - std::unordered_map::iterator found = vars.find(var); - - AssertISV(found != vars.end(), avar("Variable %s referenced before used when compiling script. File: %s Line: %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); - return found->second.currentType; - } - - inline S32 count() { return counter; } - - std::unordered_map variableNameMap; - -private: - std::unordered_map vars; - S32 counter = 0; -}; - +FuncVars gEvalFuncVars; FuncVars* gFuncVars = NULL; inline FuncVars* getFuncVars(S32 lineNumber) @@ -1602,7 +1552,8 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip) tbl->add(fnName, nameSpace, varName); } - gFuncVars = NULL; + // In eval mode, global func vars are allowed. + gFuncVars = gIsEvalCompile ? &gEvalFuncVars : NULL; return ip; } diff --git a/Engine/source/console/codeBlock.cpp b/Engine/source/console/codeBlock.cpp index 1d1ad7593..f03ec25f6 100644 --- a/Engine/source/console/codeBlock.cpp +++ b/Engine/source/console/codeBlock.cpp @@ -37,6 +37,9 @@ CodeBlock * CodeBlock::smCodeBlockList = NULL; CodeBlock * CodeBlock::smCurrentCodeBlock = NULL; ConsoleParser *CodeBlock::smCurrentParser = NULL; +extern FuncVars gEvalFuncVars; +extern FuncVars* gFuncVars; + //------------------------------------------------------------------------- CodeBlock::CodeBlock() @@ -491,6 +494,8 @@ bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, con chompUTF8BOM(inScript, &script); gSyntaxError = false; + gIsEvalCompile = false; + gFuncVars = NULL; consoleAllocReset(); @@ -629,6 +634,11 @@ ConsoleValue CodeBlock::compileExec(StringTableEntry fileName, const char *inStr addToCodeList(); gStatementList = NULL; + + // we are an eval compile if we don't have a file name associated (no exec) + gIsEvalCompile = fileName == NULL; + // In eval mode, global func vars are allowed. + gFuncVars = gIsEvalCompile ? &gEvalFuncVars : NULL; // Set up the parser. smCurrentParser = getParserForFile(fileName); @@ -667,6 +677,8 @@ ConsoleValue CodeBlock::compileExec(StringTableEntry fileName, const char *inStr codeStream.emit(OP_RETURN_VOID); codeStream.emitCodeStream(&codeSize, &code, &lineBreakPairs); + + S32 localRegisterCount = gIsEvalCompile ? gEvalFuncVars.count() : 0; consoleAllocReset(); @@ -683,7 +695,8 @@ ConsoleValue CodeBlock::compileExec(StringTableEntry fileName, const char *inStr if (lastIp + 1 != codeSize) Con::warnf(ConsoleLogEntry::General, "precompile size mismatch, precompile: %d compile: %d", codeSize, lastIp); - return std::move(exec(0, fileName, NULL, 0, 0, noCalls, NULL, setFrame)); + // repurpose argc as local register counter for global state + return std::move(exec(0, fileName, NULL, localRegisterCount, 0, noCalls, NULL, setFrame)); } //------------------------------------------------------------------------- diff --git a/Engine/source/console/compiledEval.cpp b/Engine/source/console/compiledEval.cpp index 561e1f04a..360c13c90 100644 --- a/Engine/source/console/compiledEval.cpp +++ b/Engine/source/console/compiledEval.cpp @@ -693,7 +693,8 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa // Do we want this code to execute using a new stack frame? if (setFrame < 0) { - gEvalState.pushFrame(NULL, NULL, 0); + // argc is the local count for eval + gEvalState.pushFrame(NULL, NULL, argc); gCallStack.pushFrame(0); popFrame = true; } diff --git a/Engine/source/console/compiler.cpp b/Engine/source/console/compiler.cpp index 1ab6e7b22..13839feda 100644 --- a/Engine/source/console/compiler.cpp +++ b/Engine/source/console/compiler.cpp @@ -34,6 +34,8 @@ #include "console/simBase.h" +extern FuncVars gEvalFuncVars; + namespace Compiler { @@ -86,6 +88,7 @@ namespace Compiler //------------------------------------------------------------ bool gSyntaxError = false; + bool gIsEvalCompile = false; //------------------------------------------------------------ @@ -121,6 +124,7 @@ namespace Compiler getFunctionStringTable().reset(); getIdentTable().reset(); getFunctionVariableMappingTable().reset(); + gEvalFuncVars.clear(); } void *consoleAlloc(U32 size) { return gConsoleAllocator.alloc(size); } @@ -132,6 +136,44 @@ namespace Compiler using namespace Compiler; +S32 FuncVars::assign(StringTableEntry var, TypeReq currentType, S32 lineNumber, bool isConstant) +{ + std::unordered_map::iterator found = vars.find(var); + if (found != vars.end()) + { + AssertISV(!found->second.isConstant, avar("Reassigning variable %s when it is a constant. File: %s Line : %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); + return found->second.reg; + } + + S32 id = counter++; + vars[var] = { id, currentType, var, isConstant }; + variableNameMap[id] = var; + + return id; +} + +S32 FuncVars::lookup(StringTableEntry var, S32 lineNumber) +{ + std::unordered_map::iterator found = vars.find(var); + AssertISV(found != vars.end(), avar("Variable %s referenced before used when compiling script. File: %s Line: %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); + return found->second.reg; +} + +TypeReq FuncVars::lookupType(StringTableEntry var, S32 lineNumber) +{ + std::unordered_map::iterator found = vars.find(var); + + AssertISV(found != vars.end(), avar("Variable %s referenced before used when compiling script. File: %s Line: %d", var, CodeBlock::smCurrentParser->getCurrentFile(), lineNumber)); + return found->second.currentType; +} + +void FuncVars::clear() +{ + vars.clear(); + variableNameMap.clear(); + counter = 0; +} + //------------------------------------------------------------------------- diff --git a/Engine/source/console/compiler.h b/Engine/source/console/compiler.h index 117576a61..24067257f 100644 --- a/Engine/source/console/compiler.h +++ b/Engine/source/console/compiler.h @@ -276,6 +276,35 @@ namespace Compiler void consoleAllocReset(); extern bool gSyntaxError; + extern bool gIsEvalCompile; +}; + +class FuncVars +{ + struct Var + { + S32 reg; + TypeReq currentType; + StringTableEntry name; + bool isConstant; + }; + +public: + S32 assign(StringTableEntry var, TypeReq currentType, S32 lineNumber, bool isConstant = false); + + S32 lookup(StringTableEntry var, S32 lineNumber); + + TypeReq lookupType(StringTableEntry var, S32 lineNumber); + + inline S32 count() { return counter; } + + std::unordered_map variableNameMap; + + void clear(); + +private: + std::unordered_map vars; + S32 counter = 0; }; /// Utility class to emit and patch bytecode