Start work to enable scripting

This commit is contained in:
Marianne Gagnon 2015-04-24 20:59:32 -04:00
parent fc942433e2
commit 9f883db6f7
10 changed files with 230 additions and 94 deletions

View File

@ -339,7 +339,7 @@ int asCContext::Prepare(asIScriptFunction *func)
asASSERT( m_engine );
// Make sure the function is from the same engine as the context to avoid mixups
if( m_engine != func->GetEngine() )
if (m_engine != func->GetEngine())
{
asCString str;
str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_d, "Prepare", func->GetDeclaration(true, true), asINVALID_ARG);

View File

@ -29,7 +29,7 @@
#include "states_screens/dialogs/tutorial_message_dialog.hpp"
#include "tracks/track_object_manager.hpp"
#include "tracks/track.hpp"
#include "utils/profiler.hpp"
using namespace Scripting;
@ -38,8 +38,7 @@ namespace Scripting
{
//Line Callback
void MessageCallback(const asSMessageInfo *msg, void *param)
void AngelScript_ErrorCallback (const asSMessageInfo *msg, void *param)
{
const char *type = "ERR ";
if (msg->type == asMSGTYPE_WARNING)
@ -47,7 +46,7 @@ void MessageCallback(const asSMessageInfo *msg, void *param)
else if (msg->type == asMSGTYPE_INFORMATION)
type = "INFO";
printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
Log::warn("Scripting", "%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
}
@ -56,19 +55,19 @@ ScriptEngine::ScriptEngine()
{
// Create the script engine
m_engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
if( m_engine == 0 )
if (m_engine == NULL)
{
std::cout << "Failed to create script engine." << std::endl;
Log::error("Scripting", "Failed to create script engine.");
}
// The script compiler will write any compiler messages to the callback.
//m_engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);
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
@ -85,12 +84,15 @@ std::string getScript(std::string scriptName)
{
std::string script_dir = file_manager->getAsset(FileManager::SCRIPT, "");
script_dir += World::getWorld()->getTrack()->getIdent() + "/";
if (scriptName != "update" && scriptName != "collisions" && scriptName!="start") scriptName = "triggers";
if (scriptName != "update" && scriptName != "collisions" && scriptName != "start")
scriptName = "triggers";
script_dir += scriptName + ".as";
FILE *f = fopen(script_dir.c_str(), "rb");
if( f == 0 )
if (f == NULL)
{
std::cout << "Failed to open the script file " + scriptName + ".as" << std::endl;
Log::debug("Scripting", "File does not exist : {0}.as", scriptName.c_str());
return "";
}
// Determine the size of the file
@ -103,25 +105,27 @@ std::string getScript(std::string scriptName)
script.resize(len);
int c = fread(&script[0], len, 1, f);
fclose(f);
if( c == 0 )
if (c == NULL)
{
std::cout << "Failed to load script file." << std::endl;
Log::error("Scripting", "Failed to load script file.");
return "";
}
return script;
}
//-----------------------------------------------------------------------------
/** runs the specified script
* \param string scriptName = name of script to run
*/
void ScriptEngine::runScript(std::string scriptName)
{
return; // Scripting disabled for now
PROFILER_PUSH_CPU_MARKER("RunScript", 255, 0, 0);
// Create a context that will execute the script.
asIScriptContext *ctx = m_engine->CreateContext();
if (ctx == 0)
if (ctx == NULL)
{
std::cout << "Failed to create the context." << std::endl;
Log::error("Scripting", "Failed to create the context.");
//m_engine->Release();
return;
}
@ -132,16 +136,12 @@ void ScriptEngine::runScript(std::string scriptName)
if (m_script_cache.find(scriptName) == m_script_cache.end())
{
// Compile the script code
Log::debug("Scripting", "Compiling script '%s' (was not in cache)", scriptName.c_str());
r = compileScript(m_engine, scriptName);
if (r < 0)
{
return;
}
//set line callback here soon
if (r < 0)
{
std::cout << "Failed to set the line callback function." << std::endl;
Log::debug("Scripting", "Script '%s' is not available", scriptName.c_str());
m_script_cache[scriptName] = NULL; // remember that this script is unavaiable
ctx->Release();
return;
}
@ -166,32 +166,40 @@ void ScriptEngine::runScript(std::string scriptName)
//trigger type can have different names
func = Scripting::Track::registerScriptCallbacks(m_engine, scriptName);
}
if (func == 0)
if (func == NULL)
{
std::cout << "The required function was not found." << std::endl;
Log::warn("Scripting", "The required function was not found : %s", scriptName.c_str());
ctx->Release();
//m_engine->Release();
return;
}
//CACHE UPDATE
m_script_cache[scriptName] = func;
func->AddRef();
}
else
{
//Script present in cache
// TODO: clear when done
func = m_script_cache[scriptName];
std::cout << "FOUND CACHED : " << scriptName << std::endl;
}
if (func == NULL)
{
PROFILER_POP_CPU_MARKER();
return; // script unavailable
}
// 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 )
if (r < 0)
{
std::cout << "Failed to prepare the context." << std::endl;
Log::error("Scripting", "Failed to prepare the context.");
ctx->Release();
//m_engine->Release();
return;
@ -204,25 +212,29 @@ void ScriptEngine::runScript(std::string scriptName)
// Execute the function
r = ctx->Execute();
if( r != asEXECUTION_FINISHED )
if (r != asEXECUTION_FINISHED)
{
// The execution didn't finish as we had planned. Determine why.
if( r == asEXECUTION_ABORTED )
std::cout << "The script was aborted before it could finish. Probably it timed out." << std::endl;
else if( r == asEXECUTION_EXCEPTION )
if (r == asEXECUTION_ABORTED)
{
std::cout << "The script ended with an exception." << std::endl;
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;
//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
std::cout << "The script ended for some unforeseen reason (" << r << ")." << std::endl;
{
Log::error("Scripting", "The script ended for some unforeseen reason (%i)", r);
}
}
else
{
@ -234,8 +246,19 @@ void ScriptEngine::runScript(std::string scriptName)
// We must release the contexts when no longer using them
ctx->Release();
PROFILER_POP_CPU_MARKER();
}
//-----------------------------------------------------------------------------
void ScriptEngine::cleanupCache()
{
for (auto curr : m_script_cache)
{
curr.second->Release();
}
m_script_cache.clear();
}
//-----------------------------------------------------------------------------
/** Configures the script engine by binding functions, enums
@ -245,6 +268,7 @@ void ScriptEngine::configureEngine(asIScriptEngine *engine)
{
// Register the script string type
RegisterStdString(engine); //register std::string
RegisterStdStringUtils(engine);
RegisterVec3(engine); //register Vec3
Scripting::Track::registerScriptFunctions(m_engine);
@ -266,13 +290,17 @@ void ScriptEngine::configureEngine(asIScriptEngine *engine)
//-----------------------------------------------------------------------------
int ScriptEngine::compileScript(asIScriptEngine *engine, std::string scriptName)
{
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
@ -280,9 +308,9 @@ int ScriptEngine::compileScript(asIScriptEngine *engine, std::string scriptName)
// 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 )
if (r < 0)
{
std::cout << "AddScriptSection() failed" << std::endl;
Log::error("Scripting", "AddScriptSection() failed");
return -1;
}
@ -291,9 +319,9 @@ int ScriptEngine::compileScript(asIScriptEngine *engine, std::string scriptName)
// script engine. If there are no errors, and no warnings, nothing will
// be written to the stream.
r = mod->Build();
if( r < 0 )
if (r < 0)
{
std::cout << "Build() failed" << std::endl;
Log::error("Scripting", "Build() failed");
return -1;
}

View File

@ -65,6 +65,7 @@ namespace Scripting
~ScriptEngine();
void runScript(std::string scriptName);
void cleanupCache();
private:
asIScriptEngine *m_engine;

View File

@ -156,7 +156,7 @@ namespace Scripting
void displayMessage(asIScriptGeneric *gen)
{
std::string *input = (std::string*)gen->GetArgAddress(0);
irr::core::stringw out = irr::core::stringw((*input).c_str()); //irr::core::stringw supported by message dialogs
irr::core::stringw out = StringUtils::utf8_to_wide(input->c_str());
new TutorialMessageDialog((out), true);
}
//generic disable method for track objects

View File

@ -20,6 +20,7 @@
#include "scriptarray.hpp"
#include <stdio.h>
#include <string.h>
#include "utils/translation.hpp"
using namespace std;
@ -125,22 +126,110 @@ static void StringJoin_Generic(asIScriptGeneric *gen)
new(gen->GetAddressOfReturnLocation()) string(StringJoin(*array, *delim));
}
void translate(asIScriptGeneric *gen)
{
// Get the arguments
std::string *input = (std::string*)gen->GetArgAddress(0);
irr::core::stringw out = translations->fribidize(translations->w_gettext(input->c_str()));
// Return the string
new(gen->GetAddressOfReturnLocation()) string(StringUtils::wide_to_utf8(out.c_str()));
}
void insertValues1(asIScriptGeneric *gen)
{
// Get the arguments
std::string *input = (std::string*)gen->GetArgAddress(0);
std::string *arg1 = (std::string*)gen->GetArgAddress(1);
irr::core::stringw out = StringUtils::insertValues(StringUtils::utf8_to_wide(input->c_str()),
StringUtils::utf8_to_wide(arg1->c_str()));
// Return the string
new(gen->GetAddressOfReturnLocation()) string(StringUtils::wide_to_utf8(out.c_str()));
}
void insertValues2(asIScriptGeneric *gen)
{
// Get the arguments
std::string *input = (std::string*)gen->GetArgAddress(0);
std::string *arg1 = (std::string*)gen->GetArgAddress(1);
std::string *arg2 = (std::string*)gen->GetArgAddress(2);
irr::core::stringw out = StringUtils::insertValues(StringUtils::utf8_to_wide(input->c_str()),
StringUtils::utf8_to_wide(arg1->c_str()),
StringUtils::utf8_to_wide(arg2->c_str()));
// Return the string
new(gen->GetAddressOfReturnLocation()) string(StringUtils::wide_to_utf8(out.c_str()));
}
void insertValues3(asIScriptGeneric *gen)
{
// Get the arguments
std::string *input = (std::string*)gen->GetArgAddress(0);
std::string *arg1 = (std::string*)gen->GetArgAddress(1);
std::string *arg2 = (std::string*)gen->GetArgAddress(2);
std::string *arg3 = (std::string*)gen->GetArgAddress(3);
irr::core::stringw out = StringUtils::insertValues(StringUtils::utf8_to_wide(input->c_str()),
StringUtils::utf8_to_wide(arg1->c_str()),
StringUtils::utf8_to_wide(arg2->c_str()),
StringUtils::utf8_to_wide(arg3->c_str()));
// Return the string
new(gen->GetAddressOfReturnLocation()) string(StringUtils::wide_to_utf8(out.c_str()));
}
/*
void insertValues(asIScriptGeneric *gen)
{
// Get the arguments
std::string *input = (std::string*)gen->GetArgAddress(0);
CScriptArray *array = *(CScriptArray**)gen->GetAddressOfArg(1);
int size = array->GetSize();
vector<string> all_values;
for (int i = 0; i < size; i++)
{
string* curr = (string*)array->At(i);
all_values.push_back(curr);
}
StringUtils::insertValues(*input, all_values);
irr::core::stringw out = translations->fribidize(translations->w_gettext(input->c_str()));
// Return the string
new(gen->GetAddressOfReturnLocation()) string(irr::core::stringc(out).c_str());
}
*/
// This is where the utility functions are registered.
// The string type must have been registered first.
void RegisterStdStringUtils(asIScriptEngine *engine)
{
int r;
if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
{
r = engine->RegisterObjectMethod("string", "array<string>@ split(const string &in) const", asFUNCTION(StringSplit_Generic), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterGlobalFunction("string join(const array<string> &in, const string &in)", asFUNCTION(StringJoin_Generic), asCALL_GENERIC); assert(r >= 0);
}
else
{
r = engine->RegisterObjectMethod("string", "array<string>@ split(const string &in) const", asFUNCTION(StringSplit), asCALL_CDECL_OBJLAST); assert(r >= 0);
r = engine->RegisterGlobalFunction("string join(const array<string> &in, const string &in)", asFUNCTION(StringJoin), asCALL_CDECL); assert(r >= 0);
}
//if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY"))
//{
//r = engine->RegisterObjectMethod("string", "array<string>@ split(const string &in) const", asFUNCTION(StringSplit_Generic), asCALL_GENERIC); assert(r >= 0);
//r = engine->RegisterGlobalFunction("string join(const array<string> &in, const string &in)", asFUNCTION(StringJoin_Generic), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterGlobalFunction("string translate(const string &in)", asFUNCTION(translate), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in)", asFUNCTION(insertValues1), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in, const string &in)", asFUNCTION(insertValues2), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &in, const string &in, const string &in)", asFUNCTION(insertValues3), asCALL_GENERIC); assert(r >= 0);
//}
//else
//{
// //r = engine->RegisterObjectMethod("string", "array<string>@ split(const string &in) const", asFUNCTION(StringSplit), asCALL_CDECL_OBJLAST); assert(r >= 0);
// //r = engine->RegisterGlobalFunction("string join(const array<string> &in, const string &in)", asFUNCTION(StringJoin), asCALL_CDECL); assert(r >= 0);
// r = engine->RegisterGlobalFunction("string translate(const string &in)", asFUNCTION(translate), asCALL_CDECL); assert(r >= 0);
// r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &arg1)", asFUNCTION(insertValues1), asCALL_CDECL); assert(r >= 0);
// r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &arg1, const string &arg2)", asFUNCTION(insertValues2), asCALL_CDECL); assert(r >= 0);
// r = engine->RegisterGlobalFunction("string insertValues(const string &in, const string &arg1, const string &arg2, const string &arg3)", asFUNCTION(insertValues3), asCALL_CDECL); assert(r >= 0);
//}
}
END_AS_NAMESPACE

View File

@ -448,6 +448,10 @@ void Track::cleanup()
Log::info("CACHE", "[%i] %s", i, path.getPath().c_str());
}
#endif
Scripting::ScriptEngine* script_engine =
World::getWorld()->getScriptEngine();
script_engine->cleanupCache();
} // cleanup
//-----------------------------------------------------------------------------

View File

@ -921,6 +921,7 @@ void TrackObjectPresentationActionTrigger::onTriggerItemApproached(Item* who)
_("Complete all challenges to unlock the big door!"), true);
}
}
/*
else if (m_action == "tutorial_drive")
{
//if (World::getWorld()->getPhase() == World::RACE_PHASE)
@ -1036,19 +1037,19 @@ void TrackObjectPresentationActionTrigger::onTriggerItemApproached(Item* who)
new TutorialMessageDialog(_("You are now ready to race. Good luck!"),
true);
}
}*/
else if (m_action == "tutorial_exit")
{
// TODO: move to scripting
World::getWorld()->scheduleExitRace();
return;
}
else
{
//TODO move all above functions into scripts and remove the ifs
Scripting::ScriptEngine* m_script_engine =
Scripting::ScriptEngine* script_engine =
World::getWorld()->getScriptEngine();
m_action_active = false;
m_script_engine->runScript(m_action);
script_engine->runScript(m_action);
/*
Catch exception -> script not found

View File

@ -22,7 +22,7 @@
#include "utils/log.hpp"
#include "utils/time.hpp"
#include "utils/utf8.h"
#include "coreutil.h"
#include <math.h>
@ -684,6 +684,32 @@ namespace StringUtils
return output.str();
} // xmlEncode
// ------------------------------------------------------------------------
std::string wide_to_utf8(const wchar_t* input)
{
static std::vector<char> utf8line;
utf8line.clear();
utf8::utf16to8(input, input + wcslen(input), back_inserter(utf8line));
utf8line.push_back(0);
return std::string(&utf8line[0]);
}
// ------------------------------------------------------------------------
irr::core::stringw utf8_to_wide(const char* input)
{
static std::vector<wchar_t> utf16line;
utf16line.clear();
utf8::utf8to16(input, input + strlen(input), back_inserter(utf16line));
utf16line.push_back(0);
return irr::core::stringw(&utf16line[0]);
}
// ------------------------------------------------------------------------
/** Converts a version string (in the form of 'X.Y.Za-rcU' into an
* integer number.

View File

@ -259,7 +259,7 @@ namespace StringUtils
all_vals.push_back(irr::core::stringw(std::forward<T>(v)));
__Fill(all_vals, std::forward<Args>(args)...);
}
static void __Fill(std::vector<irr::core::stringw>&) {}
};
@ -363,6 +363,11 @@ namespace StringUtils
return parseString(input.c_str(), output);
} // parseString
// ------------------------------------------------------------------------
std::string wide_to_utf8(const wchar_t* input);
irr::core::stringw utf8_to_wide(const char* input);
} // namespace StringUtils
#endif

View File

@ -42,7 +42,6 @@
#include "io/file_manager.hpp"
#include "utils/constants.hpp"
#include "utils/log.hpp"
#include "utils/utf8.h"
// set to 1 to debug i18n
@ -71,29 +70,6 @@ const LanguageList* Translations::getLanguageList() const
return &g_language_list;
}
char* wide_to_utf8(const wchar_t* input)
{
static std::vector<char> utf8line;
utf8line.clear();
utf8::utf16to8(input, input + wcslen(input), back_inserter(utf8line));
utf8line.push_back(0);
return &utf8line[0];
}
wchar_t* utf8_to_wide(const char* input)
{
static std::vector<wchar_t> utf16line;
utf16line.clear();
utf8::utf8to16(input, input + strlen(input), back_inserter(utf16line));
utf16line.push_back(0);
return &utf16line[0];
}
// ----------------------------------------------------------------------------
/** Frees the memory allocated for the result of toFribidiChar(). */
void freeFribidiChar(FriBidiChar *str)
@ -439,7 +415,8 @@ bool Translations::isRTLText(const wchar_t *in_ptr)
*/
const wchar_t* Translations::w_gettext(const wchar_t* original, const char* context)
{
return w_gettext( wide_to_utf8(original), context );
std::string in = StringUtils::wide_to_utf8(original);
return w_gettext(in.c_str(), context);
}
/**
@ -461,7 +438,7 @@ const wchar_t* Translations::w_gettext(const char* original, const char* context
if (original_t == original)
{
m_converted_string = utf8_to_wide(original);
m_converted_string = StringUtils::utf8_to_wide(original);
#if TRANSLATE_VERBOSE
std::wcout << L" translation : " << m_converted_string << std::endl;
@ -472,9 +449,10 @@ const wchar_t* Translations::w_gettext(const char* original, const char* context
// print
//for (int n=0;; n+=4)
wchar_t* original_tw = utf8_to_wide(original_t.c_str());
static core::stringw original_tw;
original_tw = StringUtils::utf8_to_wide(original_t.c_str());
wchar_t* out_ptr = original_tw;
const wchar_t* out_ptr = original_tw.c_str();
if (REMOVE_BOM) out_ptr++;
#if TRANSLATE_VERBOSE
@ -493,7 +471,9 @@ const wchar_t* Translations::w_gettext(const char* original, const char* context
*/
const wchar_t* Translations::w_ngettext(const wchar_t* singular, const wchar_t* plural, int num, const char* context)
{
return w_ngettext( wide_to_utf8(singular), wide_to_utf8(plural), num, context);
std::string in = StringUtils::wide_to_utf8(singular);
std::string in2 = StringUtils::wide_to_utf8(plural);
return w_ngettext(in.c_str(), in2.c_str(), num, context);
}
/**
@ -509,7 +489,9 @@ const wchar_t* Translations::w_ngettext(const char* singular, const char* plural
m_dictionary.translate_plural(singular, plural, num) :
m_dictionary.translate_ctxt_plural(context, singular, plural, num));
wchar_t* out_ptr = utf8_to_wide(res.c_str());
static core::stringw str_buffer;
str_buffer = StringUtils::utf8_to_wide(res.c_str());
const wchar_t* out_ptr = str_buffer.c_str();
if (REMOVE_BOM) out_ptr++;
#if TRANSLATE_VERBOSE