forked from mirror/openmw-tes3mp
[Server] Add timers support to Mono
This commit is contained in:
parent
4601884931
commit
f37c252dbe
6 changed files with 249 additions and 14 deletions
|
@ -26,6 +26,15 @@ Timer::Timer(lua_State *lua, ScriptFuncLua callback, long msec, const std::strin
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_MONO
|
||||||
|
Timer::Timer(MonoObject *callback, long msec, const std::string &def, std::vector<boost::any> args) : ScriptFunction(callback, 'v', def)
|
||||||
|
{
|
||||||
|
targetMsec = msec;
|
||||||
|
this->args = args;
|
||||||
|
end = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void Timer::Tick()
|
void Timer::Tick()
|
||||||
{
|
{
|
||||||
if (end)
|
if (end)
|
||||||
|
@ -93,6 +102,28 @@ int TimerAPI::CreateTimerLua(lua_State *lua, ScriptFuncLua callback, long msec,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_MONO)
|
||||||
|
int TimerAPI::CreateTimerMono(MonoObject *callback, long msec, const std::string& def, std::vector<boost::any> args)
|
||||||
|
{
|
||||||
|
int id = -1;
|
||||||
|
|
||||||
|
for (auto timer : timers)
|
||||||
|
{
|
||||||
|
if (timer.second != nullptr)
|
||||||
|
continue;
|
||||||
|
timer.second = new Timer(callback, msec, def, args);
|
||||||
|
id = timer.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == -1)
|
||||||
|
{
|
||||||
|
timers[pointer] = new Timer(callback, msec, def, args);
|
||||||
|
id = pointer;
|
||||||
|
pointer++;
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int TimerAPI::CreateTimer(ScriptFunc callback, long msec, const std::string &def, std::vector<boost::any> args)
|
int TimerAPI::CreateTimer(ScriptFunc callback, long msec, const std::string &def, std::vector<boost::any> args)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,10 @@
|
||||||
#include <Script/Script.hpp>
|
#include <Script/Script.hpp>
|
||||||
#include <Script/ScriptFunction.hpp>
|
#include <Script/ScriptFunction.hpp>
|
||||||
|
|
||||||
|
#ifdef ENABLE_MONO
|
||||||
|
#include <mono/metadata/object.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace mwmp
|
namespace mwmp
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -24,6 +28,9 @@ namespace mwmp
|
||||||
Timer(ScriptFunc callback, long msec, const std::string& def, std::vector<boost::any> args);
|
Timer(ScriptFunc callback, long msec, const std::string& def, std::vector<boost::any> args);
|
||||||
#if defined(ENABLE_LUA)
|
#if defined(ENABLE_LUA)
|
||||||
Timer(lua_State *lua, ScriptFuncLua callback, long msec, const std::string& def, std::vector<boost::any> args);
|
Timer(lua_State *lua, ScriptFuncLua callback, long msec, const std::string& def, std::vector<boost::any> args);
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_MONO
|
||||||
|
Timer(MonoObject *callback, long msec, const std::string& def, std::vector<boost::any> args);
|
||||||
#endif
|
#endif
|
||||||
void Tick();
|
void Tick();
|
||||||
|
|
||||||
|
@ -44,6 +51,9 @@ namespace mwmp
|
||||||
public:
|
public:
|
||||||
#if defined(ENABLE_LUA)
|
#if defined(ENABLE_LUA)
|
||||||
static int CreateTimerLua(lua_State *lua, ScriptFuncLua callback, long msec, const std::string& def, std::vector<boost::any> args);
|
static int CreateTimerLua(lua_State *lua, ScriptFuncLua callback, long msec, const std::string& def, std::vector<boost::any> args);
|
||||||
|
#endif
|
||||||
|
#if defined(ENABLE_MONO)
|
||||||
|
static int CreateTimerMono(MonoObject *callback, long msec, const std::string& def, std::vector<boost::any> args);
|
||||||
#endif
|
#endif
|
||||||
static int CreateTimer(ScriptFunc callback, long msec, const std::string& def, std::vector<boost::any> args);
|
static int CreateTimer(ScriptFunc callback, long msec, const std::string& def, std::vector<boost::any> args);
|
||||||
static void FreeTimer(int timerid);
|
static void FreeTimer(int timerid);
|
||||||
|
|
|
@ -4,13 +4,107 @@
|
||||||
|
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <mono/metadata/appdomain.h>
|
#include <mono/metadata/appdomain.h>
|
||||||
|
#include <mono/metadata/object-forward.h>
|
||||||
#include <mono/jit/jit.h>
|
#include <mono/jit/jit.h>
|
||||||
#include <mono/metadata/assembly.h>
|
#include <mono/metadata/assembly.h>
|
||||||
|
#include <mono/metadata/mono-config.h>
|
||||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||||
|
#include <apps/openmw-mp/Script/API/TimerAPI.hpp>
|
||||||
#include "LangMono.hpp"
|
#include "LangMono.hpp"
|
||||||
|
|
||||||
static MonoDomain *domain = nullptr; // shared domain
|
static MonoDomain *domain = nullptr; // shared domain
|
||||||
|
|
||||||
|
std::string monoStringToStdString(MonoString *monoString)
|
||||||
|
{
|
||||||
|
char *utf8 = mono_string_to_utf8(monoString);
|
||||||
|
std::string str = utf8;
|
||||||
|
mono_free(utf8);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T unbox(MonoObject *obj)
|
||||||
|
{
|
||||||
|
return *(T *) mono_object_unbox(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::any monoObjectToAny(MonoObject *obj)
|
||||||
|
{
|
||||||
|
|
||||||
|
MonoClass *klass = mono_object_get_class(obj);
|
||||||
|
MonoType *rawType = mono_class_get_type(klass);
|
||||||
|
|
||||||
|
switch ((MonoTypeEnum) mono_type_get_type(rawType))
|
||||||
|
{
|
||||||
|
case MONO_TYPE_END:
|
||||||
|
case MONO_TYPE_VOID:
|
||||||
|
break;
|
||||||
|
case MONO_TYPE_BOOLEAN:
|
||||||
|
return (bool) unbox<MonoBoolean>(obj);
|
||||||
|
case MONO_TYPE_CHAR:
|
||||||
|
return unbox<uint16_t>(obj);
|
||||||
|
case MONO_TYPE_I1:
|
||||||
|
return unbox<int8_t>(obj);
|
||||||
|
case MONO_TYPE_U1:
|
||||||
|
return unbox<uint8_t>(obj);
|
||||||
|
case MONO_TYPE_I2:
|
||||||
|
return unbox<int16_t>(obj);
|
||||||
|
case MONO_TYPE_U2:
|
||||||
|
return unbox<uint16_t>(obj);
|
||||||
|
case MONO_TYPE_I4:
|
||||||
|
return unbox<int32_t>(obj);
|
||||||
|
case MONO_TYPE_U4:
|
||||||
|
return unbox<uint32_t>(obj);
|
||||||
|
case MONO_TYPE_I8:
|
||||||
|
return unbox<int64_t>(obj);
|
||||||
|
case MONO_TYPE_U8:
|
||||||
|
return unbox<uint64_t>(obj);
|
||||||
|
case MONO_TYPE_R4:
|
||||||
|
return unbox<float>(obj);
|
||||||
|
case MONO_TYPE_R8:
|
||||||
|
return unbox<double>(obj);
|
||||||
|
case MONO_TYPE_STRING:
|
||||||
|
return monoStringToStdString((MonoString *) obj);
|
||||||
|
case MONO_TYPE_ARRAY:
|
||||||
|
case MONO_TYPE_SZARRAY:
|
||||||
|
{
|
||||||
|
MonoArrayType *arrayType = mono_type_get_array_type(rawType);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return boost::any();
|
||||||
|
}
|
||||||
|
return boost::any();
|
||||||
|
}
|
||||||
|
|
||||||
|
int LangMono::CreateTimerEx(MonoObject *delegate, long msec, MonoString *monoStr, MonoArray *monoArgs)
|
||||||
|
{
|
||||||
|
size_t argsLength = mono_array_length(monoArgs);
|
||||||
|
std::vector<boost::any> params (argsLength);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < argsLength; ++i)
|
||||||
|
params[i] = monoObjectToAny(mono_array_get(monoArgs, MonoObject*, i));
|
||||||
|
|
||||||
|
char *types = mono_string_to_utf8(monoStr);
|
||||||
|
int id = mwmp::TimerAPI::CreateTimerMono(delegate, msec, types, params);
|
||||||
|
mono_free(types);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LangMono::MakePublic(MonoObject *delegate, const char *name) noexcept
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MonoObject *LangMono::CallPublic(const char *name, MonoArray *args)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
lib_t LangMono::GetInterface()
|
lib_t LangMono::GetInterface()
|
||||||
{
|
{
|
||||||
|
@ -40,6 +134,9 @@ void LangMono::Init()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
domain = mono_jit_init("TES3MP Mono VM"); // will leak :P
|
domain = mono_jit_init("TES3MP Mono VM"); // will leak :P
|
||||||
|
mono_add_internal_call("TES3MPSharp.TES3MP::CreateTimerEx", (void*) &LangMono::CreateTimerEx);
|
||||||
|
mono_add_internal_call("TES3MPSharp.TES3MP::MakePublic", (void*) &LangMono::MakePublic);
|
||||||
|
mono_add_internal_call("TES3MPSharp.TES3MP::CallPublic", (void*) &LangMono::CallPublic);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MonoClass *> getInstanceClassList(MonoImage *image, const std::string &parentName)
|
std::vector<MonoClass *> getInstanceClassList(MonoImage *image, const std::string &parentName)
|
||||||
|
@ -109,8 +206,7 @@ boost::any LangMono::Call(const char *name, const char *argl, int buf, ...)
|
||||||
|
|
||||||
int n_args = (int) (strlen(argl));
|
int n_args = (int) (strlen(argl));
|
||||||
|
|
||||||
std::vector<void *> vec;
|
std::vector<void *> vec(n_args);
|
||||||
vec.reserve(n_args);
|
|
||||||
|
|
||||||
for (int index = 0; index < n_args; index++)
|
for (int index = 0; index < n_args; index++)
|
||||||
{
|
{
|
||||||
|
@ -119,48 +215,48 @@ boost::any LangMono::Call(const char *name, const char *argl, int buf, ...)
|
||||||
case 'i':
|
case 'i':
|
||||||
{
|
{
|
||||||
auto val = va_arg(vargs, unsigned int);
|
auto val = va_arg(vargs, unsigned int);
|
||||||
vec.push_back((void *) &val);
|
vec[index] = (void *) &val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'q':
|
case 'q':
|
||||||
{
|
{
|
||||||
auto val = va_arg(vargs, signed int);
|
auto val = va_arg(vargs, signed int);
|
||||||
vec.push_back((void *) &val);
|
vec[index] = (void *) &val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'l':
|
case 'l':
|
||||||
{
|
{
|
||||||
auto val = va_arg(vargs, unsigned long long);
|
auto val = va_arg(vargs, unsigned long long);
|
||||||
vec.push_back((void *) &val);
|
vec[index] = (void *) &val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'w':
|
case 'w':
|
||||||
{
|
{
|
||||||
auto val = va_arg(vargs, signed long long);
|
auto val = va_arg(vargs, signed long long);
|
||||||
vec.push_back((void *) &val);
|
vec[index] = (void *) &val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'f':
|
case 'f':
|
||||||
{
|
{
|
||||||
auto val = va_arg(vargs, double);
|
auto val = va_arg(vargs, double);
|
||||||
vec.push_back((void *) &val);
|
vec[index] = (void *) &val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'p':
|
case 'p':
|
||||||
{
|
{
|
||||||
auto val = va_arg(vargs, void*);
|
auto val = va_arg(vargs, void*);
|
||||||
vec.push_back((void *) &val);
|
vec[index] = (void *) &val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 's':
|
case 's':
|
||||||
{
|
{
|
||||||
vec.push_back(mono_string_new(mono_domain_get(), va_arg(vargs, const char*)));
|
vec[index] = (mono_string_new(mono_domain_get(), va_arg(vargs, const char*)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'b':
|
case 'b':
|
||||||
{
|
{
|
||||||
auto val = va_arg(vargs, int);
|
auto val = va_arg(vargs, int);
|
||||||
vec.push_back((void *) &val);
|
vec[index] = (void *) &val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,6 +278,9 @@ boost::any LangMono::Call(const char *name, const char *argl, int buf, ...)
|
||||||
methodsCache[{name, n_args}] = method;
|
methodsCache[{name, n_args}] = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (method == nullptr)
|
||||||
|
return boost::any();
|
||||||
|
|
||||||
MonoObject *ret = mono_runtime_invoke(method, instance->object, vec.data(), nullptr);
|
MonoObject *ret = mono_runtime_invoke(method, instance->object, vec.data(), nullptr);
|
||||||
if (ret)
|
if (ret)
|
||||||
return boost::any(mono_object_unbox(ret));
|
return boost::any(mono_object_unbox(ret));
|
||||||
|
|
|
@ -63,6 +63,10 @@ public:
|
||||||
virtual boost::any Call(const char *name, const char *argl, int buf, ...) override;
|
virtual boost::any Call(const char *name, const char *argl, int buf, ...) override;
|
||||||
virtual boost::any Call(const char *name, const char *argl, const std::vector<boost::any> &args) override;
|
virtual boost::any Call(const char *name, const char *argl, const std::vector<boost::any> &args) override;
|
||||||
|
|
||||||
|
static int CreateTimerEx(MonoObject *delegate, long msec, MonoString *monoStr, MonoArray *args);
|
||||||
|
static void MakePublic(MonoObject *delegate, const char *name) noexcept;
|
||||||
|
static MonoObject *CallPublic(const char *name, MonoArray *args);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Init();
|
void Init();
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,7 +24,12 @@ ScriptFunction::ScriptFunction(const ScriptFuncLua &fLua, lua_State *lua, char r
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if defined (ENABLE_MONO)
|
||||||
|
ScriptFunction::ScriptFunction(MonoObject *delegate, char ret_type, const std::string &def) :
|
||||||
|
fMono({delegate}), ret_type(ret_type), def(def), script_type(SCRIPT_MONO)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ScriptFunction::~ScriptFunction()
|
ScriptFunction::~ScriptFunction()
|
||||||
{
|
{
|
||||||
|
@ -36,7 +41,7 @@ ScriptFunction::~ScriptFunction()
|
||||||
|
|
||||||
boost::any ScriptFunction::Call(const vector<boost::any> &args)
|
boost::any ScriptFunction::Call(const vector<boost::any> &args)
|
||||||
{
|
{
|
||||||
boost::any result;
|
boost::any result = boost::any();
|
||||||
|
|
||||||
if (def.length() != args.size())
|
if (def.length() != args.size())
|
||||||
throw runtime_error("Script call: Number of arguments does not match definition");
|
throw runtime_error("Script call: Number of arguments does not match definition");
|
||||||
|
@ -61,13 +66,84 @@ boost::any ScriptFunction::Call(const vector<boost::any> &args)
|
||||||
result = boost::any_cast<luabridge::LuaRef>(any).cast<const char*>();
|
result = boost::any_cast<luabridge::LuaRef>(any).cast<const char*>();
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
result = boost::any();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw runtime_error("Lua call: Unknown return type" + ret_type);
|
throw runtime_error("Lua call: Unknown return type" + ret_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if defined (ENABLE_MONO)
|
||||||
|
else if (script_type == SCRIPT_MONO)
|
||||||
|
{
|
||||||
|
std::vector<void*> argList;
|
||||||
|
argList.resize(args.size());
|
||||||
|
|
||||||
|
for (int index = 0; index < args.size(); index++)
|
||||||
|
{
|
||||||
|
switch (def[index])
|
||||||
|
{
|
||||||
|
case 'i':
|
||||||
|
{
|
||||||
|
auto val = boost::any_cast<unsigned int>(args.at(index));
|
||||||
|
argList[index] = ((void *) &val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'q':
|
||||||
|
{
|
||||||
|
auto val = boost::any_cast<signed int>(args.at(index));
|
||||||
|
argList[index] = ((void *) &val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'l':
|
||||||
|
{
|
||||||
|
auto val = boost::any_cast<unsigned long long>(args.at(index));
|
||||||
|
argList[index] = ((void *) &val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'w':
|
||||||
|
{
|
||||||
|
auto val = boost::any_cast<signed long long>(args.at(index));
|
||||||
|
argList[index] = ((void *) &val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'f':
|
||||||
|
{
|
||||||
|
auto val = boost::any_cast<double>(args.at(index));
|
||||||
|
argList[index] = ((void *) &val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'p':
|
||||||
|
{
|
||||||
|
auto val = boost::any_cast<void *>(args.at(index));
|
||||||
|
argList[index] = ((void *) &val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's':
|
||||||
|
{
|
||||||
|
if (args.at(index).type() == typeid(std::string)) // mono to mono call
|
||||||
|
argList[index] = mono_string_new(mono_domain_get(), boost::any_cast<std::string>(args.at(index)).c_str());
|
||||||
|
else // lua to mono
|
||||||
|
argList[index] = mono_string_new(mono_domain_get(), boost::any_cast<const char *>(args.at(index)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'b':
|
||||||
|
{
|
||||||
|
auto val = boost::any_cast<int>(args.at(index));
|
||||||
|
argList[index] = ((void *) &val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("Call: Unknown argument identifier " + def[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MonoObject *monoRet = mono_runtime_delegate_invoke(fMono.delegate, argList.data(), NULL);
|
||||||
|
if (monoRet != nullptr)
|
||||||
|
result = mono_object_unbox(monoRet); // todo cast
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,11 @@
|
||||||
#include "LangLua/LangLua.hpp"
|
#include "LangLua/LangLua.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined (ENABLE_MONO)
|
||||||
|
#include <mono/metadata/object.h>
|
||||||
|
#include <mono/metadata/appdomain.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef unsigned long long(*ScriptFunc)();
|
typedef unsigned long long(*ScriptFunc)();
|
||||||
#if defined (ENABLE_LUA)
|
#if defined (ENABLE_LUA)
|
||||||
typedef std::string ScriptFuncLua;
|
typedef std::string ScriptFuncLua;
|
||||||
|
@ -29,6 +34,12 @@ protected:
|
||||||
lua_State *lua;
|
lua_State *lua;
|
||||||
ScriptFuncLua name;
|
ScriptFuncLua name;
|
||||||
} fLua;
|
} fLua;
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_MONO
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
MonoObject *delegate;
|
||||||
|
} fMono;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,12 +50,16 @@ protected:
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
SCRIPT_CPP,
|
SCRIPT_CPP,
|
||||||
SCRIPT_LUA
|
SCRIPT_LUA,
|
||||||
|
SCRIPT_MONO
|
||||||
};
|
};
|
||||||
|
|
||||||
ScriptFunction(ScriptFunc fCpp, char ret_type, const std::string &def);
|
ScriptFunction(ScriptFunc fCpp, char ret_type, const std::string &def);
|
||||||
#if defined (ENABLE_LUA)
|
#if defined (ENABLE_LUA)
|
||||||
ScriptFunction(const ScriptFuncLua &fPawn, lua_State *lua, char ret_type, const std::string &def);
|
ScriptFunction(const ScriptFuncLua &fPawn, lua_State *lua, char ret_type, const std::string &def);
|
||||||
|
#endif
|
||||||
|
#if defined (ENABLE_MONO)
|
||||||
|
ScriptFunction(MonoObject *delegate, char ret_type, const std::string &def);
|
||||||
#endif
|
#endif
|
||||||
virtual ~ScriptFunction();
|
virtual ~ScriptFunction();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue