diff --git a/Bin/Data/Scripts/NinjaSnowWar.as b/Bin/Data/Scripts/NinjaSnowWar.as index 3b2ecc8cf..d942abd2e 100644 --- a/Bin/Data/Scripts/NinjaSnowWar.as +++ b/Bin/Data/Scripts/NinjaSnowWar.as @@ -180,7 +180,7 @@ void updateControls() Entity@ playerEntity = gameScene.getEntity("ObjPlayer"); if (@playerEntity == null) return; - + ScriptInstance@ instance = playerEntity.getComponent("ScriptInstance"); GameObject@ object = cast<GameObject>(instance.getScriptObject()); object.setControls(playerControls); @@ -205,7 +205,7 @@ void updateCamera() // Collide camera ray with static objects (collision mask 2) Vector3 rayDir = (maxDist - minDist).getNormalized(); float rayDistance = cameraMaxDist - cameraMinDist + cameraSafetyDist; - array<PhysicsRaycastResult> result = gameScene.getPhysicsWorld().raycast(Ray(minDist, rayDir), rayDistance, 2); + array<PhysicsRaycastResult>@ result = gameScene.getPhysicsWorld().raycast(Ray(minDist, rayDir), rayDistance, 2); if (result.length() > 0) rayDistance = min(rayDistance, result[0].distance - cameraSafetyDist); diff --git a/Engine/Engine/RegisterScene.cpp b/Engine/Engine/RegisterScene.cpp index 02671f7e3..172f636f8 100644 --- a/Engine/Engine/RegisterScene.cpp +++ b/Engine/Engine/RegisterScene.cpp @@ -388,7 +388,6 @@ static CScriptArray* SceneGetEntitiesWithClass(const std::string& className, Sce } } } - return vectorToHandleArray<Entity*>(result, "array<Entity@>"); } diff --git a/Engine/Script/ScriptFile.cpp b/Engine/Script/ScriptFile.cpp index b5a57d3ec..e3389fefa 100644 --- a/Engine/Script/ScriptFile.cpp +++ b/Engine/Script/ScriptFile.cpp @@ -28,6 +28,7 @@ #include "ResourceCache.h" #include "ScriptEngine.h" #include "ScriptFile.h" +#include "ScriptInstance.h" #include "SharedArrayPtr.h" #include "StringUtils.h" @@ -72,10 +73,17 @@ void ScriptFile::load(Deserializer& source, ResourceCache* cache) { PROFILE(Script_Load); - // Discard the previous module if there was one + // If script instances have created objects from this file, release them now + // Make a copy of the vector because the script instances will remove themselves from the member vector + std::vector<ScriptInstance*> instances = mScriptInstances; + for (std::vector<ScriptInstance*>::iterator i = instances.begin(); i != instances.end(); ++i) + (*i)->releaseObject(); + + // Discard the previous module if there was one, and clear search caches mCompiled = false; mAllIncludeFiles.clear(); - mInterfaceFound.clear(); + mCheckedClasses.clear(); + mFunctions.clear(); setMemoryUse(0); removeAllEventHandlers(); @@ -101,6 +109,10 @@ void ScriptFile::load(Deserializer& source, ResourceCache* cache) LOGINFO("Compiled script module " + getName()); mCompiled = true; + + // Now let the script instances recreate their objects + for (std::vector<ScriptInstance*>::iterator i = instances.begin(); i != instances.end(); ++i) + (*i)->setScriptClass(this, (*i)->getClassName()); } void ScriptFile::addEventHandler(StringHash eventType, const std::string& handlerName) @@ -262,8 +274,10 @@ asIScriptObject* ScriptFile::createObject(const std::string& className, asIScrip // Ensure that the type implements the "ScriptObject" interface, so it can be returned also to script properly bool found = false; - std::map<asIObjectType*, bool>::const_iterator i = mInterfaceFound.find(type); - if (i == mInterfaceFound.end()) + std::map<asIObjectType*, bool>::const_iterator i = mCheckedClasses.find(type); + if (i != mCheckedClasses.end()) + found = i->second; + else { unsigned numInterfaces = type->GetInterfaceCount(); for (unsigned j = 0; j < numInterfaces; ++j) @@ -275,10 +289,8 @@ asIScriptObject* ScriptFile::createObject(const std::string& className, asIScrip break; } } - mInterfaceFound[type] = found; + mCheckedClasses[type] = found; } - else - found = i->second; if (!found) { LOGERROR("Script class " + className + " does not implement the ScriptObject interface"); @@ -302,13 +314,19 @@ asIScriptObject* ScriptFile::createObject(const std::string& className, asIScrip return obj; } -asIScriptFunction* ScriptFile::getFunction(const std::string& declaration) const +asIScriptFunction* ScriptFile::getFunction(const std::string& declaration) { if (!mCompiled) return 0; + std::map<std::string, asIScriptFunction*>::const_iterator i = mFunctions.find(declaration); + if (i != mFunctions.end()) + return i->second; + int id = mScriptModule->GetFunctionIdByDecl(declaration.c_str()); - return mScriptModule->GetFunctionDescriptorById(id); + asIScriptFunction* function = mScriptModule->GetFunctionDescriptorById(id); + mFunctions[declaration] = function; + return function; } asIScriptFunction* ScriptFile::getMethod(asIScriptObject* object, const std::string& declaration) const @@ -324,6 +342,23 @@ asIScriptFunction* ScriptFile::getMethod(asIScriptObject* object, const std::str return mScriptModule->GetFunctionDescriptorById(id); } +void ScriptFile::addScriptInstance(ScriptInstance* instance) +{ + mScriptInstances.push_back(instance); +} + +void ScriptFile::removeScriptInstance(ScriptInstance* instance) +{ + for (std::vector<ScriptInstance*>::iterator i = mScriptInstances.begin(); i != mScriptInstances.end(); ++i) + { + if ((*i) == instance) + { + mScriptInstances.erase(i); + break; + } + } +} + void ScriptFile::addScriptSection(asIScriptEngine* engine, Deserializer& source, ResourceCache* cache) { unsigned dataSize = source.getSize(); diff --git a/Engine/Script/ScriptFile.h b/Engine/Script/ScriptFile.h index acd44f736..6408af51d 100644 --- a/Engine/Script/ScriptFile.h +++ b/Engine/Script/ScriptFile.h @@ -33,6 +33,7 @@ #include <vector> class ScriptEngine; +class ScriptInstance; class Variant; class asIObjectType; class asIScriptContext; @@ -76,13 +77,18 @@ public: ScriptEngine* getScriptEngine() const { return mScriptEngine; } //! Return script module asIScriptModule* getScriptModule() const { return mScriptModule; } - //! Return a function by declaration - asIScriptFunction* getFunction(const std::string& declaration) const; + //! Return a function by declaration. Will be stored to a search cache so that further searches should be faster + asIScriptFunction* getFunction(const std::string& declaration); //! Return an object method by declaration asIScriptFunction* getMethod(asIScriptObject* object, const std::string& declaration) const; //! Return whether script compiled successfully bool isCompiled() const { return mCompiled; } + //! Add script instance to keep track of in case of script reload + void addScriptInstance(ScriptInstance* instance); + //! Remove script instance to keep track of + void removeScriptInstance(ScriptInstance* instance); + private: //! Add a script section, checking for includes recursively void addScriptSection(asIScriptEngine* engine, Deserializer& source, ResourceCache* cache); @@ -102,7 +108,11 @@ private: //! Encountered include files during script file loading std::set<std::string> mAllIncludeFiles; //! Search cache for checking whether script classes implement "ScriptObject" interface - std::map<asIObjectType*, bool> mInterfaceFound; + std::map<asIObjectType*, bool> mCheckedClasses; + //! Search cache for functions + std::map<std::string, asIScriptFunction*> mFunctions; + //! ScriptInstances that have created objects from this script file + std::vector<ScriptInstance*> mScriptInstances; }; //! Get last script file that is executing or has executed script functions diff --git a/Engine/Script/ScriptInstance.cpp b/Engine/Script/ScriptInstance.cpp index be1afeed6..495b2ac6f 100644 --- a/Engine/Script/ScriptInstance.cpp +++ b/Engine/Script/ScriptInstance.cpp @@ -275,7 +275,7 @@ bool ScriptInstance::setScriptClass(ScriptFile* scriptFile, const std::string& c return false; } - if ((scriptFile == mScriptFile) && (className == mClassName)) + if ((mScriptObject) && (scriptFile == mScriptFile) && (className == mClassName)) return true; releaseObject(); @@ -293,6 +293,7 @@ bool ScriptInstance::setScriptClass(ScriptFile* scriptFile, const std::string& c mScriptObject = mScriptFile->createObject(mClassName, mScriptContext); if (mScriptObject) { + mScriptFile->addScriptInstance(this); objectToInstance[(void*)mScriptObject] = this; getSupportedMethods(); if (mMethods[METHOD_START]) @@ -365,6 +366,8 @@ void ScriptInstance::releaseObject() mScriptObject->Release(); mScriptObject = 0; + + mScriptFile->removeScriptInstance(this); } } diff --git a/Engine/Script/ScriptInstance.h b/Engine/Script/ScriptInstance.h index 175c538e5..5c4b29424 100644 --- a/Engine/Script/ScriptInstance.h +++ b/Engine/Script/ScriptInstance.h @@ -114,15 +114,15 @@ public: asIScriptObject* getScriptObject() const { return mScriptObject; } //! Return class name const std::string& getClassName() const { return mClassName; } - //! Return whether object created and running bool isRunning() const { return mScriptObject != 0; } //! Return whether scripted updates and event handlers are enabled bool isEnabled() const { return mEnabled; } -private: //! Release object void releaseObject(); + +private: //! Clear supported methods void clearMethods(); //! Check for supported methods diff --git a/Examples/ScriptTest/Game.cpp b/Examples/ScriptTest/Game.cpp index e3ab50342..484571308 100644 --- a/Examples/ScriptTest/Game.cpp +++ b/Examples/ScriptTest/Game.cpp @@ -71,11 +71,14 @@ void Game::run() { init(); - if (!mRunFrameFunction) - return; - while (!mEngine->isExiting()) - mScriptFile->execute(mRunFrameFunction); + { + mScriptFile->execute("void runFrame()"); + + // Test reloading the ninja script + if (mEngine->getInput()->getKeyPress('R')) + mCache->reloadResource(mCache->getResource<ScriptFile>("Scripts/Ninja.as")); + } } void Game::init() @@ -112,10 +115,7 @@ void Game::init() // Execute the rest of initialization, including scene creation, in script mScriptFile = mCache->getResource<ScriptFile>("Scripts/NinjaSnowWar.as"); - mInitFunction = mScriptFile->getFunction("void init()"); - mRunFrameFunction = mScriptFile->getFunction("void runFrame()"); - - mScriptFile->execute(mInitFunction); + mScriptFile->execute("void init()"); } void Game::createSkyPlaneModel() diff --git a/Examples/ScriptTest/Game.h b/Examples/ScriptTest/Game.h index 07d83709f..d5347e8a0 100644 --- a/Examples/ScriptTest/Game.h +++ b/Examples/ScriptTest/Game.h @@ -50,8 +50,6 @@ private: SharedPtr<Engine> mEngine; SharedPtr<ResourceCache> mCache; SharedPtr<ScriptFile> mScriptFile; - asIScriptFunction* mInitFunction; - asIScriptFunction* mRunFrameFunction; }; #endif // GAME_H