// // Created by koncord on 19.03.16. // #ifndef PLUGINSYSTEM3_SCRIPT_HPP #define PLUGINSYSTEM3_SCRIPT_HPP #include "Types.hpp" #include "SystemInterface.hpp" #include "ScriptFunction.hpp" #include "ScriptFunctions.hpp" #include "Language.hpp" #include #include #include #include class Script : private ScriptFunctions { // http://imgur.com/hU0N4EH private: Language *lang; enum { SCRIPT_CPP, SCRIPT_PAWN, SCRIPT_LUA }; template R GetScript(const char *name) { if (script_type == SCRIPT_CPP) { return SystemInterface(lang->GetInterface(), name).result; } else { return reinterpret_cast(lang->IsCallbackPresent(name)); } } int script_type; std::unordered_map> callbacks_; typedef std::vector> ScriptList; static ScriptList scripts; Script(const char *path); Script(const Script&) = delete; Script& operator=(const Script&) = delete; public: ~Script(); static void LoadScript(const char *script, const char* base); static void LoadScripts(char* scripts, const char* base); static void UnloadScripts(); static constexpr ScriptCallbackData const& CallBackData(const unsigned int I, const unsigned int N = 0) { return callbacks[N].index == I ? callbacks[N] : CallBackData(I, N + 1); } template using CallBackReturn = typename CharType::type; template static constexpr unsigned int CallbackIdentity(const char(&str)[N]) { return Utils::hash(str); } template static unsigned int Call(CallBackReturn& result, Args&&... args) { constexpr ScriptCallbackData const& data = CallBackData(I); static_assert(data.callback.matches(TypeString::type...>::value), "Wrong number or types of arguments"); unsigned int count = 0; for (auto& script : scripts) { if (!script->callbacks_.count(I)) script->callbacks_.emplace(I, script->GetScript>(data.name)); auto callback = script->callbacks_[I]; if (!callback) continue; LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Called function \"%s\"", data.name); if (script->script_type == SCRIPT_CPP) result = reinterpret_cast>>(callback)(std::forward(args)...); #if defined (ENABLE_PAWN) else if (script->script_type == SCRIPT_PAWN) { boost::any any = script->lang->Call(data.name, data.callback.types, B, std::forward(args)...); result = reinterpret_cast> ((int)boost::any_cast(any)); // TODO: WTF?! int?! } #endif #if defined (ENABLE_LUA) else if (script->script_type == SCRIPT_LUA) { boost::any any = script->lang->Call(data.name, data.callback.types, B, std::forward(args)...); result = static_cast>(boost::any_cast(any).cast>()); } #endif ++count; } return count; } template static unsigned int Call(Args&&... args) { constexpr ScriptCallbackData const& data = CallBackData(I); static_assert(data.callback.matches(TypeString::type...>::value), "Wrong number or types of arguments"); unsigned int count = 0; for (auto& script : scripts) { if (!script->callbacks_.count(I)) script->callbacks_.emplace(I, script->GetScript>(data.name)); auto callback = script->callbacks_[I]; if (!callback) continue; LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Called function \"%s\"", data.name); if (script->script_type == SCRIPT_CPP) reinterpret_cast>>(callback)(std::forward(args)...); #if defined (ENABLE_PAWN) else if (script->script_type == SCRIPT_PAWN) script->lang->Call(data.name, data.callback.types, B, std::forward(args)...); #endif #if defined (ENABLE_LUA) else if (script->script_type == SCRIPT_LUA) script->lang->Call(data.name, data.callback.types, B, std::forward(args)...); #endif ++count; } return count; } }; #endif //PLUGINSYSTEM3_SCRIPT_HPP