#pragma once #include #include #include #include #include #include "CFunctionBase.h" #include "CSwitchable.h" #include "CFunction.h" #include "CLuaFunction.h" #include "CScriptObjectBase.h" #include "U_SafeLuaCall.h" class CSmartCallback; using CSmartCallbackPtr = std::shared_ptr; class CCallbackHandlerBase : public virtual CSwitchable, public CScriptObjectBase { public: virtual ~CCallbackHandlerBase(); void RegisterCallback(CSmartCallback* callback); void UnregisterCallback(CSmartCallback* callback); virtual sol::object CallFromLua(sol::variadic_args va, sol::state_view s) = 0; virtual std::shared_ptr GetLastFunctionHandleShared() = 0; virtual CSmartCallbackPtr AddLuaFunction(sol::function func, sol::object name) = 0; virtual sol::object CallLua(sol::variadic_args va, sol::this_state s) = 0; DEFINE_SOL_USERTYPE(); virtual void m_deleteFunction(void* ptr) = 0; virtual void DeleteFunctionAtIndex(size_t index) = 0; virtual void DeleteFunctionsByName(const std::string& name) = 0; private: std::vector callbacks; }; class CSmartCallback : public CScriptObjectBase, public std::enable_shared_from_this { public: CSmartCallback() = delete; CSmartCallback(CCallbackHandlerBase& _handler, void* _func); ~CSmartCallback(); void Invalidate(); void ForceDelete(); bool IsValid() const; bool V_ScriptInit(std::shared_ptr state, sol::table table) override; CCallbackHandlerBase& Handler; void* FunctionPointer = nullptr; private: void m_InitiateDeletion(); }; template class CCallbackHandler : public CCallbackHandlerBase //TODO add CallByName { public: //out - CPP to LUA //in - LUA TO CPP using CLuaArgsOutTransformer = CLuaFunction::CustomOutCallerFunction; using CLuaArgsInTransformer = CFunctionBase::CustomInCallerFunction; CCallbackHandler() = default; CCallbackHandler(CCallbackHandler&&) noexcept = default; CCallbackHandler& operator=(CCallbackHandler&&) noexcept = default; CCallbackHandler(const CCallbackHandler&) = delete; CCallbackHandler& operator=(const CCallbackHandler&) = delete; ~CCallbackHandler() { for (auto& func : Functions) { CLuaFunction* luafunc = dynamic_cast*>(func.get()); if(luafunc) { std::wcout << L"detected lua func at deleting CCallbackHandler\n"; continue; } } } using FuncType = CFunctionBase; using FuncTypeUniquePtr = std::unique_ptr; using FuncTypeRawPtr = FuncType*; using ReturnType = Ret; using ReturnsVector = typename std::conditional::value, std::vector, std::vector>::type; CSmartCallbackPtr AddLuaFunction(sol::function func, sol::object name) override { Add(std::make_unique>(func)); std::string nm; if(name.valid() && name.is()) { nm = name.as(); if(!nm.empty()) { Functions.back()->SetName(nm); } } return GetLastFunctionHandleShared(); } sol::object CallLua(sol::variadic_args va, sol::this_state s) override { return CallFromLua(va, s); } bool V_ScriptInit(std::shared_ptr _state, sol::table table) override //TODO __call { table.set_function("add", [this](sol::function func, sol::object name) -> sol::table { Add(std::make_unique>(func)); std::string nm; if(name.valid() && name.is()) { nm = name.as(); if(!nm.empty()) { Functions.back()->SetName(nm); } } sol::table tabl = sol::state_view(func.lua_state()).create_table(); FuncTypeRawPtr ptr = Functions.back().get(); tabl.set_function("delete", [this, ptr]() mutable { if(!ptr) { return; } DeleteFunction(ptr); ptr = nullptr; }); tabl.set_function("getSmartDeleter", [this, ptr](sol::this_state ts) mutable { auto obj = GetFunctionHandleShared(ptr); auto ret = obj->GetScriptTable(ts); ret["__obj"] = obj; return ret; }); tabl.set("name", nm); tabl.set("__ptr", ptr); return tabl; }); table.set_function("call", [this](sol::variadic_args va, sol::this_state s) -> sol::object { return CallFromLua(va, s); }); table.set_function("isEnabled", [this](sol::this_state s) -> bool { return IsEnabled(); }); table.set_function("setState", [this](bool state, sol::this_state s) -> void { return SetEnabledState(state); }); table.set_function("delete", [this](sol::object obj, sol::this_state s) -> void { if(!obj.valid()) { return; } if(obj.is()) { sol::table tabl = obj.as(); sol::object del_obj = tabl["delete"]; if(del_obj.valid() && del_obj.is()) { sol::function del_func = del_obj.as(); SafeCallLua(del_func); //del_func(); } } else if(obj.is()) { std::string nm = obj.as(); DeleteFunctionsByName(nm); } }); table.set_function("getLastFunctionSmartDeleter", [this](sol::this_state ts) -> sol::object { auto obj = GetLastFunctionHandleShared(); auto ret = obj->GetScriptTable(ts); ret["__obj"] = obj; return ret; }); return true; } CCallbackHandler& operator+=(FuncTypeUniquePtr&& func) { Add(std::move(func)); return *this; } FuncTypeRawPtr Add(FuncTypeUniquePtr&& func) { Functions.push_back(std::move(func)); SetupSingleFunctionTransformers(Functions.back()); return Functions.back().get(); } bool IsEmpty() const { return Functions.empty(); } operator bool() const { return !Functions.empty(); } void operator()(Args... args) const { return Call(args...); } void Call(Args... args) const { if (!IsEnabled()) { return; } for (auto& func : Functions) { (*func)(args...); } } sol::object CallFromLua(sol::variadic_args va, sol::state_view s) override { if (!IsEnabled()) { return sol::lua_nil; } if constexpr (std::is_same_v) { for (auto& func : Functions) { func->CallFromLua(va, s); } return sol::lua_nil; } else { size_t index = 1; sol::table ret = s.create_table(); for (auto& func : Functions) { ret[index] = func->CallFromLua(va, s); index++; } return ret; } } ReturnsVector CallWithReturns(Args... args) const { if (!IsEnabled()) { return ReturnsVector(); } ReturnsVector ret; if constexpr (std::is_void_v) { ret.resize(Functions.size()); std::fill(ret.begin(), ret.end(), int(0)); for (auto& func : Functions) { (*func)(args...); } return ret; } else { ret.reserve(Functions.size()); for (auto& func : Functions) { Ret result = (*func)(args...); ret.push_back(result); } return ret; } } CFunction* AddFunction(const std::function& func) { Functions.push_back(std::make_unique>(func)); SetupSingleFunctionTransformers(Functions.back()); return dynamic_cast*>(Functions.back().get()); } CLuaFunction* AddLuaFunction(const sol::protected_function& func) { Add(std::make_unique>(func)); return dynamic_cast*>(Functions.back().get()); } CLuaFunction* AddLuaFunction(std::unique_ptr>&& func) { return dynamic_cast*>(Add(func)); } CCallbackHandler& operator+=(const std::function& func) { AddFunction(func); return *this; } CCallbackHandler& operator+=(const sol::protected_function& func) { AddLuaFunction(func); return *this; } bool IsEmpty() { return Functions.empty(); } void SetupLuaTransformers(const CLuaArgsOutTransformer& outtransform, const CLuaArgsInTransformer& intransform) { LuaArgsOutTransformer = std::make_unique(outtransform); LuaArgsInTransformer = std::make_unique(intransform); for(auto& func : Functions) { SetupSingleFunctionTransformers(func); } } size_t GetCount() { return Functions.size(); } size_t GetLastIndex() { if(IsEmpty()) { return 0; } return GetCount() - 1; } CSmartCallback GetLastFunctionHandle() { return CSmartCallback(*this, Functions.empty() ? nullptr : Functions.back().get()); } std::shared_ptr GetLastFunctionHandleShared() override { return std::make_shared(*this, Functions.empty() ? nullptr : Functions.back().get()); } std::unique_ptr GetLastFunctionHandleUnique() { return std::make_unique(*this, Functions.empty() ? nullptr : Functions.back().get()); } CSmartCallback GetFunctionHandle(FuncTypeRawPtr rawptr) { auto it = std::find_if(Functions.begin(), Functions.end(), [rawptr](auto& func) -> bool { return func.get() == rawptr; }); return CSmartCallback(*this, (it == Functions.end()) ? nullptr : (*it).get()); } std::shared_ptr GetFunctionHandleShared(FuncTypeRawPtr rawptr) { auto it = std::find_if(Functions.begin(), Functions.end(), [rawptr](auto& func) -> bool { return func.get() == rawptr; }); return std::make_shared(*this, (it == Functions.end()) ? nullptr : (*it).get()); } std::unique_ptr GetFunctionHandleUnique(FuncTypeRawPtr rawptr) { auto it = std::find_if(Functions.begin(), Functions.end(), [rawptr](auto& func) -> bool { return func.get() == rawptr; }); return std::make_unique(*this, (it == Functions.end()) ? nullptr : (*it).get()); } FuncTypeUniquePtr& GetLastFunction() { if(IsEmpty()) { throw std::runtime_error("No functions"); } return Functions.back(); } FuncTypeRawPtr GetLastFunctionRaw() { if(IsEmpty()) { return nullptr; } return Functions.back().get(); } void DeleteFunctionAtIndex(size_t index) override { if(index >= Functions.size()) { return; } Functions.erase(Functions.begin() + index); } void DeleteFunction(FuncTypeUniquePtr& smrptr) { auto it = std::find_if(Functions.begin(), Functions.end(), [&smrptr](auto& myptr) -> bool { return smrptr == myptr; }); if(it == Functions.end()) { return; } Functions.erase(it); } void DeleteFunction(FuncTypeRawPtr ptr) { auto it = std::find_if(Functions.begin(), Functions.end(), [ptr](auto& myptr) -> bool { return ptr == myptr.get(); }); if(it == Functions.end()) { return; } Functions.erase(it); } void m_deleteFunction(void* ptr) override { auto it = std::find_if(Functions.begin(), Functions.end(), [ptr](auto& myptr) -> bool { return ptr == static_cast(myptr.get()); }); if(it == Functions.end()) { return; } Functions.erase(it); } void DeleteFunctionsByName(const std::string& name) override { if(name.empty()) { return; } std::erase_if(Functions, [&name](auto& ptr) -> bool { return ptr->HasName() && ptr->GetName() == name; }); } std::vector Functions; private: void SetupSingleFunctionTransformers(FuncTypeUniquePtr& func) { CLuaFunction* luafunc = dynamic_cast*>(func.get()); if(luafunc && LuaArgsOutTransformer) { luafunc->MakeCustomOutCaller(*LuaArgsOutTransformer); } if(LuaArgsInTransformer) { func->MakeCustomInCaller(*LuaArgsInTransformer); } } std::unique_ptr LuaArgsOutTransformer; std::unique_ptr LuaArgsInTransformer; };