32#include "scriptstdstring/scriptstdstring.h"
33#include "scriptmath/scriptmath.h"
34#include "scriptmath3d/scriptmath3d.h"
35#include "scriptarray/scriptarray.h"
36#include "scriptdictionary/scriptdictionary.h"
37#include "scriptany/scriptany.h"
55using namespace AngelScript;
59# define assert_net(expr) ROR_ASSERT(expr)
76 return std::string(reg->
name);
102 for (std::map<std::string, callbackList>::iterator typeit =
callbacks.begin();
104 for (callbackList::iterator it = typeit->second.begin(); it != typeit->second.end(); ++it) {
108 typeit->second.clear();
114 if (scriptname.empty())
return 0;
120 r = builder.StartNewModule(
engine,
"script");
126 r = builder.AddSectionFromFile(scriptname.c_str());
132 r = builder.BuildModule();
134 if (r == asINVALID_CONFIGURATION)
137 else if (r == asERROR)
140 else if (r == asBUILD_IN_PROGRESS)
143 else if (r == asINIT_GLOBAL_VARS_FAILED)
145 "ScriptEngine: It was not possible to initialize at least one of the global variables.");
154 asIScriptModule *mod = builder.GetModule();
157 asIScriptFunction *func;
159 func = mod->GetFunctionByDecl(
"void frameStep(float)");
162 func = mod->GetFunctionByDecl(
"void playerDeleted(int, int)");
163 if (func)
addCallback(
"playerDeleted", func, NULL);
165 func = mod->GetFunctionByDecl(
"void playerAdded(int)");
168 func = mod->GetFunctionByDecl(
"int streamAdded(int, StreamRegister@)");
171 func = mod->GetFunctionByDecl(
"int playerChat(int, string msg)");
174 func = mod->GetFunctionByDecl(
"void gameCmd(int, string)");
177 func = mod->GetFunctionByDecl(
"void curlStatus(curlStatusType, int, int, string, string)");
186 func = mod->GetFunctionByDecl(
"void main()");
191 "ScriptEngine: The script must have the function 'void main()'. Please add it and try again.");
199 if (r != asEXECUTION_FINISHED) {
201 if (r == asEXECUTION_EXCEPTION) {
204 "ScriptEngine: An exception '%s' occurred. Please correct the code in file '%s' and try again.",
205 context->GetExceptionString(), scriptname.c_str());
220 asIScriptModule *mod =
engine->GetModule(
"script");
222 engine->DiscardModule(
"script");
230 const asIScriptFunction *function = ctx->GetExceptionFunction();
235 const char* sectName =
nullptr;
236 int col, line = ctx->GetExceptionLineNumber(&col, §Name);
243 for (asUINT n = 0; n < ctx->GetCallstackSize(); n++) {
244 function = ctx->GetFunction(n);
245 const char* fnDeclSectionName =
nullptr;
248 function->GetDeclaredAt(&fnDeclSectionName, &fnDeclRow, &fnDeclCol);
249 sprintf(tmp,
"%s (%d): %s", fnDeclSectionName, fnDeclRow,
250 function->GetDeclaration());
259 asIScriptEngine *
engine = ctx->GetEngine();
261 const char *sectionName;
262 int line = ctx->GetLineNumber(0, &col, §ionName);
263 int indent = ctx->GetCallstackSize();
264 for (
int n = 0; n < indent; n++)
265 sprintf(tmp + n,
" ");
266 const asIScriptFunction *function =
engine->GetFunctionById(0);
267 sprintf(tmp + indent,
"%s:%s:%s:%d,%d", function->GetModuleName(), sectionName,
268 function->GetDeclaration(),
278 asIScriptEngine *
engine = ctx->GetEngine();
281 int typeId = ctx->GetThisTypeId(stackLevel);
282 void *varPointer = ctx->GetThisPointer(stackLevel);
288 int numVars = ctx->GetVarCount(stackLevel);
289 for (
int n = 0; n < numVars; n++) {
291 const char* varName =
nullptr;
292 ctx->GetVar(n, stackLevel, &varName, &typeId);
293 void *varPointer = ctx->GetAddressOfVar(n, stackLevel);
294 if (typeId == asTYPEID_INT32) {
295 Logger::Log(
LOG_INFO,
" %s = %d", ctx->GetVarDeclaration(n, stackLevel), *(
int *) varPointer);
296 }
else if (typeId == asTYPEID_FLOAT) {
297 Logger::Log(
LOG_INFO,
" %s = %f", ctx->GetVarDeclaration(n, stackLevel), *(
float *) varPointer);
298 }
else if (typeId & asTYPEID_SCRIPTOBJECT) {
299 asIScriptObject *obj = (asIScriptObject *) varPointer;
304 }
else if (typeId ==
engine->GetTypeIdByDecl(
"string")) {
305 std::string *str = (std::string *) varPointer;
321 engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
329 if (result == asINVALID_ARG) {
331 "ScriptEngine: One of the arguments is incorrect, e.g. obj is null for a class method.");
333 }
else if (result == asNOT_SUPPORTED) {
345 RegisterStdString(
engine);
346 RegisterScriptArray(
engine,
348 RegisterStdStringUtils(
engine);
349 RegisterScriptMath3D(
engine);
350 RegisterScriptMath(
engine);
351 RegisterScriptDictionary(
engine);
353 RegisterScriptAny(
engine);
358 result =
engine->RegisterObjectType(
"ServerScriptClass",
sizeof(
ServerScript), asOBJ_REF | asOBJ_NOCOUNT);
360 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"void Log(const string &in)",
363 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"void say(const string &in, int uid, int type)",
366 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"void kick(int kuid, const string &in)",
369 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"void ban(int buid, const string &in)",
372 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"bool unban(int buid)", asMETHOD(
ServerScript, unban),
375 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"int cmd(int uid, string cmd)",
376 asMETHOD(
ServerScript, sendGameCommand), asCALL_THISCALL);
378 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"void curlRequestAsync(string url, string displayname)",
379 asMETHOD(
ServerScript, curlRequestAsync), asCALL_THISCALL);
382 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"int getNumClients()",
383 asMETHOD(
ServerScript, getNumClients), asCALL_THISCALL);
385 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string getUserName(int uid)",
388 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"void setUserName(int uid, const string &in)",
391 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string getUserAuth(int uid)",
394 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"int getUserAuthRaw(int uid)",
395 asMETHOD(
ServerScript, getUserAuthRaw), asCALL_THISCALL);
397 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"void setUserAuthRaw(int uid, int)",
398 asMETHOD(
ServerScript, setUserAuthRaw), asCALL_THISCALL);
400 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"int getUserColourNum(int uid)",
401 asMETHOD(
ServerScript, getUserColourNum), asCALL_THISCALL);
403 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"void setUserColourNum(int uid, int)",
404 asMETHOD(
ServerScript, setUserColourNum), asCALL_THISCALL);
406 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"void broadcastUserInfo(int)",
407 asMETHOD(
ServerScript, broadcastUserInfo), asCALL_THISCALL);
409 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string getUserToken(int uid)",
412 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string getUserVersion(int uid)",
413 asMETHOD(
ServerScript, getUserVersion), asCALL_THISCALL);
415 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string getUserIPAddress(int uid)",
416 asMETHOD(
ServerScript, getUserIPAddress), asCALL_THISCALL);
418 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string getServerTerrain()",
419 asMETHOD(
ServerScript, getServerTerrain), asCALL_THISCALL);
421 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"int getTime()", asMETHOD(
ServerScript, getTime),
424 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"int getStartTime()",
427 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
428 "void setCallback(const string &in, const string &in, ?&in)",
431 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
432 "void deleteCallback(const string &in, const string &in, ?&in)",
435 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"void throwException(const string &in)",
436 asMETHOD(
ServerScript, throwException), asCALL_THISCALL);
438 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string get_version()",
441 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string get_asVersion()",
442 asMETHOD(
ServerScript, get_asVersion), asCALL_THISCALL);
444 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string get_protocolVersion()",
445 asMETHOD(
ServerScript, get_protocolVersion), asCALL_THISCALL);
447 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"uint get_maxClients()",
448 asMETHOD(
ServerScript, get_maxClients), asCALL_THISCALL);
450 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string get_serverName()",
451 asMETHOD(
ServerScript, get_serverName), asCALL_THISCALL);
453 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string get_IPAddr()",
456 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"uint get_listenPort()",
457 asMETHOD(
ServerScript, get_listenPort), asCALL_THISCALL);
459 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"int get_serverMode()",
460 asMETHOD(
ServerScript, get_serverMode), asCALL_THISCALL);
462 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string get_owner()", asMETHOD(
ServerScript, get_owner),
465 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string get_website()",
468 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string get_ircServ()",
471 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"string get_voipServ()",
474 result =
engine->RegisterObjectMethod(
"ServerScriptClass",
"int rangeRandomInt(int, int)",
475 asMETHOD(
ServerScript, rangeRandomInt), asCALL_THISCALL);
478 result =
engine->RegisterGlobalProperty(
"ServerScriptClass server", serverscript);
483 asOBJ_REF | asOBJ_NOCOUNT);
485 result =
engine->RegisterObjectMethod(
"StreamRegister",
"string getName()",
488 result =
engine->RegisterObjectProperty(
"StreamRegister",
"int type",
491 result =
engine->RegisterObjectProperty(
"StreamRegister",
"int status",
494 result =
engine->RegisterObjectProperty(
"StreamRegister",
"int origin_sourceid",
497 result =
engine->RegisterObjectProperty(
"StreamRegister",
"int origin_streamid",
503 result =
engine->RegisterEnum(
"ServerType");
513 result =
engine->RegisterEnum(
"broadcastType");
527 result =
engine->RegisterEnum(
"authType");
542 result =
engine->RegisterEnumValue(
"authType",
"AUTH_ALL", 0xFFFFFFFF);
546 result =
engine->RegisterEnum(
"serverSayType");
550 result =
engine->RegisterEnumValue(
"serverSayType",
"FROM_HOST",
FROM_HOST);
552 result =
engine->RegisterEnumValue(
"serverSayType",
"FROM_MOTD",
FROM_MOTD);
554 result =
engine->RegisterEnumValue(
"serverSayType",
"FROM_RULES",
FROM_RULES);
558 result =
engine->RegisterEnum(
"curlStatusType");
572 result =
engine->RegisterGlobalProperty(
"const int TO_ALL", (
void *) &
TO_ALL);
580 const char *type =
"Error";
581 if (msg->type == asMSGTYPE_INFORMATION)
583 else if (msg->type == asMSGTYPE_WARNING)
586 Logger::Log(
LOG_INFO,
"ScriptEngine: %s (%d, %d): %s = %s", msg->section, msg->row, msg->col, type, msg->message);
600 for (
unsigned int i = 0; i < queue.size(); ++i) {
602 r =
context->Prepare(queue[i].func);
606 if (queue[i].obj != NULL) {
607 context->SetObject(queue[i].obj);
619 engine->GarbageCollect(asGC_ONE_STEP);
635 for (
unsigned int i = 0; i < queue.size(); ++i) {
637 r =
context->Prepare(queue[i].func);
641 if (queue[i].obj != NULL) {
642 context->SetObject(queue[i].obj);
648 context->SetArgDWord(1, crash);
670 for (
unsigned int i = 0; i < queue.size(); ++i) {
672 r =
context->Prepare(queue[i].func);
676 if (queue[i].obj != NULL) {
677 context->SetObject(queue[i].obj);
701 for (
unsigned int i = 0; i < queue.size(); ++i) {
703 r =
context->Prepare(queue[i].func);
707 if (queue[i].obj != NULL) {
708 context->SetObject(queue[i].obj);
714 context->SetArgObject(1, (
void *) reg);
718 if (r == asEXECUTION_FINISHED) {
719 int newRet =
context->GetReturnDWord();
741 for (
unsigned int i = 0; i < queue.size(); ++i) {
743 r =
context->Prepare(queue[i].func);
747 if (queue[i].obj != NULL) {
748 context->SetObject(queue[i].obj);
754 context->SetArgObject(1, (
void *) &msg);
758 if (r == asEXECUTION_FINISHED) {
759 int newRet =
context->GetReturnDWord();
780 for (
unsigned int i = 0; i < queue.size(); ++i) {
782 r =
context->Prepare(queue[i].func);
786 if (queue[i].obj != NULL) {
787 context->SetObject(queue[i].obj);
793 context->SetArgObject(1, (
void *) &cmd);
817 for (
unsigned int i = 0; i < queue.size(); ++i) {
819 r =
context->Prepare(queue[i].func);
823 if (queue[i].obj != NULL) {
824 context->SetObject(queue[i].obj);
829 context->SetArgDWord(0, (asDWORD)type);
830 context->SetArgDWord(1, (asDWORD)n1);
831 context->SetArgDWord(2, (asDWORD)n2);
832 context->SetArgObject(3, (
void*)&displayname);
833 context->SetArgObject(4, (
void*)&message);
893 context->SetException(message.c_str());
900 std::string funcDecl =
"";
901 if (type ==
"frameStep")
902 funcDecl =
"void " + _func +
"(float)";
903 else if (type ==
"playerChat")
904 funcDecl =
"int " + _func +
"(int, const string &in)";
905 else if (type ==
"gameCmd")
906 funcDecl =
"void " + _func +
"(int, const string &in)";
907 else if (type ==
"playerAdded")
908 funcDecl =
"void " + _func +
"(int)";
909 else if (type ==
"playerDeleted")
910 funcDecl =
"void " + _func +
"(int, int)";
911 else if (type ==
"streamAdded")
912 funcDecl =
"int " + _func +
"(int, StreamRegister@)";
913 else if (type ==
"curlStatus")
914 funcDecl =
"void " + _func +
"(curlStatusType, int, int, string, string)";
917 " does not exist! Possible type strings: 'frameStep', 'playerChat', 'gameCmd', 'playerAdded', 'playerDeleted', 'streamAdded'.");
921 asIScriptFunction *func;
924 asITypeInfo *objType = obj->GetObjectType();
925 func = objType->GetMethodByDecl(funcDecl.c_str());
928 func = objType->GetMethodByName(_func.c_str());
930 setException(
"Method '" + std::string(func->GetDeclaration(
false)) +
"' was found in '" +
931 objType->GetName() +
"' but the correct declaration is: '" + funcDecl +
"'.");
933 setException(
"Method '" + funcDecl +
"' was not found in '" + objType->GetName() +
"'.");
938 asIScriptModule *mod =
engine->GetModule(
"script");
939 func = mod->GetFunctionByDecl(funcDecl.c_str());
942 func = mod->GetFunctionByName(_func.c_str());
944 setException(
"Function '" + std::string(func->GetDeclaration(
false)) +
945 "' was found, but the correct declaration is: '" + funcDecl +
"'.");
947 setException(
"Function '" + funcDecl +
"' was not found.");
953 Logger::Log(
LOG_INFO,
"ScriptEngine: error: Function '" + std::string(func->GetDeclaration(
false)) +
954 "' is already a callback for '" + type +
"'.");
966 engine->AddRefScriptObject(obj, obj->GetObjectType());
976 if (type ==
"frameStep") {
982 std::string(func->GetDeclaration(
true)));
989 std::string funcDecl =
"";
990 if (type ==
"frameStep")
991 funcDecl =
"void " + _func +
"(float)";
992 else if (type ==
"playerChat")
993 funcDecl =
"int " + _func +
"(int, const string &in)";
994 else if (type ==
"gameCmd")
995 funcDecl =
"void " + _func +
"(int, const string &in)";
996 else if (type ==
"playerAdded")
997 funcDecl =
"void " + _func +
"(int)";
998 else if (type ==
"playerDeleted")
999 funcDecl =
"void " + _func +
"(int, int)";
1000 else if (type ==
"streamAdded")
1001 funcDecl =
"int " + _func +
"(int, StreamRegister@)";
1002 else if (type ==
"curlStatus")
1003 funcDecl =
"void " + _func +
"(curlStatusType, int, int, string, string)";
1006 " does not exist! Possible type strings: 'frameStep', 'playerChat', 'gameCmd', 'playerAdded', 'playerDeleted', 'streamAdded'.");
1011 asIScriptFunction *func;
1014 asITypeInfo *objType = obj->GetObjectType();
1015 func = objType->GetMethodByDecl(funcDecl.c_str());
1018 func = objType->GetMethodByName(_func.c_str());
1020 setException(
"Method '" + std::string(func->GetDeclaration(
false)) +
"' was found in '" +
1021 objType->GetName() +
"' but the correct declaration is: '" + funcDecl +
"'.");
1023 setException(
"Method '" + funcDecl +
"' was not found in '" + objType->GetName() +
"'.");
1029 asIScriptModule *mod =
engine->GetModule(
"script");
1030 func = mod->GetFunctionByDecl(funcDecl.c_str());
1033 func = mod->GetFunctionByName(_func.c_str());
1035 setException(
"Function '" + std::string(func->GetDeclaration(
false)) +
1036 "' was found, but the correct declaration is: '" + funcDecl +
"'.");
1038 setException(
"Function '" + funcDecl +
"' was not found.");
1049 for (callbackList::iterator it =
callbacks[type].begin(); it !=
callbacks[type].end(); ++it) {
1050 if (it->obj == obj && it->func == func) {
1053 std::string(func->GetDeclaration(
true)));
1055 engine->ReleaseScriptObject(obj, obj->GetObjectType());
1059 Logger::Log(
LOG_INFO,
"ScriptEngine: error: failed to remove callback: " + std::string(func->GetDeclaration(
true)));
1063 if (!
engine)
return false;
1065 for (callbackList::iterator it =
callbacks[type].begin(); it !=
callbacks[type].end(); ++it) {
1066 if (it->obj == obj && it->func == func)
#define ROR_ASSERT(_EXPR)
#define RGN_SERVER_SCRIPTS
std::string stream_register_get_name(RoRnet::StreamRegister *reg)
void SetResourceGroup(const Ogre::String &rg)
bool callbackExists(const std::string &type, AngelScript::asIScriptFunction *func, AngelScript::asIScriptObject *obj)
This checks if a script callback exists.
void init()
This function initialzies the engine and registeres all types.
void TimerThreadMain()
A loop that periodically the frameStep() script callback.
void deleteAllCallbacks()
Deletes all script callbacks.
AngelScript::asIScriptEngine * engine
instance of the scripting engine
void addCallback(const std::string &type, AngelScript::asIScriptFunction *func, AngelScript::asIScriptObject *obj)
Adds a script callback.
void playerDeleted(int uid, int crash=0)
void playerAdded(RoRnet::UserInfo &user)
void deleteCallback(const std::string &type, AngelScript::asIScriptFunction *func, AngelScript::asIScriptObject *obj)
Deletes a script callback.
ThreadState m_timer_thread_state
AngelScript::asIScriptContext * context
context in which all scripting happens
void curlStatus(ServerScriptCurlStatusType type, int n1, int n2, std::string displayname, std::string message)
Params n1, n2 and message depend on status type :
std::map< std::string, callbackList > callbacks
A map containing the script callbacks by type.
void setException(const std::string &message)
Sets an exception that aborts the currently running script and shows the exception in the log file.
void LineCallback(AngelScript::asIScriptContext *ctx, void *param)
unused
void addCallbackScript(const std::string &type, const std::string &func, AngelScript::asIScriptObject *obj)
This method checks and converts the parameters and then adds a script callback.
void gameCmd(int uid, const std::string &cmd)
ServerScriptSequencer * seq
int streamAdded(int uid, RoRnet::StreamRegister *reg)
int loadScript(std::string scriptName)
std::thread m_timer_thread
void ExceptionCallback(AngelScript::asIScriptContext *ctx, void *param)
This callback gets called when an exception occurs in the script.
ServerScriptEngine(ServerScriptSequencer *sequencer)
std::mutex m_timer_thread_mutex
void PrintVariables(AngelScript::asIScriptContext *ctx, int stackLevel)
This logs all variables and their values at the specified stack level.
int playerChat(int uid, std::string msg)
ThreadState GetTimerThreadState()
void msgCallback(const AngelScript::asSMessageInfo *msg)
This is the callback function that gets called when script error occur.
void deleteCallbackScript(const std::string &type, const std::string &_func, AngelScript::asIScriptObject *obj)
This method checks and converts the parameters and then deletes a script callback.
void EnsureTimerThreadRunning()
void frameStepScripts(float dt)
void Log(ServerLogLevel level, const char *format,...)
std::vector< rorserver_callback_t > callbackList
void RegisterScriptFile_Native(AngelScript::asIScriptEngine *engine)
ServerScriptCurlStatusType
@ CURL_STATUS_START
New CURL request started, n1/n2 both 0.
@ CURL_STATUS_INVALID
Should never be reported.
@ CURL_STATUS_SUCCESS
CURL request finished, n1 = CURL return code, n2 = HTTP result code, message = received payload.
@ CURL_STATUS_FAILURE
CURL request finished, n1 = CURL return code, n2 = HTTP result code, message = CURL error string.
@ CURL_STATUS_PROGRESS
Download in progress, n1 = bytes downloaded, n2 = total bytes.
@ AUTH_MOD
moderator status
@ AUTH_NONE
no authentication
@ AUTH_RANKED
ranked status
@ AUTH_ADMIN
admin on the server
This struct holds the information for a script callback.
AngelScript::asIScriptObject * obj
The object instance that will need to be used with the function.
AngelScript::asIScriptFunction * func
The function or method pointer that will be called.
< Sent from the client to server and vice versa, to broadcast a new stream
uint32_t uniqueid
user unique id