#pragma once #include #include #include #include namespace fxn { inline constexpr char ToLower(const char c) noexcept { return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c; } inline constexpr unsigned int HashString(std::string_view str) noexcept { uint32_t hash = 0; for (char ch : str) { hash += ToLower(ch); hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return hash; } class NativeInvoker { public: static NativeInvoker& GetInstance(); static void AddTickEvent(const std::function& callback); public: void Initialize(); public: /** * @brief Invokes the native on current thread * @note MAYBE UNSAFE IF NOT ON GAME THREAD * @param hash native hash to invoke * @param context native context to use * @return whether the native could be found and executed */ bool Invoke(fxn::NativeContext* context); /** * @brief Invokes the native on a special game thread * @param hash native hash to invoke * @param context native context to use * @return whether the native could be found and executed */ bool Schedule(fxn::NativeContext* context, bool waitForCompletion = true); public: template R Invoke(std::uint64_t hash, Args&&... args) { fxn::NativeContext context { hash }; (context.PushArgument(std::forward(args)), ...); Invoke(&context); if constexpr (!std::is_same_v) { return context.GetResult(); } } template R Schedule(std::uint64_t hash, Args&&... args) { fxn::NativeContext context { hash }; (context.PushArgument(std::forward(args)), ...); Schedule(&context, true); if constexpr (!std::is_same_v) { return context.GetResult(); } } public: void HookNative(std::uint64_t hash, std::function hook); }; }