Work on scripting
This commit is contained in:
parent
e23f854845
commit
080936f144
17
data/gui/scripting_console.stkgui
Normal file
17
data/gui/scripting_console.stkgui
Normal 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>
|
@ -171,7 +171,7 @@ void Physics::update(float dt)
|
|||||||
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
||||||
int kartid1 = p->getUserPointer(0)->getPointerKart()->getWorldKartId();
|
int kartid1 = p->getUserPointer(0)->getPointerKart()->getWorldKartId();
|
||||||
int kartid2 = p->getUserPointer(1)->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) {
|
[=](asIScriptContext* ctx) {
|
||||||
ctx->SetArgDWord(0, kartid1);
|
ctx->SetArgDWord(0, kartid1);
|
||||||
ctx->SetArgDWord(1, kartid2);
|
ctx->SetArgDWord(1, kartid2);
|
||||||
@ -189,7 +189,7 @@ void Physics::update(float dt)
|
|||||||
std::string obj_id = p->getUserPointer(0)->getPointerPhysicalObject()->getID();
|
std::string obj_id = p->getUserPointer(0)->getPointerPhysicalObject()->getID();
|
||||||
|
|
||||||
// TODO: pass obj_id as arguent
|
// TODO: pass obj_id as arguent
|
||||||
script_engine->runScript("void onKartObjectCollision(int)",
|
script_engine->runFunction("void onKartObjectCollision(int)",
|
||||||
[=](asIScriptContext* ctx) {
|
[=](asIScriptContext* ctx) {
|
||||||
ctx->SetArgDWord(0, kartId);
|
ctx->SetArgDWord(0, kartId);
|
||||||
});
|
});
|
||||||
@ -260,7 +260,7 @@ void Physics::update(float dt)
|
|||||||
// p->getUserPointer(1)->getPointerPhysicalObject()->getID(),
|
// p->getUserPointer(1)->getPointerPhysicalObject()->getID(),
|
||||||
// "item"
|
// "item"
|
||||||
//);
|
//);
|
||||||
script_engine->runScript("void onItemObjectCollision()");
|
script_engine->runFunction("void onItemObjectCollision()");
|
||||||
p->getUserPointer(0)->getPointerFlyable()
|
p->getUserPointer(0)->getPointerFlyable()
|
||||||
->hit(NULL, p->getUserPointer(1)->getPointerPhysicalObject());
|
->hit(NULL, p->getUserPointer(1)->getPointerPhysicalObject());
|
||||||
PhysicalObject* obj = p->getUserPointer(1)->getPointerPhysicalObject();
|
PhysicalObject* obj = p->getUserPointer(1)->getPointerPhysicalObject();
|
||||||
|
@ -38,308 +38,372 @@ using namespace Scripting;
|
|||||||
|
|
||||||
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)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
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,
|
//Constructor, creates a new Scripting Engine using AngelScript
|
||||||
// and variables that the script should be able to use.
|
ScriptEngine::ScriptEngine()
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
Log::debug("Scripting", "File does not exist : {0}.as", scriptName.c_str());
|
// Create the script engine
|
||||||
return "";
|
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
|
ScriptEngine::~ScriptEngine()
|
||||||
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.");
|
// Release the engine
|
||||||
return "";
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
/** Get Script By it's file name
|
||||||
|
* \param string scriptname = name of script to get
|
||||||
/** runs the specified script
|
* \return The corresponding script
|
||||||
* \param string scriptName = name of script to run
|
*/
|
||||||
*/
|
std::string getScript(std::string fileName)
|
||||||
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())
|
|
||||||
{
|
{
|
||||||
// Compile the script code
|
std::string script_dir = file_manager->getAsset(FileManager::SCRIPT, "");
|
||||||
Log::debug("Scripting", "Compiling script '%s' (was not in cache)", scriptName.c_str());
|
script_dir += World::getWorld()->getTrack()->getIdent() + "/";
|
||||||
r = compileScript(m_engine, scriptName);
|
|
||||||
|
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)
|
if (r < 0)
|
||||||
{
|
{
|
||||||
Log::debug("Scripting", "Script '%s' is not available", scriptName.c_str());
|
Log::error("Scripting", "evalScript: AddScriptSection() failed");
|
||||||
m_script_cache[scriptName] = NULL; // remember that this script is unavailable
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the function for the function we want to execute.
|
r = mod->Build();
|
||||||
//This is how you call a normal function with arguments
|
if (r < 0)
|
||||||
//asIScriptFunction *func = engine->GetModule(0)->GetFunctionByDecl("void func(arg1Type, arg2Type)");
|
|
||||||
func = registerScriptCallbacks(m_engine, scriptName);
|
|
||||||
|
|
||||||
if (func == NULL)
|
|
||||||
{
|
{
|
||||||
Log::debug("Scripting", "Scripting function was not found : %s", scriptName.c_str());
|
Log::error("Scripting", "evalScript: Build() failed");
|
||||||
m_script_cache[scriptName] = NULL; // remember that this script is unavailable
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//CACHE UPDATE
|
asIScriptFunction* func = m_engine->GetModule(MODULE_ID_EVAL)
|
||||||
m_script_cache[scriptName] = func;
|
->GetFunctionByDecl("void evalScript_main()");
|
||||||
func->AddRef();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Script present in cache
|
|
||||||
func = cached_script->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (func == NULL)
|
asIScriptContext *ctx = m_engine->CreateContext();
|
||||||
{
|
if (ctx == NULL)
|
||||||
return; // script unavailable
|
{
|
||||||
}
|
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.
|
// Execute the function
|
||||||
asIScriptContext *ctx = m_engine->CreateContext();
|
r = ctx->Execute();
|
||||||
if (ctx == NULL)
|
if (r != asEXECUTION_FINISHED)
|
||||||
{
|
{
|
||||||
Log::error("Scripting", "Failed to create the context.");
|
// The execution didn't finish as we had planned. Determine why.
|
||||||
//m_engine->Release();
|
if (r == asEXECUTION_ABORTED)
|
||||||
return;
|
{
|
||||||
}
|
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();
|
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)
|
/** runs the specified script
|
||||||
callback(ctx);
|
* \param string scriptName = name of script to run
|
||||||
|
*/
|
||||||
// Execute the function
|
void ScriptEngine::runFunction(std::string function_name)
|
||||||
r = ctx->Execute();
|
|
||||||
if (r != asEXECUTION_FINISHED)
|
|
||||||
{
|
{
|
||||||
// The execution didn't finish as we had planned. Determine why.
|
std::function<void(asIScriptContext*)> callback;
|
||||||
if (r == asEXECUTION_ABORTED)
|
runFunction(function_name, callback);
|
||||||
{
|
}
|
||||||
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;
|
/** runs the specified script
|
||||||
//std::cout << "modl: " << func->GetModuleName() << std::endl;
|
* \param string scriptName = name of script to run
|
||||||
//std::cout << "sect: " << func->GetScriptSectionName() << std::endl;
|
*/
|
||||||
//std::cout << "line: " << ctx->GetExceptionLineNumber() << std::endl;
|
void ScriptEngine::runFunction(std::string function_name, std::function<void(asIScriptContext*)> callback)
|
||||||
//std::cout << "desc: " << ctx->GetExceptionString() << std::endl;
|
{
|
||||||
|
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
|
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)
|
for (auto curr : m_functions_cache)
|
||||||
// <type> returnValue = ctx->getReturnType(); for example
|
{
|
||||||
//float returnValue = ctx->GetReturnFloat();
|
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();
|
/** Configures the script engine by binding functions, enums
|
||||||
}
|
* \param asIScriptEngine engine = engine to configure
|
||||||
|
*/
|
||||||
//-----------------------------------------------------------------------------
|
void ScriptEngine::configureEngine(asIScriptEngine *engine)
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (curr.second != NULL)
|
// Register the script string type
|
||||||
curr.second->Release();
|
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);
|
||||||
|
|
||||||
|
// 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.
|
||||||
}
|
}
|
||||||
m_script_cache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
/** 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);
|
int ScriptEngine::compileScript(asIScriptEngine *engine, std::string scriptName)
|
||||||
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
|
int r;
|
||||||
return -1;
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -52,15 +52,15 @@ namespace Scripting
|
|||||||
ScriptEngine();
|
ScriptEngine();
|
||||||
~ScriptEngine();
|
~ScriptEngine();
|
||||||
|
|
||||||
void runScript(std::string scriptName);
|
void runFunction(std::string function_name);
|
||||||
void runScript(std::string scriptName, std::function<void(asIScriptContext*)> callback);
|
void runFunction(std::string function_name, std::function<void(asIScriptContext*)> callback);
|
||||||
|
void evalScript(std::string script_fragment);
|
||||||
void cleanupCache();
|
void cleanupCache();
|
||||||
asIScriptFunction*
|
|
||||||
registerScriptCallbacks(asIScriptEngine *engine, std::string scriptName);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
asIScriptEngine *m_engine;
|
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);
|
void configureEngine(asIScriptEngine *engine);
|
||||||
int compileScript(asIScriptEngine *engine,std::string scriptName);
|
int compileScript(asIScriptEngine *engine,std::string scriptName);
|
||||||
|
@ -115,7 +115,7 @@ namespace Scripting
|
|||||||
|
|
||||||
void registerScriptFunctions(asIScriptEngine *engine)
|
void registerScriptFunctions(asIScriptEngine *engine)
|
||||||
{
|
{
|
||||||
int r;
|
int r; // of type asERetCodes
|
||||||
engine->SetDefaultNamespace("Kart");
|
engine->SetDefaultNamespace("Kart");
|
||||||
r = engine->RegisterGlobalFunction("void squash(int id, float time)", asFUNCTION(squash), asCALL_CDECL); assert(r >= 0);
|
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);
|
r = engine->RegisterGlobalFunction("void teleport(int id, const Vec3 &in)", asFUNCTION(teleport), asCALL_CDECL); assert(r >= 0);
|
||||||
|
@ -227,7 +227,7 @@ namespace Scripting
|
|||||||
|
|
||||||
void registerScriptFunctions(asIScriptEngine *engine)
|
void registerScriptFunctions(asIScriptEngine *engine)
|
||||||
{
|
{
|
||||||
int r;
|
int r; // of type asERetCodes
|
||||||
|
|
||||||
engine->SetDefaultNamespace("Track");
|
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 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 disableTrigger(const string &in)", asFUNCTION(disableTrigger), asCALL_CDECL); assert(r >= 0);
|
||||||
r = engine->RegisterGlobalFunction("void createTrigger(const string &in, const Vec3 &in, float distance)",
|
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);
|
r = engine->RegisterGlobalFunction("TrackObject@ getTrackObject(const string &in)", asFUNCTION(getTrackObject), asCALL_CDECL); assert(r >= 0);
|
||||||
|
|
||||||
// TrackObject
|
// TrackObject
|
||||||
|
@ -107,7 +107,7 @@ namespace Scripting
|
|||||||
{
|
{
|
||||||
std::string *str = (std::string*)gen->GetArgAddress(0);
|
std::string *str = (std::string*)gen->GetArgAddress(0);
|
||||||
ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
||||||
script_engine->runScript(*str);
|
script_engine->runFunction(*str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Log to the console */
|
/** Log to the console */
|
||||||
|
86
src/states_screens/dialogs/scripting_console.cpp
Normal file
86
src/states_screens/dialogs/scripting_console.cpp
Normal 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
51
src/states_screens/dialogs/scripting_console.hpp
Normal file
51
src/states_screens/dialogs/scripting_console.hpp
Normal 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
|
@ -1486,7 +1486,7 @@ void Track::update(float dt)
|
|||||||
if (!m_startup_run) // first time running update = good point to run startup script
|
if (!m_startup_run) // first time running update = good point to run startup script
|
||||||
{
|
{
|
||||||
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
|
||||||
script_engine->runScript("void onStart()");
|
script_engine->runFunction("void onStart()");
|
||||||
m_startup_run = true;
|
m_startup_run = true;
|
||||||
}
|
}
|
||||||
m_track_object_manager->update(dt);
|
m_track_object_manager->update(dt);
|
||||||
|
@ -955,7 +955,7 @@ void TrackObjectPresentationActionTrigger::onTriggerItemApproached(Item* who)
|
|||||||
Camera* camera = Camera::getActiveCamera();
|
Camera* camera = Camera::getActiveCamera();
|
||||||
if (camera != NULL && camera->getKart() != NULL)
|
if (camera != NULL && camera->getKart() != NULL)
|
||||||
idKart = camera->getKart()->getWorldKartId();
|
idKart = camera->getKart()->getWorldKartId();
|
||||||
script_engine->runScript("void " + m_action + "(int)",
|
script_engine->runFunction("void " + m_action + "(int)",
|
||||||
[=](asIScriptContext* ctx) { ctx->SetArgDWord(0, idKart); });
|
[=](asIScriptContext* ctx) { ctx->SetArgDWord(0, idKart); });
|
||||||
}
|
}
|
||||||
} // onTriggerItemApproached
|
} // onTriggerItemApproached
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "main_loop.hpp"
|
#include "main_loop.hpp"
|
||||||
#include "replay/replay_recorder.hpp"
|
#include "replay/replay_recorder.hpp"
|
||||||
#include "states_screens/dialogs/debug_slider.hpp"
|
#include "states_screens/dialogs/debug_slider.hpp"
|
||||||
|
#include "states_screens/dialogs/scripting_console.hpp"
|
||||||
#include "utils/constants.hpp"
|
#include "utils/constants.hpp"
|
||||||
#include "utils/log.hpp"
|
#include "utils/log.hpp"
|
||||||
#include "utils/profiler.hpp"
|
#include "utils/profiler.hpp"
|
||||||
@ -103,6 +104,7 @@ enum DebugMenuCommand
|
|||||||
DEBUG_VISUAL_VALUES,
|
DEBUG_VISUAL_VALUES,
|
||||||
DEBUG_PRINT_START_POS,
|
DEBUG_PRINT_START_POS,
|
||||||
DEBUG_ADJUST_LIGHTS,
|
DEBUG_ADJUST_LIGHTS,
|
||||||
|
DEBUG_SCRIPT_CONSOLE
|
||||||
}; // DebugMenuCommand
|
}; // DebugMenuCommand
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -265,6 +267,7 @@ bool onEvent(const SEvent &event)
|
|||||||
mnu->addItem(L"Save history", DEBUG_SAVE_HISTORY);
|
mnu->addItem(L"Save history", DEBUG_SAVE_HISTORY);
|
||||||
mnu->addItem(L"Print position", DEBUG_PRINT_START_POS);
|
mnu->addItem(L"Print position", DEBUG_PRINT_START_POS);
|
||||||
mnu->addItem(L"Adjust Lights", DEBUG_ADJUST_LIGHTS);
|
mnu->addItem(L"Adjust Lights", DEBUG_ADJUST_LIGHTS);
|
||||||
|
mnu->addItem(L"Scripting console", DEBUG_SCRIPT_CONSOLE);
|
||||||
|
|
||||||
g_debug_menu_visible = true;
|
g_debug_menu_visible = true;
|
||||||
irr_driver->showPointer();
|
irr_driver->showPointer();
|
||||||
@ -650,6 +653,10 @@ bool onEvent(const SEvent &event)
|
|||||||
dsd->changeLabel("SSAO Sigma", "[None]");
|
dsd->changeLabel("SSAO Sigma", "[None]");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
else if (cmdID == DEBUG_SCRIPT_CONSOLE)
|
||||||
|
{
|
||||||
|
ScriptingConsole* console = new ScriptingConsole();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // event has been handled
|
return false; // event has been handled
|
||||||
|
Loading…
x
Reference in New Issue
Block a user