Work on scripting

This commit is contained in:
Marianne Gagnon 2015-05-17 19:27:25 -04:00
parent e23f854845
commit 080936f144
12 changed files with 495 additions and 270 deletions

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<stkgui>
<div x="2%" y="10%" width="96%" height="80%" layout="vertical-row" >
<label raw_text="Run script"/>
<textbox id="textfield" width="75%" I18N="In the 'add new grand prix' dialog" align="center"/>
<spacer height="20" width="20" />
<div align="center" height="fit" width="100%" layout="horizontal-row">
<button id="run" raw_text="Run" align="center" proportion="1"/>
<spacer height="20" width="20" />
<button id="close" raw_text="Close" align="center" proportion="1"/>
</div>
</div>
</stkgui>

View File

@ -171,7 +171,7 @@ void Physics::update(float dt)
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
int kartid1 = p->getUserPointer(0)->getPointerKart()->getWorldKartId();
int kartid2 = p->getUserPointer(1)->getPointerKart()->getWorldKartId();
script_engine->runScript("void onKartKartCollision(int, int)",
script_engine->runFunction("void onKartKartCollision(int, int)",
[=](asIScriptContext* ctx) {
ctx->SetArgDWord(0, kartid1);
ctx->SetArgDWord(1, kartid2);
@ -189,7 +189,7 @@ void Physics::update(float dt)
std::string obj_id = p->getUserPointer(0)->getPointerPhysicalObject()->getID();
// TODO: pass obj_id as arguent
script_engine->runScript("void onKartObjectCollision(int)",
script_engine->runFunction("void onKartObjectCollision(int)",
[=](asIScriptContext* ctx) {
ctx->SetArgDWord(0, kartId);
});
@ -260,7 +260,7 @@ void Physics::update(float dt)
// p->getUserPointer(1)->getPointerPhysicalObject()->getID(),
// "item"
//);
script_engine->runScript("void onItemObjectCollision()");
script_engine->runFunction("void onItemObjectCollision()");
p->getUserPointer(0)->getPointerFlyable()
->hit(NULL, p->getUserPointer(1)->getPointerPhysicalObject());
PhysicalObject* obj = p->getUserPointer(1)->getPointerPhysicalObject();

View File

@ -38,308 +38,372 @@ using namespace Scripting;
namespace Scripting
{
const char* MODULE_ID_MAIN_SCRIPT_FILE = "main";
const char* MODULE_ID_EVAL = "eval";
void AngelScript_ErrorCallback (const asSMessageInfo *msg, void *param)
{
const char *type = "ERR ";
if (msg->type == asMSGTYPE_WARNING)
type = "WARN";
else if (msg->type == asMSGTYPE_INFORMATION)
type = "INFO";
Log::warn("Scripting", "%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
}
//Constructor, creates a new Scripting Engine using AngelScript
ScriptEngine::ScriptEngine()
{
// Create the script engine
m_engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
if (m_engine == NULL)
void AngelScript_ErrorCallback (const asSMessageInfo *msg, void *param)
{
Log::fatal("Scripting", "Failed to create script engine.");
const char *type = "ERR ";
if (msg->type == asMSGTYPE_WARNING)
type = "WARN";
else if (msg->type == asMSGTYPE_INFORMATION)
type = "INFO";
Log::warn("Scripting", "%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
}
// The script compiler will write any compiler messages to the callback.
m_engine->SetMessageCallback(asFUNCTION(AngelScript_ErrorCallback), 0, asCALL_CDECL);
// Configure the script engine with all the functions,
// and variables that the script should be able to use.
configureEngine(m_engine);
}
ScriptEngine::~ScriptEngine()
{
// Release the engine
m_engine->Release();
}
/** Get Script By it's file name
* \param string scriptname = name of script to get
* \return The corresponding script
*/
std::string getScript(std::string scriptName)
{
std::string script_dir = file_manager->getAsset(FileManager::SCRIPT, "");
script_dir += World::getWorld()->getTrack()->getIdent() + "/";
// TODO: allow splitting in multiple files
script_dir += "scripting.as";
FILE *f = fopen(script_dir.c_str(), "rb");
if (f == NULL)
//Constructor, creates a new Scripting Engine using AngelScript
ScriptEngine::ScriptEngine()
{
Log::debug("Scripting", "File does not exist : {0}.as", scriptName.c_str());
return "";
// Create the script engine
m_engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
if (m_engine == NULL)
{
Log::fatal("Scripting", "Failed to create script engine.");
}
// The script compiler will write any compiler messages to the callback.
m_engine->SetMessageCallback(asFUNCTION(AngelScript_ErrorCallback), 0, asCALL_CDECL);
// Configure the script engine with all the functions,
// and variables that the script should be able to use.
configureEngine(m_engine);
}
// Determine the size of the file
fseek(f, 0, SEEK_END);
int len = ftell(f);
fseek(f, 0, SEEK_SET);
// Read the entire file
std::string script;
script.resize(len);
int c = fread(&script[0], len, 1, f);
fclose(f);
if (c == NULL)
ScriptEngine::~ScriptEngine()
{
Log::error("Scripting", "Failed to load script file.");
return "";
// Release the engine
m_engine->Release();
}
return script;
}
//-----------------------------------------------------------------------------
/** runs the specified script
* \param string scriptName = name of script to run
*/
void ScriptEngine::runScript(std::string scriptName)
{
std::function<void(asIScriptContext*)> callback;
runScript(scriptName, callback);
}
//-----------------------------------------------------------------------------
/** runs the specified script
* \param string scriptName = name of script to run
*/
void ScriptEngine::runScript(std::string scriptName, std::function<void(asIScriptContext*)> callback)
{
int r; //int for error checking
asIScriptFunction *func;
auto cached_script = m_script_cache.find(scriptName);
if (cached_script == m_script_cache.end())
/** Get Script By it's file name
* \param string scriptname = name of script to get
* \return The corresponding script
*/
std::string getScript(std::string fileName)
{
// Compile the script code
Log::debug("Scripting", "Compiling script '%s' (was not in cache)", scriptName.c_str());
r = compileScript(m_engine, scriptName);
std::string script_dir = file_manager->getAsset(FileManager::SCRIPT, "");
script_dir += World::getWorld()->getTrack()->getIdent() + "/";
script_dir += fileName;
FILE *f = fopen(script_dir.c_str(), "rb");
if (f == NULL)
{
Log::debug("Scripting", "File does not exist : {0}.as", fileName.c_str());
return "";
}
// Determine the size of the file
fseek(f, 0, SEEK_END);
int len = ftell(f);
fseek(f, 0, SEEK_SET);
// Read the entire file
std::string script;
script.resize(len);
int c = fread(&script[0], len, 1, f);
fclose(f);
if (c == NULL)
{
Log::error("Scripting", "Failed to load script file.");
return "";
}
return script;
}
//-----------------------------------------------------------------------------
void ScriptEngine::evalScript(std::string script_fragment)
{
script_fragment = "void evalScript_main() { \n" + script_fragment + "\n}";
asIScriptModule* mod = m_engine->GetModule(MODULE_ID_EVAL, asGM_ALWAYS_CREATE);
int r = mod->AddScriptSection("script", &script_fragment[0], script_fragment.size());
if (r < 0)
{
Log::debug("Scripting", "Script '%s' is not available", scriptName.c_str());
m_script_cache[scriptName] = NULL; // remember that this script is unavailable
Log::error("Scripting", "evalScript: AddScriptSection() failed");
return;
}
// Find the function for the function we want to execute.
//This is how you call a normal function with arguments
//asIScriptFunction *func = engine->GetModule(0)->GetFunctionByDecl("void func(arg1Type, arg2Type)");
func = registerScriptCallbacks(m_engine, scriptName);
if (func == NULL)
r = mod->Build();
if (r < 0)
{
Log::debug("Scripting", "Scripting function was not found : %s", scriptName.c_str());
m_script_cache[scriptName] = NULL; // remember that this script is unavailable
Log::error("Scripting", "evalScript: Build() failed");
return;
}
//CACHE UPDATE
m_script_cache[scriptName] = func;
func->AddRef();
}
else
{
// Script present in cache
func = cached_script->second;
}
asIScriptFunction* func = m_engine->GetModule(MODULE_ID_EVAL)
->GetFunctionByDecl("void evalScript_main()");
if (func == NULL)
{
return; // script unavailable
}
asIScriptContext *ctx = m_engine->CreateContext();
if (ctx == NULL)
{
Log::error("Scripting", "evalScript: Failed to create the context.");
//m_engine->Release();
return;
}
r = ctx->Prepare(func);
if (r < 0)
{
Log::error("Scripting", "evalScript: Failed to prepare the context.");
ctx->Release();
return;
}
// Create a context that will execute the script.
asIScriptContext *ctx = m_engine->CreateContext();
if (ctx == NULL)
{
Log::error("Scripting", "Failed to create the context.");
//m_engine->Release();
return;
}
// Execute the function
r = ctx->Execute();
if (r != asEXECUTION_FINISHED)
{
// The execution didn't finish as we had planned. Determine why.
if (r == asEXECUTION_ABORTED)
{
Log::error("Scripting", "The script was aborted before it could finish. Probably it timed out.");
}
else if (r == asEXECUTION_EXCEPTION)
{
Log::error("Scripting", "The script ended with an exception.");
}
else
{
Log::error("Scripting", "The script ended for some unforeseen reason (%i)", r);
}
}
// Prepare the script context with the function we wish to execute. Prepare()
// must be called on the context before each new script function that will be
// executed. Note, that if because we intend to execute the same function
// several times, we will store the function returned by
// GetFunctionByDecl(), so that this relatively slow call can be skipped.
r = ctx->Prepare(func);
if (r < 0)
{
Log::error("Scripting", "Failed to prepare the context.");
ctx->Release();
//m_engine->Release();
return;
}
// Here, we can pass parameters to the script functions.
//ctx->setArgType(index, value);
//for example : ctx->SetArgFloat(0, 3.14159265359f);
//-----------------------------------------------------------------------------
if (callback)
callback(ctx);
// Execute the function
r = ctx->Execute();
if (r != asEXECUTION_FINISHED)
/** runs the specified script
* \param string scriptName = name of script to run
*/
void ScriptEngine::runFunction(std::string function_name)
{
// The execution didn't finish as we had planned. Determine why.
if (r == asEXECUTION_ABORTED)
{
Log::error("Scripting", "The script was aborted before it could finish. Probably it timed out.");
}
else if (r == asEXECUTION_EXCEPTION)
{
Log::error("Scripting", "The script ended with an exception.");
std::function<void(asIScriptContext*)> callback;
runFunction(function_name, callback);
}
// Write some information about the script exception
asIScriptFunction *func = ctx->GetExceptionFunction();
//std::cout << "func: " << func->GetDeclaration() << std::endl;
//std::cout << "modl: " << func->GetModuleName() << std::endl;
//std::cout << "sect: " << func->GetScriptSectionName() << std::endl;
//std::cout << "line: " << ctx->GetExceptionLineNumber() << std::endl;
//std::cout << "desc: " << ctx->GetExceptionString() << std::endl;
//-----------------------------------------------------------------------------
/** runs the specified script
* \param string scriptName = name of script to run
*/
void ScriptEngine::runFunction(std::string function_name, std::function<void(asIScriptContext*)> callback)
{
int r; //int for error checking
asIScriptFunction *func;
// TODO: allow splitting in multiple files
std::string script_filename = "scripting.as";
auto cached_script = m_loaded_files.find(script_filename);
auto cached_function = m_functions_cache.find(function_name);
if (cached_script == m_loaded_files.end())
{
// Compile the script code
Log::debug("Scripting", "Compiling script '%s' (was not in cache)", script_filename.c_str());
r = compileScript(m_engine, script_filename);
if (r < 0)
{
Log::debug("Scripting", "Script '%s' is not available", script_filename.c_str());
m_loaded_files[script_filename] = false;
m_functions_cache[function_name] = NULL; // remember that this script is unavailable
return;
}
m_loaded_files[script_filename] = true;
}
else if (cached_script->second == false)
{
return; // script file unavailable
}
if (cached_function == m_functions_cache.end())
{
// Find the function for the function we want to execute.
// This is how you call a normal function with arguments
// asIScriptFunction *func = engine->GetModule(0)->GetFunctionByDecl("void func(arg1Type, arg2Type)");
func = m_engine->GetModule(MODULE_ID_MAIN_SCRIPT_FILE)
->GetFunctionByDecl(function_name.c_str());
if (func == NULL)
{
Log::debug("Scripting", "Scripting function was not found : %s", function_name.c_str());
m_loaded_files[function_name] = NULL; // remember that this script is unavailable
return;
}
m_functions_cache[function_name] = func;
func->AddRef();
}
else
{
Log::error("Scripting", "The script ended for some unforeseen reason (%i)", r);
// Script present in cache
func = cached_function->second;
}
if (func == NULL)
{
return; // function unavailable
}
// Create a context that will execute the script.
asIScriptContext *ctx = m_engine->CreateContext();
if (ctx == NULL)
{
Log::error("Scripting", "Failed to create the context.");
//m_engine->Release();
return;
}
// Prepare the script context with the function we wish to execute. Prepare()
// must be called on the context before each new script function that will be
// executed. Note, that if because we intend to execute the same function
// several times, we will store the function returned by
// GetFunctionByDecl(), so that this relatively slow call can be skipped.
r = ctx->Prepare(func);
if (r < 0)
{
Log::error("Scripting", "Failed to prepare the context.");
ctx->Release();
//m_engine->Release();
return;
}
// Here, we can pass parameters to the script functions.
//ctx->setArgType(index, value);
//for example : ctx->SetArgFloat(0, 3.14159265359f);
if (callback)
callback(ctx);
// Execute the function
r = ctx->Execute();
if (r != asEXECUTION_FINISHED)
{
// The execution didn't finish as we had planned. Determine why.
if (r == asEXECUTION_ABORTED)
{
Log::error("Scripting", "The script was aborted before it could finish. Probably it timed out.");
}
else if (r == asEXECUTION_EXCEPTION)
{
Log::error("Scripting", "The script ended with an exception.");
// Write some information about the script exception
asIScriptFunction *func = ctx->GetExceptionFunction();
//std::cout << "func: " << func->GetDeclaration() << std::endl;
//std::cout << "modl: " << func->GetModuleName() << std::endl;
//std::cout << "sect: " << func->GetScriptSectionName() << std::endl;
//std::cout << "line: " << ctx->GetExceptionLineNumber() << std::endl;
//std::cout << "desc: " << ctx->GetExceptionString() << std::endl;
}
else
{
Log::error("Scripting", "The script ended for some unforeseen reason (%i)", r);
}
}
else
{
// Retrieve the return value from the context here (for scripts that return values)
// <type> returnValue = ctx->getReturnType(); for example
//float returnValue = ctx->GetReturnFloat();
}
// We must release the contexts when no longer using them
ctx->Release();
}
else
//-----------------------------------------------------------------------------
void ScriptEngine::cleanupCache()
{
// Retrieve the return value from the context here (for scripts that return values)
// <type> returnValue = ctx->getReturnType(); for example
//float returnValue = ctx->GetReturnFloat();
for (auto curr : m_functions_cache)
{
if (curr.second != NULL)
curr.second->Release();
}
m_functions_cache.clear();
m_loaded_files.clear();
}
// We must release the contexts when no longer using them
ctx->Release();
}
//-----------------------------------------------------------------------------
asIScriptFunction* ScriptEngine::registerScriptCallbacks(asIScriptEngine *engine,
std::string function_name)
{
asIScriptFunction *func;
func = engine->GetModule(0)->GetFunctionByDecl(function_name.c_str());
return func;
}
//-----------------------------------------------------------------------------
void ScriptEngine::cleanupCache()
{
for (auto curr : m_script_cache)
//-----------------------------------------------------------------------------
/** Configures the script engine by binding functions, enums
* \param asIScriptEngine engine = engine to configure
*/
void ScriptEngine::configureEngine(asIScriptEngine *engine)
{
if (curr.second != NULL)
curr.second->Release();
}
m_script_cache.clear();
}
// Register the script string type
RegisterStdString(engine); //register std::string
RegisterVec3(engine); //register Vec3
//-----------------------------------------------------------------------------
/** Configures the script engine by binding functions, enums
* \param asIScriptEngine engine = engine to configure
*/
void ScriptEngine::configureEngine(asIScriptEngine *engine)
{
// Register the script string type
RegisterStdString(engine); //register std::string
RegisterVec3(engine); //register Vec3
Scripting::Track::registerScriptFunctions(m_engine);
Scripting::Kart::registerScriptFunctions(m_engine);
Scripting::Physics::registerScriptFunctions(m_engine);
Scripting::Utils::registerScriptFunctions(m_engine);
Scripting::GUI::registerScriptFunctions(m_engine);
Scripting::GUI::registerScriptEnums(m_engine);
Scripting::Track::registerScriptFunctions(m_engine);
Scripting::Kart::registerScriptFunctions(m_engine);
Scripting::Physics::registerScriptFunctions(m_engine);
Scripting::Utils::registerScriptFunctions(m_engine);
Scripting::GUI::registerScriptFunctions(m_engine);
Scripting::GUI::registerScriptEnums(m_engine);
// It is possible to register the functions, properties, and types in
// configuration groups as well. When compiling the scripts it can then
// be defined which configuration groups should be available for that
// script. If necessary a configuration group can also be removed from
// the engine, so that the engine configuration could be changed
// without having to recompile all the scripts.
}
//-----------------------------------------------------------------------------
int ScriptEngine::compileScript(asIScriptEngine *engine, std::string scriptName)
{
int r;
std::string script = getScript(scriptName);
if (script.size() == 0)
{
// No such file
return -1;
// It is possible to register the functions, properties, and types in
// configuration groups as well. When compiling the scripts it can then
// be defined which configuration groups should be available for that
// script. If necessary a configuration group can also be removed from
// the engine, so that the engine configuration could be changed
// without having to recompile all the scripts.
}
// Add the script sections that will be compiled into executable code.
// If we want to combine more than one file into the same script, then
// we can call AddScriptSection() several times for the same module and
// the script engine will treat them all as if they were one. The script
// section name, will allow us to localize any errors in the script code.
asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
r = mod->AddScriptSection("script", &script[0], script.size());
if (r < 0)
//-----------------------------------------------------------------------------
int ScriptEngine::compileScript(asIScriptEngine *engine, std::string scriptName)
{
Log::error("Scripting", "AddScriptSection() failed");
return -1;
}
int r;
std::string script = getScript(scriptName);
if (script.size() == 0)
{
// No such file
return -1;
}
// Add the script sections that will be compiled into executable code.
// If we want to combine more than one file into the same script, then
// we can call AddScriptSection() several times for the same module and
// the script engine will treat them all as if they were one. The script
// section name, will allow us to localize any errors in the script code.
asIScriptModule *mod = engine->GetModule(MODULE_ID_MAIN_SCRIPT_FILE, asGM_ALWAYS_CREATE);
r = mod->AddScriptSection("script", &script[0], script.size());
if (r < 0)
{
Log::error("Scripting", "AddScriptSection() failed");
return -1;
}
// Compile the script. If there are any compiler messages they will
// be written to the message stream that we set right after creating the
// script engine. If there are no errors, and no warnings, nothing will
// be written to the stream.
r = mod->Build();
if (r < 0)
{
Log::error("Scripting", "Build() failed");
return -1;
// Compile the script. If there are any compiler messages they will
// be written to the message stream that we set right after creating the
// script engine. If there are no errors, and no warnings, nothing will
// be written to the stream.
r = mod->Build();
if (r < 0)
{
Log::error("Scripting", "Build() failed");
return -1;
}
// The engine doesn't keep a copy of the script sections after Build() has
// returned. So if the script needs to be recompiled, then all the script
// sections must be added again.
// If we want to have several scripts executing at different times but
// that have no direct relation with each other, then we can compile them
// into separate script modules. Each module uses their own namespace and
// scope, so function names, and global variables will not conflict with
// each other.
return 0;
}
// The engine doesn't keep a copy of the script sections after Build() has
// returned. So if the script needs to be recompiled, then all the script
// sections must be added again.
// If we want to have several scripts executing at different times but
// that have no direct relation with each other, then we can compile them
// into separate script modules. Each module uses their own namespace and
// scope, so function names, and global variables will not conflict with
// each other.
return 0;
}
}

View File

@ -51,16 +51,16 @@ namespace Scripting
ScriptEngine();
~ScriptEngine();
void runScript(std::string scriptName);
void runScript(std::string scriptName, std::function<void(asIScriptContext*)> callback);
void runFunction(std::string function_name);
void runFunction(std::string function_name, std::function<void(asIScriptContext*)> callback);
void evalScript(std::string script_fragment);
void cleanupCache();
asIScriptFunction*
registerScriptCallbacks(asIScriptEngine *engine, std::string scriptName);
private:
asIScriptEngine *m_engine;
std::map<std::string, asIScriptFunction*> m_script_cache;
std::map<std::string, bool> m_loaded_files;
std::map<std::string, asIScriptFunction*> m_functions_cache;
void configureEngine(asIScriptEngine *engine);
int compileScript(asIScriptEngine *engine,std::string scriptName);

View File

@ -115,7 +115,7 @@ namespace Scripting
void registerScriptFunctions(asIScriptEngine *engine)
{
int r;
int r; // of type asERetCodes
engine->SetDefaultNamespace("Kart");
r = engine->RegisterGlobalFunction("void squash(int id, float time)", asFUNCTION(squash), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("void teleport(int id, const Vec3 &in)", asFUNCTION(teleport), asCALL_CDECL); assert(r >= 0);

View File

@ -227,7 +227,7 @@ namespace Scripting
void registerScriptFunctions(asIScriptEngine *engine)
{
int r;
int r; // of type asERetCodes
engine->SetDefaultNamespace("Track");
@ -243,7 +243,7 @@ namespace Scripting
r = engine->RegisterGlobalFunction("void enableTrigger(const string &in)", asFUNCTION(enableTrigger), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("void disableTrigger(const string &in)", asFUNCTION(disableTrigger), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("void createTrigger(const string &in, const Vec3 &in, float distance)",
asFUNCTION(createTrigger), asCALL_GENERIC); assert(r >= 0);
asFUNCTION(createTrigger), asCALL_CDECL); assert(r >= 0);
r = engine->RegisterGlobalFunction("TrackObject@ getTrackObject(const string &in)", asFUNCTION(getTrackObject), asCALL_CDECL); assert(r >= 0);
// TrackObject

View File

@ -107,7 +107,7 @@ namespace Scripting
{
std::string *str = (std::string*)gen->GetArgAddress(0);
ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
script_engine->runScript(*str);
script_engine->runFunction(*str);
}
/** Log to the console */

View File

@ -0,0 +1,86 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2014-2015 Marc Coll
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "states_screens/dialogs/scripting_console.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/widgets/button_widget.hpp"
#include "guiengine/widgets/label_widget.hpp"
#include "guiengine/widgets/text_box_widget.hpp"
#include "modes/world.hpp"
#include "scriptengine/script_engine.hpp"
#include "states_screens/state_manager.hpp"
#include "utils/translation.hpp"
#include <IGUIEnvironment.h>
using namespace GUIEngine;
using namespace irr::core;
// -----------------------------------------------------------------------------
ScriptingConsole::ScriptingConsole() :
ModalDialog(0.95f, 0.2f, GUIEngine::MODAL_DIALOG_LOCATION_BOTTOM)
{
m_fade_background = false;
loadFromFile("scripting_console.stkgui");
TextBoxWidget* textCtrl = getWidget<TextBoxWidget>("textfield");
assert(textCtrl != NULL);
textCtrl->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
}
// -----------------------------------------------------------------------------
ScriptingConsole::~ScriptingConsole()
{
// FIXME: what is this code for?
TextBoxWidget* textCtrl = getWidget<TextBoxWidget>("textfield");
textCtrl->getIrrlichtElement()->remove();
textCtrl->clearListeners();
}
// -----------------------------------------------------------------------------
GUIEngine::EventPropagation ScriptingConsole::processEvent(const std::string& eventSource)
{
if (eventSource == "close")
{
dismiss();
return GUIEngine::EVENT_BLOCK;
}
else if (eventSource == "run")
{
runScript();
return GUIEngine::EVENT_BLOCK;
}
return GUIEngine::EVENT_LET;
}
// -----------------------------------------------------------------------------
void ScriptingConsole::runScript()
{
TextBoxWidget* textCtrl = getWidget<TextBoxWidget>("textfield");
core::stringw script = textCtrl->getText();
textCtrl->setText(L"");
World::getWorld()->getScriptEngine()->evalScript(core::stringc(script.c_str()).c_str());
}
// -----------------------------------------------------------------------------

View File

@ -0,0 +1,51 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2014-2015 Marc Coll
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_SCRIPTING_CONSOLE_DIALOG_HPP
#define HEADER_SCRIPTING_CONSOLE_DIALOG_HPP
#include "guiengine/modaldialog.hpp"
#include "utils/cpp2011.hpp"
#include <irrString.h>
namespace GUIEngine
{
class TextBoxWidget;
class ButtonWidget;
class LabelWidget;
}
/**
* \brief Dialog that allows the player to enter the name for a new grand prix
* \ingroup states_screens
*/
class ScriptingConsole : public GUIEngine::ModalDialog
{
public:
ScriptingConsole();
~ScriptingConsole();
virtual void onEnterPressedInternal() OVERRIDE{ runScript(); }
void runScript();
GUIEngine::EventPropagation processEvent(const std::string& eventSource);
};
#endif

View File

@ -1486,7 +1486,7 @@ void Track::update(float dt)
if (!m_startup_run) // first time running update = good point to run startup script
{
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
script_engine->runScript("void onStart()");
script_engine->runFunction("void onStart()");
m_startup_run = true;
}
m_track_object_manager->update(dt);

View File

@ -955,7 +955,7 @@ void TrackObjectPresentationActionTrigger::onTriggerItemApproached(Item* who)
Camera* camera = Camera::getActiveCamera();
if (camera != NULL && camera->getKart() != NULL)
idKart = camera->getKart()->getWorldKartId();
script_engine->runScript("void " + m_action + "(int)",
script_engine->runFunction("void " + m_action + "(int)",
[=](asIScriptContext* ctx) { ctx->SetArgDWord(0, idKart); });
}
} // onTriggerItemApproached

View File

@ -33,6 +33,7 @@
#include "main_loop.hpp"
#include "replay/replay_recorder.hpp"
#include "states_screens/dialogs/debug_slider.hpp"
#include "states_screens/dialogs/scripting_console.hpp"
#include "utils/constants.hpp"
#include "utils/log.hpp"
#include "utils/profiler.hpp"
@ -103,6 +104,7 @@ enum DebugMenuCommand
DEBUG_VISUAL_VALUES,
DEBUG_PRINT_START_POS,
DEBUG_ADJUST_LIGHTS,
DEBUG_SCRIPT_CONSOLE
}; // DebugMenuCommand
// -----------------------------------------------------------------------------
@ -265,6 +267,7 @@ bool onEvent(const SEvent &event)
mnu->addItem(L"Save history", DEBUG_SAVE_HISTORY);
mnu->addItem(L"Print position", DEBUG_PRINT_START_POS);
mnu->addItem(L"Adjust Lights", DEBUG_ADJUST_LIGHTS);
mnu->addItem(L"Scripting console", DEBUG_SCRIPT_CONSOLE);
g_debug_menu_visible = true;
irr_driver->showPointer();
@ -650,6 +653,10 @@ bool onEvent(const SEvent &event)
dsd->changeLabel("SSAO Sigma", "[None]");
#endif
}
else if (cmdID == DEBUG_SCRIPT_CONSOLE)
{
ScriptingConsole* console = new ScriptingConsole();
}
}
return false; // event has been handled