فهرست منبع

Merge remote-tracking branch 'devhead/Preview4_0' into cpuinfo

Jeff Hutchinson 4 سال پیش
والد
کامیت
ca0a5d41a7
42فایلهای تغییر یافته به همراه658 افزوده شده و 208 حذف شده
  1. 24 3
      Engine/source/T3D/assets/MaterialAsset.cpp
  2. 6 0
      Engine/source/T3D/assets/MaterialAsset.h
  3. 9 12
      Engine/source/T3D/fx/particleEmitter.cpp
  4. 7 8
      Engine/source/T3D/fx/precipitation.cpp
  5. 29 19
      Engine/source/T3D/fx/precipitation.h
  6. 2 2
      Engine/source/T3D/prefab.cpp
  7. 1 1
      Engine/source/T3D/prefab.h
  8. 2 0
      Engine/source/T3D/projectile.cpp
  9. 0 4
      Engine/source/T3D/tsStatic.cpp
  10. 3 52
      Engine/source/console/astNodes.cpp
  11. 14 1
      Engine/source/console/codeBlock.cpp
  12. 3 2
      Engine/source/console/compiledEval.cpp
  13. 42 0
      Engine/source/console/compiler.cpp
  14. 29 0
      Engine/source/console/compiler.h
  15. 1 1
      Engine/source/gfx/gfxInit.cpp
  16. 1 1
      Engine/source/gfx/gl/gfxGLDevice.cpp
  17. 5 3
      Engine/source/gfx/gl/gfxGLShader.cpp
  18. 4 2
      Engine/source/gfx/gl/gfxGLShader.h
  19. 8 6
      Engine/source/gui/core/guiCanvas.cpp
  20. 2 2
      Engine/source/gui/worldEditor/worldEditor.cpp
  21. 13 3
      Engine/source/platformX86UNIX/x86UNIXConsole.cpp
  22. 12 0
      Engine/source/terrain/terrData.cpp
  23. 33 0
      Engine/source/terrain/terrData.h
  24. 0 2
      Templates/BaseGame/game/data/UI/guis/mainMenu.gui
  25. 14 5
      Templates/BaseGame/game/main.tscript.in
  26. 3 1
      Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript
  27. 1 1
      Templates/BaseGame/game/tools/assetBrowser/scripts/assetTypes/terrain.tscript
  28. 1 1
      Templates/BaseGame/game/tools/assetBrowser/scripts/creator.tscript
  29. 0 1
      Templates/BaseGame/game/tools/convexEditor/main.tscript
  30. 1 1
      Templates/BaseGame/game/tools/guiEditor/scripts/guiEditor.ed.tscript
  31. 5 5
      Templates/BaseGame/game/tools/guiEditor/scripts/guiEditorCanvas.ed.tscript
  32. 1 1
      Templates/BaseGame/game/tools/guiEditor/scripts/guiEditorNewGuiDialog.ed.tscript
  33. 7 10
      Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript
  34. 1 1
      Templates/BaseGame/game/tools/projectImporter/scripts/pre40/T3Dpre4ProjectImporter.tscript
  35. 38 12
      Templates/BaseGame/game/tools/projectImporter/scripts/projectImporter.tscript
  36. 3 3
      Templates/BaseGame/game/tools/riverEditor/riverEditorGui.tscript
  37. 287 24
      Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui
  38. 8 2
      Templates/BaseGame/game/tools/worldEditor/scripts/EditorGui.ed.tscript
  39. 1 1
      Templates/BaseGame/game/tools/worldEditor/scripts/editor.keybinds.tscript
  40. 1 1
      Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.tscript
  41. 31 11
      Templates/BaseGame/game/tools/worldEditor/scripts/menuHandlers.ed.tscript
  42. 5 3
      Templates/BaseGame/game/tools/worldEditor/scripts/menus.ed.tscript

+ 24 - 3
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))

+ 6 - 0
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();

+ 9 - 12
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);

+ 7 - 8
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 && !getSFXProfile())
       return false;
 
    return true;
@@ -200,7 +199,7 @@ void PrecipitationData::packData(BitStream* stream)
 {
    Parent::packData(stream);
 
-   sfxWrite( stream, soundProfile );
+   PACKDATA_SOUNDASSET(Sound);
 
    PACKDATA_IMAGEASSET(Drop);
 
@@ -217,7 +216,7 @@ void PrecipitationData::unpackData(BitStream* stream)
 {
    Parent::unpackData(stream);
 
-   sfxRead( stream, &soundProfile );
+   UNPACKDATA_SOUNDASSET(Sound);
 
    UNPACKDATA_IMAGEASSET(Drop);
 
@@ -598,9 +597,9 @@ bool Precipitation::onNewDataBlock( GameBaseData *dptr, bool reload )
    {
       SFX_DELETE( mAmbientSound );
 
-      if ( mDataBlock->soundProfile )
+      if ( mDataBlock->getSFXProfile())
       {
-         mAmbientSound = SFX->createSource( mDataBlock->soundProfile, &getTransform() );
+         mAmbientSound = SFX->createSource(mDataBlock->getSFXProfile(), &getTransform() );
          if ( mAmbientSound )
             mAmbientSound->play();
       }

+ 29 - 19
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,39 @@ 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);
-
-   void onDropChanged() {}
-   void onSplashChanged() {}
+      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() {}
+
+      SFXProfile* getSFXProfile() {
+         if (mSoundAsset.notNull())
+            return mSoundAsset->getSfxProfile();
+         else
+            return NULL;
+      }
 };
 
 struct Raindrop

+ 2 - 2
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;
    }
 

+ 1 - 1
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.

+ 2 - 0
Engine/source/T3D/projectile.cpp

@@ -786,6 +786,8 @@ bool Projectile::onAdd()
       // If we're on the server, we need to inherit some of our parent's velocity
       //
       mCurrTick = 0;
+
+      scriptOnAdd();
    }
    else
    {

+ 0 - 4
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);
 

+ 3 - 52
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<StringTableEntry, Var>::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<StringTableEntry, Var>::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<StringTableEntry, Var>::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<S32, StringTableEntry> variableNameMap;
-
-private:
-   std::unordered_map<StringTableEntry, Var> 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;
 }

+ 14 - 1
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));
 }
 
 //-------------------------------------------------------------------------

+ 3 - 2
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;
       }
@@ -734,7 +735,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;

+ 42 - 0
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<StringTableEntry, Var>::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<StringTableEntry, Var>::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<StringTableEntry, Var>::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;
+}
+
 //-------------------------------------------------------------------------
 
 

+ 29 - 0
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<S32, StringTableEntry> variableNameMap;
+
+   void clear();
+   
+private:
+   std::unordered_map<StringTableEntry, Var> vars;
+   S32 counter = 0;
 };
 
 /// Utility class to emit and patch bytecode

+ 1 - 1
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);
    }

+ 1 - 1
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;
 }

+ 5 - 3
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:

+ 4 - 2
Engine/source/gfx/gl/gfxGLShader.h

@@ -32,14 +32,15 @@
 class GFXGLShaderConstHandle;
 class FileStream;
 class GFXGLShaderConstBuffer;
+class GFXGLDevice;
 
 class GFXGLShader : public GFXShader
 {
    typedef Map<String, GFXGLShaderConstHandle*> 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<GFXGLShaderConstHandle*> mValidHandles;
 };
 

+ 8 - 6
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.

+ 2 - 2
Engine/source/gui/worldEditor/worldEditor.cpp

@@ -1993,12 +1993,12 @@ void WorldEditor::on3DMouseMove(const Gui3DMouseEvent & event)
    if ( !mHitObject )
    {
       SceneObject *hitObj = NULL;
-      if ( collide(event, &hitObj) && hitObj->isSelectionEnabled() && !objClassIgnored(hitObj) )
+      if ( collide(event, &hitObj) && !hitObj->isDeleted() && hitObj->isSelectionEnabled() && !objClassIgnored(hitObj) )
       {
          mHitObject = hitObj;
       }
    }
-   
+
    mLastMouseEvent = event;
 }
 

+ 13 - 3
Engine/source/platformX86UNIX/x86UNIXConsole.cpp

@@ -41,7 +41,10 @@ StdConsole *stdConsole = NULL;
 DefineEngineFunction(enableWinConsole, void, (bool _enable),, "enableWinConsole(bool);")
 {
    if (stdConsole)
-      stdConsole->enable(_enable);
+   {
+       stdConsole->enable(_enable);
+       stdConsole->enableInput(_enable);
+   }
 }
 
 void StdConsole::create()
@@ -141,6 +144,9 @@ StdConsole::StdConsole()
    stdIn  = dup(0);
    stdErr = dup(2);
 
+   // Ensure in buffer is null terminated after allocation
+   inbuf[0] = 0x00;
+
    iCmdIndex = 0;
    stdConsoleEnabled = false;
    stdConsoleInputEnabled = false;
@@ -195,11 +201,14 @@ void StdConsole::processConsoleLine(const char *consoleLine)
 {
    if(stdConsoleEnabled)
    {
-      inbuf[inpos] = 0;
       if(lineOutput)
          printf("%s\n", consoleLine);
       else
-         printf("%c%s\n%s%s", '\r', consoleLine, Con::getVariable("Con::Prompt"), inbuf);
+      {
+          // Clear current line before outputting the console line. This prevents prompt text from overflowing onto normal output.
+          printf("%c[2K", 27);
+          printf("%c%s\n%s%s", '\r', consoleLine, Con::getVariable("Con::Prompt"), inbuf);
+      }
    }
 }
 
@@ -323,6 +332,7 @@ void StdConsole::process()
 
                   printf("%s", Con::getVariable("Con::Prompt"));
                   inpos = outpos = 0;
+                  inbuf[0] = 0x00; // Ensure inbuf is NULL terminated after sending out command
                   break;
             case 27:
                // JMQTODO: are these magic numbers keyboard map specific?

+ 12 - 0
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));
+}

+ 33 - 0
Engine/source/terrain/terrData.h

@@ -488,6 +488,39 @@ public:
    void inspectPostApply();
 
    virtual void getUtilizedAssets(Vector<StringTableEntry>* 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;

+ 0 - 2
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";

+ 14 - 5
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,18 @@ 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)
+{
+    if ($platform $= "windows")
+       displaySplashWindow($Core::splashWindowImage);
+}
+else
+{
+    $Video::forceDisplayAdapter = -1;
+}
+    
 //-----------------------------------------------------------------------------
 // Load any gameplay modules
 ModuleDatabase.scanModules( "data", false );
@@ -42,6 +50,7 @@ else
    }
 }
 
-closeSplashWindow();
+if ( ($Server::Dedicated == false) && ($platform $= "windows") )
+    closeSplashWindow();
 
 echo("Engine initialized...");

+ 3 - 1
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);
    

+ 1 - 1
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" );
       }

+ 1 - 1
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"*/ );

+ 0 - 1
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.

+ 1 - 1
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();" );
 }
 
 //---------------------------------------------------------------------------------------------

+ 5 - 5
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 );
 }
 

+ 1 - 1
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;

+ 7 - 10
Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript

@@ -1097,9 +1097,6 @@ function MaterialEditorGui::updateActiveMaterial(%this, %propertyField, %value,
 {
    MaterialEditorGui.setMaterialDirty();
 
-   if(%value $= "")
-      %value = "\"\"";
-   
    // Here is where we handle undo actions with slider controls. We want to be able to
    // undo every onMouseUp; so we overrite the same undo action when necessary in order
    // to achieve this desired effect.
@@ -1130,7 +1127,7 @@ function MaterialEditorGui::updateActiveMaterial(%this, %propertyField, %value,
    
    if (MaterialEditorGui.livePreview == true)
    {
-      MaterialEditorGui.setFieldValue(%propertyField, %value);
+      MaterialEditorGui.currentMaterial.setFieldValue(%propertyField, %value);
       MaterialEditorGui.currentMaterial.flush();
       MaterialEditorGui.currentMaterial.reload();
    }
@@ -1263,8 +1260,8 @@ function MaterialEditorGui::doUpdateTextureMap( %this, %assetId )
          %bitmap = strreplace(%bitmap,"tools/materialEditor/scripts/","");
          %bitmapCtrl.setBitmap(%bitmap);
          %textCtrl.setText(%assetId);
-         MaterialEditorGui.updateActiveMaterial(%type @ "Map[" @ %layer @ "]","\"\"");
-         MaterialEditorGui.updateActiveMaterial(%type @ "MapAsset[" @ %layer @ "]","\"" @ %assetId @ "\"");	
+         MaterialEditorGui.updateActiveMaterial(%type @ "Map[" @ %layer @ "]","");
+         MaterialEditorGui.updateActiveMaterial(%type @ "MapAsset[" @ %layer @ "]", %assetId);	
       }
    }
    
@@ -1276,7 +1273,7 @@ function MaterialEditorGui::updateDetailScale(%this,%newScale)
 {
    %layer = MaterialEditorGui.currentLayer;
    
-   %detailScale = "\"" @ %newScale SPC %newScale @ "\"";
+   %detailScale = %newScale SPC %newScale;
    MaterialEditorGui.updateActiveMaterial("detailScale[" @ %layer @ "]", %detailScale);
    }
    
@@ -1284,7 +1281,7 @@ function MaterialEditorGui::updateDetailNormalStrength(%this,%newStrength)
 {
    %layer = MaterialEditorGui.currentLayer;
    
-   %detailStrength = "\"" @ %newStrength @ "\"";
+   %detailStrength = %newStrength;
    MaterialEditorGui.updateActiveMaterial("detailNormalMapStrength[" @ %layer @ "]", %detailStrength);
 }
 
@@ -1295,7 +1292,7 @@ function MaterialEditorGui::updateRotationOffset(%this, %isSlider, %onMouseUp)
 	%Y = MaterialEditorPropertiesWindow-->RotationTextEditV.getText();
 	MaterialEditorPropertiesWindow-->RotationCrosshair.setPosition(45*mAbs(%X)-2, 45*mAbs(%Y)-2);
 	
-	MaterialEditorGui.updateActiveMaterial("rotPivotOffset[" @ %layer @ "]","\"" @ %X SPC %Y @ "\"",%isSlider,%onMouseUp);
+	MaterialEditorGui.updateActiveMaterial("rotPivotOffset[" @ %layer @ "]", %X SPC %Y,%isSlider,%onMouseUp);
 }
 
 function MaterialEditorGui::updateRotationSpeed(%this, %isSlider, %onMouseUp)
@@ -1457,7 +1454,7 @@ function MaterialEditorGui::syncGuiColor(%this, %guiCtrl, %propname, %color)
    %a = getWord(%color,3);
 
    %colorSwatch = (%r SPC %g SPC %b SPC %a);
-   %color = "\"" @ %r SPC %g SPC %b SPC %a @ "\"";
+   %color = %r SPC %g SPC %b SPC %a;
 
    %guiCtrl.color = %colorSwatch;
 	MaterialEditorGui.updateActiveMaterial(%propName, %color);

+ 1 - 1
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");

+ 38 - 12
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);
+            //likely a material name, so handle it that way
+            %assetId = MaterialAsset::getAssetIdByMaterialName(%targetFilename);
+         }
       }
       else
       {
          if(!isFile(%targetFilename))
-      {
-         error("Legacy Project Importer - file described in line could not be found/is not valid");
-         return %line;
-      }
-      
-      $ProjectImporter::assetQuery.clear();
-      %foundAssets = AssetDatabase.findAssetLooseFile($ProjectImporter::assetQuery, %targetFilename);
-      if(%foundAssets != 0)
-      {
-         %assetId = $ProjectImporter::assetQuery.getAsset(0);
+         {
+            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);
+            }
          }
       }
      

+ 3 - 3
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;

+ 287 - 24
Templates/BaseGame/game/tools/worldEditor/gui/objectBuilderGui.ed.gui

@@ -313,10 +313,8 @@ function ObjectBuilderGui::createImageAssetType(%this, %index)
    else
       %name = %this.field[%index, text];
 
-   // 
-   /*%this.textControls[%this.numControls] = new GuiTextCtrl() {
+   %this.textControls[%this.numControls] = new GuiTextCtrl() {
       profile = "ToolsGuiTextRightProfile";
-      internalName = "assetText";
       text = %name;
       extent = %this.fieldNameExtent;
       position = %this.curXPos @ " " @ %this.curYPos;
@@ -324,18 +322,87 @@ function ObjectBuilderGui::createImageAssetType(%this, %index)
    };
 
    // 
-   %this.controls[%this.numControls] = new GuiButtonCtrl() {
+   %this.controls[%this.numControls] = new GuiControl() {
       HorizSizing = "width";
-      profile = "ToolsGuiButtonProfile";
-      internalName = "assetButton";
-      extent = %this.fileButtonExtent;
+      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 @ ".getImageAsset(" @ %index @ ");";
    };
+   %button.setBitmap("ToolsModule:GameTSCtrl_image");
+   %this.controls[%this.numControls].addGuiControl(%button);
 
-   %val = %this.field[%index, value];
-   %this.controls[%this.numControls].setText(fileBase(%val) @ fileExt(%val));*/
+   %this.numControls++;
+   %this.curYPos += %this.defaultFieldStep;
+}
+
+function ObjectBuilderGui::getImageAsset(%this, %index)
+{
+   if(%index >= %this.numFields || %this.field[%index, name] $= "")
+   {
+      error("ObjectBuilderGui::getImageAsset: invalid field");
+      return;
+   }
+   
+   %val = %this.field[%index, ext];
+
+   //%path = filePath(%val);
+   //%ext = fileExt(%val);
+
+   %this.currentControl = %index;
+   AssetBrowser.showDialog("ImageAsset", %this @ ".gotImageAsset", "", "", "");
+   //getLoadFilename( %val @ "|" @ %val, %this @ ".gotFileName", %this.lastPath );
+}
+
+function ObjectBuilderGui::gotImageAsset(%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::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";
@@ -373,7 +440,7 @@ function ObjectBuilderGui::createImageAssetType(%this, %index)
       extent = %this.matButtonExtent;
       position = getWord(%this.textEditExtent,0) - getWord(%this.matButtonExtent,0) @ " 0";
       modal = "1";
-      command = %this @ ".getImageAsset(" @ %index @ ");";
+      command = %this @ ".getMaterialAsset(" @ %index @ ");";
    };
    %button.setBitmap("ToolsModule:change_material_btn_n_image");
    %this.controls[%this.numControls].addGuiControl(%button);
@@ -382,11 +449,11 @@ function ObjectBuilderGui::createImageAssetType(%this, %index)
    %this.curYPos += %this.defaultFieldStep;
 }
 
-function ObjectBuilderGui::getImageAsset(%this, %index)
+function ObjectBuilderGui::getMaterialAsset(%this, %index)
 {
    if(%index >= %this.numFields || %this.field[%index, name] $= "")
    {
-      error("ObjectBuilderGui::getImageAsset: invalid field");
+      error("ObjectBuilderGui::getMaterialAsset: invalid field");
       return;
    }
    
@@ -396,11 +463,193 @@ function ObjectBuilderGui::getImageAsset(%this, %index)
    //%ext = fileExt(%val);
 
    %this.currentControl = %index;
-   AssetBrowser.showDialog("ImageAsset", %this @ ".gotImageAsset", "", "", "");
+   AssetBrowser.showDialog("MaterialAsset", %this @ ".gotMaterialAsset", "", "", "");
    //getLoadFilename( %val @ "|" @ %val, %this @ ".gotFileName", %this.lastPath );
 }
 
-function ObjectBuilderGui::gotImageAsset(%this, %name)
+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;
    
@@ -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();

+ 8 - 2
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] !$= "")

+ 1 - 1
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();" );

+ 1 - 1
Templates/BaseGame/game/tools/worldEditor/scripts/editors/creator.ed.tscript

@@ -227,7 +227,7 @@ function EWCreatorWindow::createObject( %this, %cmd )
       %this.setNewObjectGroup( getScene(0) );
 
    pushInstantGroup();
-   %objId = eval(%cmd);
+   %objId = eval("return " @ %cmd);
    popInstantGroup();
    
    if( isObject( %objId ) )

+ 31 - 11
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))
+         {
+            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()

+ 5 - 3
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();";
       };
    }
 }