Move the AngelScript API registration to the Script library and inverted the Script <-> Engine library dependency.

Move object factory registration into the subsystems where possible.
This commit is contained in:
Lasse Öörni 2013-06-26 00:09:02 +00:00
Родитель ee668a791f
Коммит 1fdf228359
36 изменённых файлов: 145 добавлений и 88 удалений

Просмотреть файл

@ -302,13 +302,11 @@ The libraries are the following:
- Physics. Provides physics simulation.
- Navigation. Provides navigation mesh generation and pathfinding.
- %Script. Provides scripting support using the AngelScript language.
- %Engine. Instantiates the subsystems from the libraries above, and manages the main loop iteration.
- %Engine. Instantiates the subsystems from the libraries above and manages the main loop iteration.
Urho3D.exe uses the Engine & Script libraries to start up the subsystems and to load the script file specified on the command line; however all of the libraries above get automatically linked as Engine library depends on all of them.
Urho3D.exe uses the Engine & Script libraries to start up the subsystems and to load the script file specified on the command line. It is also possible to use the engine through C++ only: when the scripting library is not used, the resulting executable will be significantly smaller.
Although Urho3D.exe itself is geared towards running a scripted application, it is also possible to use the engine through C++ only. When the scripting subsystem initialization is completely skipped, the resulting executable will also be significantly smaller.
The third-party libraries are used for the following functionality:
Third-party libraries are used for the following functionality:
- AngelScript: scripting language implementation
- Bullet: physics simulation implementation

Просмотреть файл

@ -66,7 +66,7 @@ The following subsystems are optional, so GetSubsystem() may return null if they
- Profiler: Provides hierarchical function execution time measurement using the operating system performance counter. Exists if profiling has been compiled in (configurable from the root CMakeLists.txt)
- Graphics: Manages the application window, the rendering context and resources. Exists if not in headless mode.
- Renderer: Renders scenes in 3D and manages rendering quality settings. Exists if not in headless mode.
- Script: Provides the AngelScript execution environment. Created by calling \ref Engine::InitializeScripting "InitializeScripting()".
- Script: Provides the AngelScript execution environment. Needs to be created and registered manually.
- Console: provides an interactive AngelScript console and log display. Created by calling \ref Engine::CreateConsole "CreateConsole()".
- DebugHud: displays rendering mode information and statistics and profiling data. Created by calling \ref Engine::CreateDebugHud "CreateDebugHud()".
@ -86,7 +86,7 @@ When subscribing to an event, a handler function must be specified. In C++ these
SubscribeToEvent(E_UPDATE, HANDLER(MyClass, MyEventHandler));
\endcode
In script events are identified by their string names instead of name hashes (though these are internally converted to hashes.) Script event handlers can either have the same signature as in C++, or a simplified signature void HandleEvent() when event type and parameters are not required. The same event subscription would look like:
In script events are identified by their string names instead of name hashes (though these are internally converted to hashes.) %Script event handlers can either have the same signature as in C++, or a simplified signature void HandleEvent() when event type and parameters are not required. The same event subscription would look like:
\code
SubscribeToEvent("Update", "MyEventHandler");
@ -286,6 +286,12 @@ Memory budgets can be set per resource type: if resources consume more memory th
\page Scripting Scripting
To enable AngelScript scripting support, the Script subsystem needs to be created and registered after initializing the Engine. This is accomplished by the following code, seen eg. in Urho3D/Urho3D.cpp:
\code
context_->RegisterSubsystem(new Script(context_));
\endcode
There are three ways the AngelScript language can be interacted with in Urho3D:
\section Scripting_Immediate Immediate execution

Просмотреть файл

@ -55,10 +55,13 @@ Audio::Audio(Context* context) :
sampleSize_(0),
playing_(false)
{
SubscribeToEvent(E_RENDERUPDATE, HANDLER(Audio, HandleRenderUpdate));
for (unsigned i = 0; i < MAX_SOUND_TYPES; ++i)
masterGain_[i] = 1.0f;
// Register Audio library object factories
RegisterAudioLibrary(context_);
SubscribeToEvent(E_RENDERUPDATE, HANDLER(Audio, HandleRenderUpdate));
}
Audio::~Audio()

Просмотреть файл

@ -124,7 +124,7 @@ private:
WeakPtr<SoundListener> listener_;
};
/// Register Sound library objects.
/// Register Audio library objects.
void RegisterAudioLibrary(Context* context);
}

Просмотреть файл

@ -8,8 +8,8 @@ set (SOURCE_FILES ${CPP_FILES} ${H_FILES})
# Define dependency libs
set (LIBS ../Audio ../Container ../Core ../Graphics ../Input ../IO ../Math ../Navigation ../Network ../Physics ../Resource
../Scene ../Script ../UI)
set (INCLUDE_DIRS_ONLY ../../ThirdParty/AngelScript/include ../../ThirdParty/Bullet/src ../../ThirdParty/kNet/include)
../Scene ../UI)
set (INCLUDE_DIRS_ONLY ../../ThirdParty/Bullet/src ../../ThirdParty/kNet/include)
# Setup target
enable_pch ()

Просмотреть файл

@ -23,6 +23,7 @@
#include "Precompiled.h"
#include "Console.h"
#include "Context.h"
#include "EngineEvents.h"
#include "Font.h"
#include "Graphics.h"
#include "GraphicsEvents.h"
@ -31,7 +32,6 @@
#include "LineEdit.h"
#include "Log.h"
#include "ResourceCache.h"
#include "Script.h"
#include "Text.h"
#include "UI.h"
#include "UIEvents.h"
@ -176,9 +176,12 @@ void Console::HandleTextFinished(StringHash eventType, VariantMap& eventData)
String line = lineEdit_->GetText();
if (!line.Empty())
{
Script* script = GetSubsystem<Script>();
if (script)
script->Execute(line);
// Send the command as an event for script subsystem
using namespace ConsoleCommand;
VariantMap eventData;
eventData[P_COMMAND] = line;
SendEvent(E_CONSOLECOMMAND, eventData);
// Store to history, then clear the lineedit
history_.Push(line);

Просмотреть файл

@ -41,8 +41,6 @@
#include "ResourceCache.h"
#include "Scene.h"
#include "SceneEvents.h"
#include "Script.h"
#include "ScriptAPI.h"
#include "StringUtils.h"
#include "UI.h"
#include "WorkQueue.h"
@ -112,8 +110,7 @@ bool Engine::Initialize(const VariantMap& parameters)
// Set headless mode
headless_ = GetParameter(parameters, "Headless", false).GetBool();
// Register object factories and attributes first, then subsystems
RegisterObjects();
// Register subsystems and object factories
RegisterSubsystems();
PROFILE(InitEngine);
@ -249,38 +246,6 @@ bool Engine::Initialize(const VariantMap& parameters)
return true;
}
bool Engine::InitializeScripting()
{
// Check if scripting already initialized
if (GetSubsystem<Script>())
return true;
RegisterScriptLibrary(context_);
context_->RegisterSubsystem(new Script(context_));
{
PROFILE(RegisterScriptAPI);
asIScriptEngine* engine = GetSubsystem<Script>()->GetScriptEngine();
RegisterMathAPI(engine);
RegisterCoreAPI(engine);
RegisterIOAPI(engine);
RegisterResourceAPI(engine);
RegisterSceneAPI(engine);
RegisterGraphicsAPI(engine);
RegisterInputAPI(engine);
RegisterAudioAPI(engine);
RegisterUIAPI(engine);
RegisterNetworkAPI(engine);
RegisterPhysicsAPI(engine);
RegisterNavigationAPI(engine);
RegisterScriptAPI(engine);
RegisterEngineAPI(engine);
}
return true;
}
void Engine::RunFrame()
{
assert(initialized_ && !exiting_);
@ -641,31 +606,12 @@ const Variant& Engine::GetParameter(const VariantMap& parameters, const String&
return i != parameters.End() ? i->second_ : defaultValue;
}
void Engine::RegisterObjects()
{
RegisterResourceLibrary(context_);
RegisterSceneLibrary(context_);
RegisterNetworkLibrary(context_);
RegisterGraphicsLibrary(context_);
RegisterAudioLibrary(context_);
RegisterUILibrary(context_);
RegisterPhysicsLibrary(context_);
RegisterNavigationLibrary(context_);
// In debug mode, check that all factory created objects can be created without crashing
#ifdef _DEBUG
const HashMap<ShortStringHash, SharedPtr<ObjectFactory> >& factories = context_->GetObjectFactories();
for (HashMap<ShortStringHash, SharedPtr<ObjectFactory> >::ConstIterator i = factories.Begin(); i != factories.End(); ++i)
SharedPtr<Object> object = i->second_->CreateObject();
#endif
}
void Engine::RegisterSubsystems()
{
// Register self as a subsystem
context_->RegisterSubsystem(this);
// Create and register the rest of the subsystems
// Create and register the rest of the subsystems. They will register object factories for their own libraries
context_->RegisterSubsystem(new Time(context_));
context_->RegisterSubsystem(new WorkQueue(context_));
#ifdef ENABLE_PROFILING
@ -680,6 +626,12 @@ void Engine::RegisterSubsystems()
context_->RegisterSubsystem(new Graphics(context_));
context_->RegisterSubsystem(new Renderer(context_));
}
else
{
// Register Graphics library object factories also in headless mode; the objects will function without allocating
// actual GPU resources
RegisterGraphicsLibrary(context_);
}
context_->RegisterSubsystem(new Input(context_));
context_->RegisterSubsystem(new UI(context_));
@ -687,6 +639,19 @@ void Engine::RegisterSubsystems()
#ifdef ENABLE_LOGGING
context_->RegisterSubsystem(new Log(context_));
#endif
// Scene, Physics & Navigation libraries do not have a corresponding subsystem which would register their object factories.
// Register manually now
RegisterSceneLibrary(context_);
RegisterPhysicsLibrary(context_);
RegisterNavigationLibrary(context_);
// In debug mode, check that all factory created objects can be created without crashing
#ifdef _DEBUG
const HashMap<ShortStringHash, SharedPtr<ObjectFactory> >& factories = context_->GetObjectFactories();
for (HashMap<ShortStringHash, SharedPtr<ObjectFactory> >::ConstIterator i = factories.Begin(); i != factories.End(); ++i)
SharedPtr<Object> object = i->second_->CreateObject();
#endif
}
}

Просмотреть файл

@ -44,8 +44,6 @@ public:
/// Initialize engine using parameters given and show the application window. Return true if successful.
bool Initialize(const VariantMap& parameters);
/// Initialize script subsystem and register the script API. Return true if successful (engine must be initialized first.)
bool InitializeScripting();
/// Run one frame.
void RunFrame();
/// Create the console and return it. May return null if engine configuration does not allow creation (headless mode.)
@ -99,8 +97,6 @@ public:
static const Variant& GetParameter(const VariantMap& parameters, const String& parameter, const Variant& defaultValue = Variant::EMPTY);
private:
/// Register object factories and attributes.
void RegisterObjects();
/// Create and register subsystems. In headless mode graphics, input & UI are not created.
void RegisterSubsystems();

Просмотреть файл

@ -0,0 +1,36 @@
//
// Copyright (c) 2008-2013 the Urho3D project.
//
// 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.
//
#pragma once
#include "Object.h"
namespace Urho3D
{
/// A command has been entered on the console
EVENT(E_CONSOLECOMMAND, ConsoleCommand)
{
PARAM(P_COMMAND, Command); // String
}
}

Просмотреть файл

@ -208,6 +208,9 @@ Graphics::Graphics(Context* context) :
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE);
++numInstances;
}
// Register Graphics library object factories
RegisterGraphicsLibrary(context_);
}
Graphics::~Graphics()

Просмотреть файл

@ -191,6 +191,9 @@ Graphics::Graphics(Context* context_) :
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_NOPARACHUTE);
++numInstances;
}
// Register Graphics library object factories
RegisterGraphicsLibrary(context_);
}
Graphics::~Graphics()

Просмотреть файл

@ -53,6 +53,9 @@ Network::Network(Context* context) :
{
network_ = new kNet::Network();
// Register Network library object factories
RegisterNetworkLibrary(context_);
SubscribeToEvent(E_BEGINFRAME, HANDLER(Network, HandleBeginFrame));
SubscribeToEvent(E_RENDERUPDATE, HANDLER(Network, HandleRenderUpdate));
}

Просмотреть файл

@ -64,6 +64,8 @@ ResourceCache::ResourceCache(Context* context) :
Object(context),
autoReloadResources_(false)
{
// Register Resource library object factories
RegisterResourceLibrary(context_);
}
ResourceCache::~ResourceCache()

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -7,8 +7,9 @@ file (GLOB H_FILES *.h)
set (SOURCE_FILES ${CPP_FILES} ${H_FILES})
# Define dependency libs
set (LIBS ../Container ../Core ../IO ../Math ../Physics ../Resource ../Scene ../../ThirdParty/AngelScript/include)
set (INCLUDE_DIRS_ONLY ../../ThirdParty/Bullet/src)
set (LIBS ../Audio ../Container ../Core ../Engine ../Graphics ../Input ../IO ../Math ../Navigation ../Network ../Physics
../Resource ../Scene ../UI ../../ThirdParty/AngelScript/include)
set (INCLUDE_DIRS_ONLY ../../ThirdParty/Bullet/src ../../ThirdParty/kNet/include)
# Setup target
enable_pch ()

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -23,10 +23,12 @@
#include "Precompiled.h"
#include "Addons.h"
#include "Context.h"
#include "EngineEvents.h"
#include "Log.h"
#include "Profiler.h"
#include "Scene.h"
#include "Script.h"
#include "ScriptAPI.h"
#include "ScriptFile.h"
#include "ScriptInstance.h"
@ -156,9 +158,31 @@ Script::Script(Context* context) :
immediateContext_ = scriptEngine_->CreateContext();
immediateContext_->SetExceptionCallback(asMETHOD(Script, ExceptionCallback), this, asCALL_THISCALL);
// Register the Array & String types
// Register Script library object factories
RegisterScriptLibrary(context_);
// Register the Array & String API
RegisterArray(scriptEngine_);
RegisterString(scriptEngine_);
// Register the rest of the script API
RegisterMathAPI(scriptEngine_);
RegisterCoreAPI(scriptEngine_);
RegisterIOAPI(scriptEngine_);
RegisterResourceAPI(scriptEngine_);
RegisterSceneAPI(scriptEngine_);
RegisterGraphicsAPI(scriptEngine_);
RegisterInputAPI(scriptEngine_);
RegisterAudioAPI(scriptEngine_);
RegisterUIAPI(scriptEngine_);
RegisterNetworkAPI(scriptEngine_);
RegisterPhysicsAPI(scriptEngine_);
RegisterNavigationAPI(scriptEngine_);
RegisterScriptAPI(scriptEngine_);
RegisterEngineAPI(scriptEngine_);
// Subscribe to console commands
SubscribeToEvent(E_CONSOLECOMMAND, HANDLER(Script, HandleConsoleCommand));
}
Script::~Script()
@ -475,6 +499,13 @@ void Script::OutputAPIRow(const String& row, bool removeReference)
Log::WriteRaw("- " + out + "\n");
}
void Script::HandleConsoleCommand(StringHash eventType, VariantMap& eventData)
{
using namespace ConsoleCommand;
Execute(eventData[P_COMMAND].GetString());
}
void RegisterScriptLibrary(Context* context)
{
ScriptFile::RegisterObject(context);

Просмотреть файл

@ -107,7 +107,9 @@ private:
asIScriptContext* GetScriptFileContext();
/// Output a sanitated row of script API. No-ops when ENABLE_LOGGING not defined.
void OutputAPIRow(const String& row, bool removeReference = false);
/// Handle a console command event.
void HandleConsoleCommand(StringHash eventType, VariantMap& eventData);
/// AngelScript engine.
asIScriptEngine* scriptEngine_;
/// Immediate execution script context.

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -83,7 +83,10 @@ UI::UI(Context* context) :
{
rootElement_->SetTraversalMode(TM_DEPTH_FIRST);
rootModalElement_->SetTraversalMode(TM_DEPTH_FIRST);
// Register UI library object factories
RegisterUILibrary(context_);
SubscribeToEvent(E_SCREENMODE, HANDLER(UI, HandleScreenMode));
SubscribeToEvent(E_MOUSEBUTTONDOWN, HANDLER(UI, HandleMouseButtonDown));
SubscribeToEvent(E_MOUSEBUTTONUP, HANDLER(UI, HandleMouseButtonUp));

Просмотреть файл

@ -207,12 +207,12 @@ void Run(const Vector<String>& arguments)
);
}
RegisterSceneLibrary(context_);
RegisterGraphicsLibrary(context_);
RegisterPhysicsLibrary(context_);
context_->RegisterSubsystem(new FileSystem(context_));
context_->RegisterSubsystem(new ResourceCache(context_));
context_->RegisterSubsystem(new WorkQueue(context_));
RegisterSceneLibrary(context_);
RegisterGraphicsLibrary(context_);
RegisterPhysicsLibrary(context_);
String command = arguments[0].ToLower();
String rootNodeName;

Просмотреть файл

@ -67,7 +67,9 @@ int main(int argc, char** argv)
}
SharedPtr<Context> context(new Context());
SharedPtr<Engine> engine(new Engine(context));
context->RegisterSubsystem(new Script(context));
context->RegisterSubsystem(new FileSystem(context));
context->RegisterSubsystem(new ResourceCache(context));
context->RegisterSubsystem(new Log(context));
@ -76,9 +78,6 @@ int main(int argc, char** argv)
log->SetLevel(LOG_WARNING);
log->SetTimeStamp(false);
if (!engine->InitializeScripting())
ErrorExit("Unable to initialize script engine. The application will now exit.");
if (!dumpApiMode)
{
String path, file, extension;

Просмотреть файл

@ -28,6 +28,7 @@
#include "ProcessUtils.h"
#include "ResourceCache.h"
#include "ResourceEvents.h"
#include "Script.h"
#include "ScriptFile.h"
#include <exception>
@ -133,8 +134,10 @@ int Application::Run()
SharedPtr<Engine> engine(new Engine(context_));
if (engine->Initialize(Engine::ParseParameters(arguments)))
{
// Instantiate and register the script subsystem
context_->RegisterSubsystem(new Script(context_));
// Hold a shared pointer to the script file to make sure it is not unloaded during runtime
engine->InitializeScripting();
SharedPtr<ScriptFile> scriptFile(context_->GetSubsystem<ResourceCache>()->GetResource<ScriptFile>(scriptFileName));
// If script loading is successful, execute engine loop