Browse Source

Added ScriptTest example, which will be a script-based (partial) reimplementation of NinjaSnowWar.
Script interface bugfixes.

Lasse Öörni 15 years ago
parent
commit
19d0ed0e45

+ 38 - 0
Bin/Data/Scripts/Ninja.as

@@ -0,0 +1,38 @@
+class Ninja
+{
+    void start()
+    {
+        subscribeToEvent("Create", "handleCreate");
+    }
+
+    void handleCreate(StringHash eventType, VariantMap& eventData)
+    {
+        Vector3 pos = eventData["Pos"].getVector3();
+        Quaternion rot = eventData["Rot"].getQuaternion();
+        
+        // Create model
+        AnimatedModel@ model = entity.createComponent("AnimatedModel");
+        model.setModel(cache.getResource("Model", "Models/Ninja.mdl"));
+        model.setMaterial(cache.getResource("Material", "Materials/Ninja.xml"));
+        model.setDrawDistance(15000);
+        model.setCastShadows(true);
+
+        // Create animation controller
+        AnimationController@ controller = entity.createComponent("AnimationController");
+        controller.setAnimatedModel(model);
+
+        // Create body
+        RigidBody@ body = entity.createComponent("RigidBody");
+        body.setPosition(pos);
+        body.setRotation(rot);
+        body.setMode(PHYS_STATIC);
+        body.setMass(80);
+        body.setFriction(0.5);
+        body.setCollisionShape(cache.getResource("CollisionShape", "Physics/Ninja.xml"));
+        body.setCollisionGroup(1);
+        body.setCollisionMask(3);
+        body.setAngularMaxVelocity(0);
+        body.addChild(model);
+        model.setPosition(Vector3(0, -90, 0));
+    }
+}

+ 57 - 8
Bin/Data/Scripts/NinjaSnowWar.as

@@ -1,15 +1,64 @@
+Scene@ gameScene;
+Camera@ gameCamera;
+
+void init(Scene@ scene)
+{
+    @gameScene = @scene;
+
+    initAudio();
+    loadScene();
+    createCamera();
+    spawnPlayer();
+
+    engine.createDebugHud();
+    debugHud.setFont(cache.getResource("Font", "cour.ttf"), 12);
+
+    registerLocalOnlyEvent("Create");
+    subscribeToEvent("Update", "handleUpdate");
+}
+
 void initAudio()
 void initAudio()
 {
 {
-    // Do a very basic test of scripting functionality by setting up sound & music in script
-    
     // Lower mastervolumes slightly
     // Lower mastervolumes slightly
     audio.setMasterGain(CHANNEL_MASTER, 0.75f);
     audio.setMasterGain(CHANNEL_MASTER, 0.75f);
     audio.setMasterGain(CHANNEL_MUSIC, 0.75f);
     audio.setMasterGain(CHANNEL_MUSIC, 0.75f);
 
 
-    // Play music only in singleplayer, otherwise there will be cacophony if testing on same machine
-    if ((!isServer()) && (!isClient()))
-    {
-        Song@ song = cache.getResource("XM", "Music/NinjaGods.xm");
-        song.play(0);
-    }
+    // Start music playback
+    Song@ song = cache.getResource("XM", "Music/NinjaGods.xm");
+    song.play(0);
+}
+
+void loadScene()
+{
+    File@ levelFile = cache.getFile("TestLevel.xml");
+    gameScene.loadXML(levelFile);
+}
+
+void createCamera()
+{
+    Entity@ cameraEntity = gameScene.createEntity("Camera");
+    @gameCamera = cameraEntity.createComponent("Camera");
+    gameCamera.setAspectRatio(float(renderer.getWidth()) / float(renderer.getHeight()));
+    gameCamera.setNearClip(10.0);
+    gameCamera.setFarClip(16000.0);
+    gameCamera.setPosition(Vector3(0, 200, -1000));
+}
+
+void spawnPlayer()
+{
+    Entity@ playerEntity = gameScene.createEntity("ObjPlayer");
+    ScriptInstance@ instance = playerEntity.createComponent("ScriptInstance");
+    instance.setScriptClass(cache.getResource("ScriptFile", "Scripts/Ninja.as"), "Ninja");
+
+    // To work properly, the script object's methods must be executed in its own context. Therefore we don't (and can't) directly access the script object
+    VariantMap eventData;
+    eventData["Pos"] = Vector3(0, 90, 0);
+    eventData["Rot"] = Quaternion();
+    sendEvent(instance, "Create", eventData);
+}
+
+void handleUpdate(StringHash eventType, VariantMap& eventData)
+{
+    if (input.getKeyPress(KEY_F1))
+        debugHud.toggleAll();
 }
 }

+ 1 - 0
CMakeLists.txt

@@ -119,6 +119,7 @@ add_subdirectory (Engine/Script)
 add_subdirectory (Engine/UI)
 add_subdirectory (Engine/UI)
 add_subdirectory (Examples/NetworkTest)
 add_subdirectory (Examples/NetworkTest)
 add_subdirectory (Examples/NinjaSnowWar)
 add_subdirectory (Examples/NinjaSnowWar)
+add_subdirectory (Examples/ScriptTest)
 add_subdirectory (Examples/Test)
 add_subdirectory (Examples/Test)
 add_subdirectory (SourceAssets/Models)
 add_subdirectory (SourceAssets/Models)
 add_subdirectory (SourceAssets/Shaders)
 add_subdirectory (SourceAssets/Shaders)

+ 4 - 3
Engine/Engine/RegisterEngine.cpp

@@ -138,6 +138,7 @@ static void registerConnection(asIScriptEngine* engine)
     engine->RegisterGlobalFunction("void sendRemoteEvent(Entity@+, const string& in, const VariantMap& in)", asFUNCTION(SendRemoteEntityEventToAll), asCALL_CDECL);
     engine->RegisterGlobalFunction("void sendRemoteEvent(Entity@+, const string& in, const VariantMap& in)", asFUNCTION(SendRemoteEntityEventToAll), asCALL_CDECL);
     engine->RegisterGlobalFunction("void sendRemoteEvent(Entity@+, const string& in, const VariantMap& in, Connection@+)", asFUNCTION(SendRemoteEntityEvent), asCALL_CDECL);
     engine->RegisterGlobalFunction("void sendRemoteEvent(Entity@+, const string& in, const VariantMap& in, Connection@+)", asFUNCTION(SendRemoteEntityEvent), asCALL_CDECL);
     engine->RegisterGlobalFunction("void sendRemoteEvent(Entity@+, const string& in, const VariantMap& in, Connection@+, float, uint16)", asFUNCTION(SendRemoteEntityEventDelayTTL), asCALL_CDECL);
     engine->RegisterGlobalFunction("void sendRemoteEvent(Entity@+, const string& in, const VariantMap& in, Connection@+, float, uint16)", asFUNCTION(SendRemoteEntityEventDelayTTL), asCALL_CDECL);
+    engine->RegisterGlobalFunction("void registerLocalOnlyEvent(const string& in)", asFUNCTIONPR(registerLocalOnlyEvent, (const std::string&), void), asCALL_CDECL);
     engine->RegisterGlobalFunction("Connection@+ getRemoteEventSender()", asFUNCTION(getRemoteEventSender), asCALL_CDECL);
     engine->RegisterGlobalFunction("Connection@+ getRemoteEventSender()", asFUNCTION(getRemoteEventSender), asCALL_CDECL);
 }
 }
 
 
@@ -389,9 +390,9 @@ static void registerEngine(asIScriptEngine* engine)
     engine->RegisterObjectBehaviour("Engine", asBEHAVE_ADDREF, "void f()", asMETHOD(Engine, addRef), asCALL_THISCALL);
     engine->RegisterObjectBehaviour("Engine", asBEHAVE_ADDREF, "void f()", asMETHOD(Engine, addRef), asCALL_THISCALL);
     engine->RegisterObjectBehaviour("Engine", asBEHAVE_RELEASE, "void f()", asMETHOD(Engine, releaseRef), asCALL_THISCALL);
     engine->RegisterObjectBehaviour("Engine", asBEHAVE_RELEASE, "void f()", asMETHOD(Engine, releaseRef), asCALL_THISCALL);
     engine->RegisterObjectMethod("Engine", "Scene@ createScene(const string& in, const BoundingBox& in, uint, bool)", asFUNCTION(EngineCreateScene), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Engine", "Scene@ createScene(const string& in, const BoundingBox& in, uint, bool)", asFUNCTION(EngineCreateScene), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectMethod("Engine", "Client@ createClient(const string& in)", asMETHOD(Engine, createClient), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Engine", "Server@ createServer()", asMETHOD(Engine, createServer), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Engine", "DebugHud@ createDebugHud()", asMETHOD(Engine, createDebugHud), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Engine", "Client@+ createClient(const string& in)", asMETHOD(Engine, createClient), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Engine", "Server@+ createServer()", asMETHOD(Engine, createServer), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Engine", "DebugHud@+ createDebugHud()", asMETHOD(Engine, createDebugHud), asCALL_THISCALL);
     engine->RegisterObjectMethod("Engine", "void removeClient()", asMETHOD(Engine, removeClient), asCALL_THISCALL);
     engine->RegisterObjectMethod("Engine", "void removeClient()", asMETHOD(Engine, removeClient), asCALL_THISCALL);
     engine->RegisterObjectMethod("Engine", "void removeServer()", asMETHOD(Engine, removeServer), asCALL_THISCALL);
     engine->RegisterObjectMethod("Engine", "void removeServer()", asMETHOD(Engine, removeServer), asCALL_THISCALL);
     engine->RegisterObjectMethod("Engine", "void setMinFps(int)", asMETHOD(Engine, setMinFps), asCALL_THISCALL);
     engine->RegisterObjectMethod("Engine", "void setMinFps(int)", asMETHOD(Engine, setMinFps), asCALL_THISCALL);

+ 1 - 0
Engine/Engine/RegisterPhysics.cpp

@@ -187,6 +187,7 @@ static void registerRigidBody(asIScriptEngine* engine)
     engine->RegisterObjectMethod("RigidBody", "void setAngularVelocity(const Vector3& in)", asMETHOD(RigidBody, setAngularVelocity), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void setAngularVelocity(const Vector3& in)", asMETHOD(RigidBody, setAngularVelocity), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void setAngularRestThreshold(float)", asMETHOD(RigidBody, setAngularRestThreshold), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void setAngularRestThreshold(float)", asMETHOD(RigidBody, setAngularRestThreshold), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void setAngularDamping(float, float)", asMETHOD(RigidBody, setAngularDamping), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void setAngularDamping(float, float)", asMETHOD(RigidBody, setAngularDamping), asCALL_THISCALL);
+    engine->RegisterObjectMethod("RigidBody", "void setAngularMaxVelocity(float)", asMETHOD(RigidBody, setAngularMaxVelocity), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void setActive(bool)", asMETHOD(RigidBody, setActive), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void setActive(bool)", asMETHOD(RigidBody, setActive), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void applyForce(const Vector3& in)", asMETHOD(RigidBody, applyForce), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void applyForce(const Vector3& in)", asMETHOD(RigidBody, applyForce), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void applyForceAtPosition(const Vector3& in, const Vector3& in)", asMETHOD(RigidBody, applyForceAtPosition), asCALL_THISCALL);
     engine->RegisterObjectMethod("RigidBody", "void applyForceAtPosition(const Vector3& in, const Vector3& in)", asMETHOD(RigidBody, applyForceAtPosition), asCALL_THISCALL);

+ 2 - 2
Engine/Script/ScriptFile.cpp

@@ -142,6 +142,7 @@ bool ScriptFile::execute(asIScriptFunction* function, asIScriptContext* context,
     {
     {
         if (context->Prepare(function->GetId()) < 0)
         if (context->Prepare(function->GetId()) < 0)
             return false;
             return false;
+        lastScriptFile = this;
         setParameters(context, function, parameters);
         setParameters(context, function, parameters);
         return context->Execute() >= 0;
         return context->Execute() >= 0;
     }
     }
@@ -164,6 +165,7 @@ bool ScriptFile::execute(asIScriptFunction* function, asIScriptContext* context,
             tempContext->Release();
             tempContext->Release();
             return false;
             return false;
         }
         }
+        lastScriptFile = this;
         setParameters(tempContext, function, parameters);
         setParameters(tempContext, function, parameters);
         
         
         ++executeNestingLevel;
         ++executeNestingLevel;
@@ -403,8 +405,6 @@ void ScriptFile::addScriptSection(asIScriptEngine* engine, Deserializer& source,
 
 
 void ScriptFile::setParameters(asIScriptContext* context, asIScriptFunction* function, const std::vector<Variant>& parameters)
 void ScriptFile::setParameters(asIScriptContext* context, asIScriptFunction* function, const std::vector<Variant>& parameters)
 {
 {
-    lastScriptFile = this;
-    
     unsigned paramCount = function->GetParamCount();
     unsigned paramCount = function->GetParamCount();
     for (unsigned i = 0; (i < parameters.size()) && (i < paramCount); ++i)
     for (unsigned i = 0; (i < parameters.size()) && (i < paramCount); ++i)
     {
     {

+ 8 - 4
Engine/Script/ScriptFile.h

@@ -57,13 +57,17 @@ public:
     virtual void addEventHandler(StringHash eventType, const std::string& handlerName);
     virtual void addEventHandler(StringHash eventType, const std::string& handlerName);
     
     
     //! Query for a function by declaration and execute if found. If context is null, use the immediate context
     //! Query for a function by declaration and execute if found. If context is null, use the immediate context
-    bool execute(const std::string& declaration, asIScriptContext* context = 0, const std::vector<Variant>& parameters = std::vector<Variant>());
+    bool execute(const std::string& declaration, asIScriptContext* context = 0, const std::vector<Variant>& parameters =
+        std::vector<Variant>());
     //! Execute a function. If context is null, use the immediate context
     //! Execute a function. If context is null, use the immediate context
-    bool execute(asIScriptFunction* function, asIScriptContext* context = 0, const std::vector<Variant>& parameters = std::vector<Variant>());
+    bool execute(asIScriptFunction* function, asIScriptContext* context = 0, const std::vector<Variant>& parameters =
+        std::vector<Variant>());
     //! Query for an object method by declaration and execute if found. If context is null, use the immediate context
     //! Query for an object method by declaration and execute if found. If context is null, use the immediate context
-    bool execute(asIScriptObject* object, const std::string& declaration, asIScriptContext* context = 0, const std::vector<Variant>& parameters = std::vector<Variant>());
+    bool execute(asIScriptObject* object, const std::string& declaration, asIScriptContext* context = 0, const std::vector<Variant>&
+        parameters = std::vector<Variant>());
     //! Execute an object method. If context is null, use the immediate context
     //! Execute an object method. If context is null, use the immediate context
-    bool execute(asIScriptObject* object, asIScriptFunction* method, asIScriptContext* context = 0, const std::vector<Variant>& parameters = std::vector<Variant>());
+    bool execute(asIScriptObject* object, asIScriptFunction* method, asIScriptContext* context = 0, const std::vector<Variant>&
+        parameters = std::vector<Variant>());
     //! Create a script object. If context is null, use the immediate context
     //! Create a script object. If context is null, use the immediate context
     asIScriptObject* createObject(const std::string& className, asIScriptContext* context = 0);
     asIScriptObject* createObject(const std::string& className, asIScriptContext* context = 0);
     
     

+ 1 - 1
Engine/Script/ScriptInstance.h

@@ -99,7 +99,7 @@ public:
     bool setScriptClass(ScriptFile* scriptFile, const std::string& className);
     bool setScriptClass(ScriptFile* scriptFile, const std::string& className);
     //! Enable or disable scripted updates and event handlers
     //! Enable or disable scripted updates and event handlers
     void setEnabled(bool enable);
     void setEnabled(bool enable);
-    //! Query for a method by declaration and execute if foud
+    //! Query for a method by declaration and execute if found
     bool execute(const std::string& declaration, const std::vector<Variant>& parameters = std::vector<Variant>());
     bool execute(const std::string& declaration, const std::vector<Variant>& parameters = std::vector<Variant>());
     //! Execute a method
     //! Execute a method
     bool execute(asIScriptFunction* method, const std::vector<Variant>& parameters = std::vector<Variant>());
     bool execute(asIScriptFunction* method, const std::vector<Variant>& parameters = std::vector<Variant>());

+ 3 - 3
Engine/UI/MenuItem.h

@@ -47,16 +47,16 @@ class MenuItem : public Button
     
     
     //! Set popup element to show on selection
     //! Set popup element to show on selection
     void setPopup(UIElement* element);
     void setPopup(UIElement* element);
-    //! Set popup offset when showing it
+    //! Set popup element offset
     void setPopupOffset(const IntVector2& offset);
     void setPopupOffset(const IntVector2& offset);
-    //! Set popup offset when showing it
+    //! Set popup element offset
     void setPopupOffset(int x, int y);
     void setPopupOffset(int x, int y);
     //! Force the popup to show or hide
     //! Force the popup to show or hide
     void showPopup(bool enable);
     void showPopup(bool enable);
     
     
     //! Return popup element
     //! Return popup element
     UIElement* getPopup() const { return mPopup; }
     UIElement* getPopup() const { return mPopup; }
-    //! Return popup offset
+    //! Return popup element offset
     const IntVector2& getPopupOffset() const { return mPopupOffset; }
     const IntVector2& getPopupOffset() const { return mPopupOffset; }
     //! Return whether popup is open
     //! Return whether popup is open
     bool getShowPopup() const { return mShowPopup; }
     bool getShowPopup() const { return mShowPopup; }

+ 2 - 3
Examples/NinjaSnowWar/CMakeLists.txt

@@ -10,14 +10,13 @@ set (SOURCE_FILES ${CPP_FILES} ${H_FILES})
 include_directories (
 include_directories (
     ../../Engine/Audio ../../Engine/Common ../../Engine/Engine ../../Engine/Event ../../Engine/Input
     ../../Engine/Audio ../../Engine/Common ../../Engine/Engine ../../Engine/Event ../../Engine/Input
     ../../Engine/Math ../../Engine/Network ../../Engine/Physics ../../Engine/Renderer ../../Engine/Resource
     ../../Engine/Math ../../Engine/Network ../../Engine/Physics ../../Engine/Renderer ../../Engine/Resource
-    ../../Engine/Scene ../../Engine/Script ../../Engine/UI ../../ThirdParty/AngelScript/include
-    ../../ThirdParty/TinyXML
+    ../../Engine/Scene ../../Engine/Script ../../Engine/UI ../../ThirdParty/TinyXML
 )
 )
 
 
 # Define target & libraries to link
 # Define target & libraries to link
 add_executable (${TARGET_NAME} WIN32 ${SOURCE_FILES})
 add_executable (${TARGET_NAME} WIN32 ${SOURCE_FILES})
 set_target_properties (${TARGET_NAME} PROPERTIES DEBUG_POSTFIX _d)
 set_target_properties (${TARGET_NAME} PROPERTIES DEBUG_POSTFIX _d)
 target_link_libraries (${TARGET_NAME} Audio Common Engine Event Input Math Network Physics Renderer
 target_link_libraries (${TARGET_NAME} Audio Common Engine Event Input Math Network Physics Renderer
-    Resource Scene Script TinyXML UI)
+    Resource Scene TinyXML UI)
 enable_pch ()
 enable_pch ()
 finalize_exe ()
 finalize_exe ()

+ 9 - 4
Examples/NinjaSnowWar/Game.cpp

@@ -197,7 +197,6 @@ void Game::init()
     
     
     // Run server in headless mode
     // Run server in headless mode
     mEngine = new Engine(logName, runServer);
     mEngine = new Engine(logName, runServer);
-    mEngine->createScriptEngine();
     if (runServer)
     if (runServer)
         openConsoleWindow();
         openConsoleWindow();
     
     
@@ -235,9 +234,15 @@ void Game::init()
     if (runClient)
     if (runClient)
         mClient = mEngine->createClient(downloadDir);
         mClient = mEngine->createClient(downloadDir);
     
     
-    // Execute sound setup in script to verify that the script interface works
-    ScriptFile* script = mCache->getResource<ScriptFile>("Scripts/NinjaSnowWar.as");
-    script->execute("void initAudio()");
+    // Setup sound. Play music in singleplayer only
+    Audio* audio = mEngine->getAudio();
+    audio->setMasterGain(CHANNEL_MASTER, 0.75f);
+    audio->setMasterGain(CHANNEL_MUSIC, 0.75f);
+    if ((!runServer) && (!runClient))
+    {
+        XM* song = mCache->getResource<XM>("Music/NinjaGods.xm");
+        song->play();
+    }
     
     
     setupOptions();
     setupOptions();
     createOverlays();
     createOverlays();

+ 0 - 1
Examples/NinjaSnowWar/Game.h

@@ -126,7 +126,6 @@ private:
     SharedPtr<Text> mScoreText;
     SharedPtr<Text> mScoreText;
     SharedPtr<Text> mHiScoreText;
     SharedPtr<Text> mHiScoreText;
     SharedPtr<Text> mMessage;
     SharedPtr<Text> mMessage;
-    SharedPtr<Song> mSong;
     
     
     std::vector<Player> mPlayers;
     std::vector<Player> mPlayers;
     std::vector<HiScore> mHiScores;
     std::vector<HiScore> mHiScores;

+ 21 - 0
Examples/ScriptTest/CMakeLists.txt

@@ -0,0 +1,21 @@
+# Define target name
+set (TARGET_NAME ScriptTest)
+
+# Define source files
+file (GLOB CPP_FILES *.cpp)
+file (GLOB H_FILES *.h)
+set (SOURCE_FILES ${CPP_FILES} ${H_FILES})
+
+# Include directories
+include_directories (
+    ../../Engine/Audio ../../Engine/Common ../../Engine/Engine ../../Engine/Event ../../Engine/Input
+    ../../Engine/Math ../../Engine/Network ../../Engine/Physics ../../Engine/Renderer ../../Engine/Resource
+    ../../Engine/Scene ../../Engine/Script ../../Engine/UI ../../ThirdParty/AngelScript/include
+)
+
+# Define target & libraries to link
+add_executable (${TARGET_NAME} WIN32 ${SOURCE_FILES})
+set_target_properties (${TARGET_NAME} PROPERTIES DEBUG_POSTFIX _d)
+target_link_libraries (${TARGET_NAME} Audio Common Engine Event Input Math Network Physics Renderer
+    Resource Scene Script UI)
+finalize_exe ()

+ 167 - 0
Examples/ScriptTest/Game.cpp

@@ -0,0 +1,167 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2011 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Camera.h"
+#include "Engine.h"
+#include "Font.h"
+#include "Game.h"
+#include "Geometry.h"
+#include "IndexBuffer.h"
+#include "Input.h"
+#include "Log.h"
+#include "Model.h"
+#include "PackageFile.h"
+#include "Pipeline.h"
+#include "ProcessUtils.h"
+#include "Profiler.h"
+#include "Renderer.h"
+#include "ResourceCache.h"
+#include "Scene.h"
+#include "ScriptEngine.h"
+#include "ScriptFile.h"
+#include "StringUtils.h"
+#include "VertexBuffer.h"
+
+#include <angelscript.h>
+
+#include "DebugNew.h"
+
+Game::Game(const std::vector<std::string>& arguments) :
+    mArguments(arguments),
+    mPaused(false)
+{
+    std::string userDir = getUserDocumentsDirectory();
+    std::string applicationDir = userDir + "ScriptTest";
+    
+    // Test the "allowed path" feature. Access outside the working directory, and these paths, should cause an exception
+    registerDirectory("Data");
+    registerDirectory(getSystemFontDirectory());
+    registerDirectory(applicationDir);
+    
+    createDirectory(applicationDir);
+}
+
+Game::~Game()
+{
+}
+
+void Game::run()
+{
+    init();
+    
+    while (!mEngine->isExiting())
+    {
+        Entity* cameraEntity = mScene->getEntity("Camera");
+        Camera* camera = 0;
+        if (cameraEntity)
+            camera = cameraEntity->getComponent<Camera>();
+        
+        mEngine->runFrame(mScene, camera, !mPaused);
+        
+        Input* input = mEngine->getInput();
+        if (input->getKeyPress(KEY_ESCAPE))
+            mEngine->exit();
+    }
+}
+
+void Game::init()
+{
+    PROFILE(Game_Init);
+    
+    std::string logName = "ScriptTest.log";
+    
+    mEngine = new Engine(logName);
+    
+    // Add the resources as a package if available
+    mCache = mEngine->getResourceCache();
+    if (fileExists("Data.pak"))
+        mCache->addPackageFile(new PackageFile("Data.pak"));
+    
+    // Force forward rendering
+    mArguments.insert(mArguments.begin(), "-forward");
+    
+    mEngine->init("ScriptTest", mArguments);
+    mEngine->createScriptEngine();
+    // Register the pause variable for script access
+    mEngine->getScriptEngine()->getAngelScriptEngine()->RegisterGlobalProperty("bool paused", &mPaused);
+    
+    mCache->addResourcePath(getSystemFontDirectory());
+    
+    Pipeline* pipeline = mEngine->getPipeline();
+    for (unsigned i = 0; i < mArguments.size(); ++i)
+    {
+        if ((pipeline) && (toLower(mArguments[i]) == "-noshadows"))
+            pipeline->setDrawShadows(false);
+        if (toLower(mArguments[i]) == "-nolimit")
+            mEngine->setMaxFps(0);
+    }
+    
+    createSkyPlaneModel();
+    
+    mScene = mEngine->createScene("ScriptTest", BoundingBox(-100000.0f, 100000.f));
+    
+    // Execute the rest of initialization in script
+    ScriptFile* script = mCache->getResource<ScriptFile>("Scripts/NinjaSnowWar.as");
+    std::vector<Variant> arguments;
+    arguments.push_back(Variant((void*)mScene.getPtr()));
+    script->execute("void init(Scene@)", 0, arguments);
+}
+
+void Game::createSkyPlaneModel()
+{
+    const float skyplanevertices[] = 
+    {
+        -1, 0, -1, 0, 0,
+        1, 0, -1, 2, 0,
+        1, 0, 1, 2, 2,
+        -1, 0, 1, 0, 2
+    };
+    const unsigned short skyplaneindices[] =
+    {
+        0, 1, 3,
+        1, 2, 3
+    };
+    
+    Renderer* renderer = mEngine->getRenderer();
+    
+    SharedPtr<VertexBuffer> vb(new VertexBuffer(renderer));
+    vb->setSize(4, MASK_POSITION | MASK_TEXCOORD1);
+    vb->setData(skyplanevertices);
+    
+    SharedPtr<IndexBuffer> ib(new IndexBuffer(renderer));
+    ib->setSize(6, false);
+    ib->setData(skyplaneindices);
+    
+    SharedPtr<Geometry> geom(new Geometry());
+    geom->setVertexBuffer(0, vb);
+    geom->setIndexBuffer(ib);
+    geom->setDrawRange(TRIANGLE_LIST, 0, ib->getIndexCount());
+    
+    SharedPtr<Model> model(new Model(renderer, "Models/CloudPlane.mdl"));
+    model->setNumGeometries(1);
+    model->setNumGeometryLodLevels(0, 1);
+    model->setGeometry(0, 0, geom);
+    model->setBoundingBox(BoundingBox(-1, 1));
+    // Add the cloudplane model as a manual resource so it can be retrieved during savegame load
+    mCache->addManualResource(model);
+}

+ 54 - 0
Examples/ScriptTest/Game.h

@@ -0,0 +1,54 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2011 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#ifndef GAME_H
+#define GAME_H
+
+#include "EventListener.h"
+#include "SharedPtr.h"
+
+class Engine;
+class ResourceCache;
+class Scene;
+
+class Game : public EventListener
+{
+public:
+    Game(const std::vector<std::string>& arguments);
+    ~Game();
+    
+    void run();
+    
+private:
+    void init();
+    void createSkyPlaneModel();
+    
+    std::vector<std::string> mArguments;
+    
+    SharedPtr<Engine> mEngine;
+    SharedPtr<ResourceCache> mCache;
+    SharedPtr<Scene> mScene;
+    bool mPaused;
+};
+
+#endif // GAME_H

+ 73 - 0
Examples/ScriptTest/Main.cpp

@@ -0,0 +1,73 @@
+//
+// Urho3D Engine
+// Copyright (c) 2008-2011 Lasse Öörni
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Exception.h"
+#include "Game.h"
+#include "ProcessUtils.h"
+
+#include <windows.h>
+
+#include "DebugNew.h"
+
+void run(const char* cmdLine);
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
+{
+    #if defined(_MSC_VER) && defined(_DEBUG)
+    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+    #endif
+    
+    #if defined(ENABLE_MINIDUMPS) && !defined(_DEBUG)
+    __try
+    {
+        run(cmdLine);
+    }
+    __except(writeMiniDump("NinjaSnowWarScript", GetExceptionInformation())) {}
+    #else
+    run(cmdLine);
+    #endif
+    
+    return 0;
+}
+
+void run(const char* cmdLine)
+{
+    std::vector<std::string> arguments;
+    getArguments(cmdLine, arguments);
+    setExecutableWorkingDirectory();
+    
+    #if !defined(_MSC_VER) || !defined(_DEBUG)
+    try
+    {
+        Game game(arguments);
+        game.run();
+    }
+    catch (Exception& e)
+    {
+        errorDialog("NinjaSnowWarScript", e.whatStr());
+    }
+    #else
+    Game game(arguments);
+    game.run();
+    #endif
+}

+ 3 - 0
Examples/ScriptTest/Readme.txt

@@ -0,0 +1,3 @@
+A work-in-progress reimplmentation of NinjaSnowWar using AngelScript for the
+majority of code.
+

+ 3 - 3
Examples/Test/Application.cpp

@@ -204,9 +204,9 @@ void Application::init()
     cursor->setPosition(renderer->getWidth() / 2, renderer->getHeight() / 2);
     cursor->setPosition(renderer->getWidth() / 2, renderer->getHeight() / 2);
     ui->setCursor(cursor);
     ui->setCursor(cursor);
     
     
-    XMLFile* uiLayout = mCache->getResource<XMLFile>("UI/TestLayout.xml");
-    SharedPtr<UIElement> layoutElement = ui->loadLayout(uiLayout, uiStyle);
-    uiRoot->addChild(layoutElement);
+    //XMLFile* uiLayout = mCache->getResource<XMLFile>("UI/TestLayout.xml");
+    //SharedPtr<UIElement> layoutElement = ui->loadLayout(uiLayout, uiStyle);
+    //uiRoot->addChild(layoutElement);
     
     
     mScene = mEngine->createScene();
     mScene = mEngine->createScene();
     PhysicsWorld* world = mScene->getExtension<PhysicsWorld>();
     PhysicsWorld* world = mScene->getExtension<PhysicsWorld>();