mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-01 15:26:59 +00:00
start integrating lua with the rest
This commit is contained in:
parent
43429eadb3
commit
931d94b7d8
@ -6,6 +6,7 @@
|
|||||||
#include <boost/asio/deadline_timer.hpp>
|
#include <boost/asio/deadline_timer.hpp>
|
||||||
#include <boost/asio/io_context.hpp>
|
#include <boost/asio/io_context.hpp>
|
||||||
#include <boost/date_time/posix_time/posix_time_duration.hpp>
|
#include <boost/date_time/posix_time/posix_time_duration.hpp>
|
||||||
|
#include <boost/signals2.hpp>
|
||||||
#include <boost/system/detail/error_code.hpp>
|
#include <boost/system/detail/error_code.hpp>
|
||||||
#include <boost/thread/scoped_thread.hpp>
|
#include <boost/thread/scoped_thread.hpp>
|
||||||
#include <boost/thread/synchronized_value.hpp>
|
#include <boost/thread/synchronized_value.hpp>
|
||||||
@ -45,6 +46,8 @@ public:
|
|||||||
/// FileWatcher::sig_file_changed is triggered.
|
/// FileWatcher::sig_file_changed is triggered.
|
||||||
void watch_files_in(const std::filesystem::path& dir);
|
void watch_files_in(const std::filesystem::path& dir);
|
||||||
|
|
||||||
|
boost::signals2::signal<void(const std::filesystem::path&)> sig_file_changed {};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Entry point for the timer thread.
|
/// Entry point for the timer thread.
|
||||||
void thread_main();
|
void thread_main();
|
||||||
@ -87,4 +90,3 @@ private:
|
|||||||
/// Thread on which all watching and timing work runs.
|
/// Thread on which all watching and timing work runs.
|
||||||
boost::scoped_thread<> m_thread;
|
boost::scoped_thread<> m_thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <boost/asio/io_service.hpp>
|
#include <boost/asio/io_service.hpp>
|
||||||
#include <boost/asio/post.hpp>
|
#include <boost/asio/post.hpp>
|
||||||
#include <boost/date_time/posix_time/posix_time_duration.hpp>
|
#include <boost/date_time/posix_time/posix_time_duration.hpp>
|
||||||
|
#include <boost/signals2.hpp>
|
||||||
#include <boost/thread/scoped_thread.hpp>
|
#include <boost/thread/scoped_thread.hpp>
|
||||||
#include <boost/thread/synchronized_value.hpp>
|
#include <boost/thread/synchronized_value.hpp>
|
||||||
#include <sol/forward.hpp>
|
#include <sol/forward.hpp>
|
||||||
@ -24,6 +25,8 @@ struct Timer {
|
|||||||
boost::posix_time::milliseconds interval;
|
boost::posix_time::milliseconds interval;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr const char* BEAMMP_MEMORY_STATE = ":console:";
|
||||||
|
|
||||||
class LuaPlugin : public Plugin {
|
class LuaPlugin : public Plugin {
|
||||||
public:
|
public:
|
||||||
/// Declare a new plugin with the path.
|
/// Declare a new plugin with the path.
|
||||||
@ -46,6 +49,10 @@ public:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Dangerous: Only use this on a special memory state.
|
||||||
|
/// Results are *printed to stdout*.
|
||||||
|
void run_raw_lua(const std::string& raw);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Initializes the error handlers for panic and exceptions.
|
/// Initializes the error handlers for panic and exceptions.
|
||||||
Error initialize_error_handlers();
|
Error initialize_error_handlers();
|
||||||
@ -117,6 +124,8 @@ private:
|
|||||||
|
|
||||||
FileWatcher m_extensions_watcher { 2 };
|
FileWatcher m_extensions_watcher { 2 };
|
||||||
|
|
||||||
|
boost::signals2::connection m_extensions_watch_conn;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Timer>> m_timers {};
|
std::vector<std::shared_ptr<Timer>> m_timers {};
|
||||||
|
|
||||||
std::shared_ptr<Timer> make_timer(size_t ms);
|
std::shared_ptr<Timer> make_timer(size_t ms);
|
||||||
@ -131,5 +140,5 @@ private:
|
|||||||
void l_mp_schedule_call_helper(const boost::system::error_code& err, std::shared_ptr<Timer> timer, const sol::function& fn, std::shared_ptr<ValueTuple> args);
|
void l_mp_schedule_call_helper(const boost::system::error_code& err, std::shared_ptr<Timer> timer, const sol::function& fn, std::shared_ptr<ValueTuple> args);
|
||||||
void l_mp_schedule_call_once(size_t ms, const sol::function& fn, sol::variadic_args args);
|
void l_mp_schedule_call_once(size_t ms, const sol::function& fn, sol::variadic_args args);
|
||||||
|
|
||||||
std::string print_impl(const sol::variadic_args&);
|
std::string print_impl(const std::vector<sol::object>&);
|
||||||
};
|
};
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
class Plugin {
|
class Plugin {
|
||||||
public:
|
public:
|
||||||
/// Self-managing pointer type of this plugin.
|
/// Self-managing pointer type of this plugin.
|
||||||
using Pointer = std::unique_ptr<Plugin>;
|
using Pointer = std::shared_ptr<Plugin>;
|
||||||
/// Allocates a Plugin of the specific derived plugin type.
|
/// Allocates a Plugin of the specific derived plugin type.
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
static Pointer make_pointer(Args&&... args) {
|
static Pointer make_pointer(Args&&... args) {
|
||||||
return std::unique_ptr<Plugin>(new T(std::forward<Args>(args)...));
|
return std::shared_ptr<Plugin>(new T(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default constructor to enable derived classes to default-construct.
|
/// Default constructor to enable derived classes to default-construct.
|
||||||
|
@ -48,7 +48,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the plugin, calls Plugin::initialize(), and so on
|
/// Adds the plugin, calls Plugin::initialize(), and so on
|
||||||
[[nodiscard]] Error add_plugin(Plugin::Pointer&& plugin) {
|
[[nodiscard]] Error add_plugin(Plugin::Pointer plugin) {
|
||||||
auto plugins = m_plugins.synchronize();
|
auto plugins = m_plugins.synchronize();
|
||||||
if (plugins->contains(plugin->name())) {
|
if (plugins->contains(plugin->name())) {
|
||||||
return Error("Plugin with the name '{}' already exists, refusing to replace it.", plugin->name());
|
return Error("Plugin with the name '{}' already exists, refusing to replace it.", plugin->name());
|
||||||
@ -63,6 +63,10 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashMap<std::string, Plugin::Pointer> get_plugins() {
|
||||||
|
return *m_plugins;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// All plugins as pointers to allow inheritance.
|
/// All plugins as pointers to allow inheritance.
|
||||||
SynchronizedHashMap<std::string, Plugin::Pointer> m_plugins;
|
SynchronizedHashMap<std::string, Plugin::Pointer> m_plugins;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Cryptography.h"
|
#include "Cryptography.h"
|
||||||
|
#include "LuaPlugin.h"
|
||||||
#include "TScopedTimer.h"
|
#include "TScopedTimer.h"
|
||||||
#include "commandline.h"
|
#include "commandline.h"
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@ -82,7 +83,7 @@ private:
|
|||||||
bool mIsLuaConsole { false };
|
bool mIsLuaConsole { false };
|
||||||
bool mFirstTime { true };
|
bool mFirstTime { true };
|
||||||
std::string mStateId;
|
std::string mStateId;
|
||||||
const std::string mDefaultStateId = "BEAMMP_SERVER_CONSOLE";
|
const std::string mDefaultStateId = BEAMMP_MEMORY_STATE;
|
||||||
std::ofstream mLogFileStream;
|
std::ofstream mLogFileStream;
|
||||||
std::mutex mLogFileStreamMtx;
|
std::mutex mLogFileStreamMtx;
|
||||||
TScopedTimer mUptimeTimer{};
|
TScopedTimer mUptimeTimer{};
|
||||||
|
@ -265,5 +265,5 @@ private:
|
|||||||
/// "invalid provider" means "provider of values for invalid sol values". If nullptr, then
|
/// "invalid provider" means "provider of values for invalid sol values". If nullptr, then
|
||||||
/// any invalid value (such as a function) will be resolved to an error instead and the function will
|
/// any invalid value (such as a function) will be resolved to an error instead and the function will
|
||||||
/// fail.
|
/// fail.
|
||||||
Result<Value> sol_obj_to_value(const sol::object&, const std::function<Result<Value>(const sol::object&)>& invalid_provider = nullptr, size_t max_depth = 500);
|
Result<Value> sol_obj_to_value(const sol::object&, const std::function<Result<Value>(const sol::object&)>& invalid_provider = nullptr, size_t max_depth = 50);
|
||||||
|
|
||||||
|
@ -93,9 +93,9 @@ void FileWatcher::check_file(const std::filesystem::path& file) {
|
|||||||
} else {
|
} else {
|
||||||
if (m_file_mod_times.at(file) != time) {
|
if (m_file_mod_times.at(file) != time) {
|
||||||
beammp_tracef("File changed: {}", file);
|
beammp_tracef("File changed: {}", file);
|
||||||
|
sig_file_changed(file);;
|
||||||
m_file_mod_times.at(file) = time;
|
m_file_mod_times.at(file) = time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,19 +113,19 @@ Error LuaPlugin::initialize_libraries() {
|
|||||||
glob["MP"]["GetStateMemoryUsage"] = [this]() { return size_t(m_state.memory_used()); };
|
glob["MP"]["GetStateMemoryUsage"] = [this]() { return size_t(m_state.memory_used()); };
|
||||||
glob["MP"]["GetPluginMemoryUsage"] = [this] { return memory_usage(); };
|
glob["MP"]["GetPluginMemoryUsage"] = [this] { return memory_usage(); };
|
||||||
glob["MP"]["LogError"] = [this](const sol::variadic_args& args) {
|
glob["MP"]["LogError"] = [this](const sol::variadic_args& args) {
|
||||||
auto result = print_impl(args);
|
auto result = print_impl({ args.begin(), args.end() });
|
||||||
beammp_lua_errorf("[out] {}", result);
|
beammp_lua_errorf("[out] {}", result);
|
||||||
};
|
};
|
||||||
glob["MP"]["LogWarn"] = [this](const sol::variadic_args& args) {
|
glob["MP"]["LogWarn"] = [this](const sol::variadic_args& args) {
|
||||||
auto result = print_impl(args);
|
auto result = print_impl({ args.begin(), args.end() });
|
||||||
beammp_lua_warnf("[out] {}", result);
|
beammp_lua_warnf("[out] {}", result);
|
||||||
};
|
};
|
||||||
glob["MP"]["LogInfo"] = [this](const sol::variadic_args& args) {
|
glob["MP"]["LogInfo"] = [this](const sol::variadic_args& args) {
|
||||||
auto result = print_impl(args);
|
auto result = print_impl({ args.begin(), args.end() });
|
||||||
beammp_lua_infof("[out] {}", result);
|
beammp_lua_infof("[out] {}", result);
|
||||||
};
|
};
|
||||||
glob["MP"]["LogDebug"] = [this](const sol::variadic_args& args) {
|
glob["MP"]["LogDebug"] = [this](const sol::variadic_args& args) {
|
||||||
auto result = print_impl(args);
|
auto result = print_impl({ args.begin(), args.end() });
|
||||||
beammp_lua_debugf("[out] {}", result);
|
beammp_lua_debugf("[out] {}", result);
|
||||||
};
|
};
|
||||||
glob["MP"]["GetPluginPath"] = [this] {
|
glob["MP"]["GetPluginPath"] = [this] {
|
||||||
@ -256,9 +256,7 @@ Error LuaPlugin::load_files() {
|
|||||||
m_extensions_watcher.watch_files_in(extensions_folder);
|
m_extensions_watcher.watch_files_in(extensions_folder);
|
||||||
// set up callback for when an extension changes.
|
// set up callback for when an extension changes.
|
||||||
// we simply reload the extension as if nothing happened :)
|
// we simply reload the extension as if nothing happened :)
|
||||||
// TODO
|
m_extensions_watch_conn = m_extensions_watcher.sig_file_changed.connect(
|
||||||
/*
|
|
||||||
m_extensions_watch_conn = m_extensions_watcher.sig_file_changed.connect_scoped(
|
|
||||||
[this, extensions_folder](const std::filesystem::path& path) {
|
[this, extensions_folder](const std::filesystem::path& path) {
|
||||||
if (path.extension() != ".lua") {
|
if (path.extension() != ".lua") {
|
||||||
return; // ignore
|
return; // ignore
|
||||||
@ -272,23 +270,24 @@ Error LuaPlugin::load_files() {
|
|||||||
load_extension(path, rel);
|
load_extension(path, rel);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
} else {
|
} else {
|
||||||
beammp_lua_debugf("Plugin '{}' has no extensions.", name());
|
beammp_lua_debugf("Plugin '{}' has no extensions.", name());
|
||||||
}
|
}
|
||||||
auto main_lua = m_path / "main.lua";
|
if (m_path != BEAMMP_MEMORY_STATE) {
|
||||||
if (std::filesystem::exists(main_lua)) {
|
auto main_lua = m_path / "main.lua";
|
||||||
// TODO: Check that it's a regular file or symlink
|
if (std::filesystem::exists(main_lua)) {
|
||||||
beammp_lua_debugf("Found main.lua: {}", main_lua.string());
|
// TODO: Check that it's a regular file or symlink
|
||||||
boost::asio::post(m_io, [this, main_lua] {
|
beammp_lua_debugf("Found main.lua: {}", main_lua.string());
|
||||||
try {
|
boost::asio::post(m_io, [this, main_lua] {
|
||||||
m_state.safe_script_file(main_lua.string());
|
try {
|
||||||
} catch (const std::exception& e) {
|
m_state.safe_script_file(main_lua.string());
|
||||||
beammp_lua_errorf("Error running '{}': {}", main_lua.string(), e.what());
|
} catch (const std::exception& e) {
|
||||||
}
|
beammp_lua_errorf("Error running '{}': {}", main_lua.string(), e.what());
|
||||||
});
|
}
|
||||||
} else {
|
});
|
||||||
beammp_lua_warnf("No 'main.lua' found, a plugin should have a 'main.lua'.");
|
} else {
|
||||||
|
beammp_lua_warnf("No 'main.lua' found, a plugin should have a 'main.lua'.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -559,7 +558,7 @@ void LuaPlugin::cancel_timer(const std::shared_ptr<Timer>& timer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LuaPlugin::l_print(const sol::variadic_args& args) {
|
void LuaPlugin::l_print(const sol::variadic_args& args) {
|
||||||
auto result = print_impl(args);
|
auto result = print_impl({ args.begin(), args.end() });
|
||||||
beammp_lua_infof("{}", result);
|
beammp_lua_infof("{}", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,8 +634,7 @@ std::shared_ptr<Timer> LuaPlugin::l_mp_schedule_call_repeat(size_t ms, const sol
|
|||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LuaPlugin::print_impl(const sol::variadic_args& args) {
|
std::string LuaPlugin::print_impl(const std::vector<sol::object>& obj_args) {
|
||||||
auto obj_args = std::vector<sol::object>(args.begin(), args.end());
|
|
||||||
std::string result {};
|
std::string result {};
|
||||||
result.reserve(500);
|
result.reserve(500);
|
||||||
|
|
||||||
@ -678,3 +676,28 @@ std::string LuaPlugin::print_impl(const sol::variadic_args& args) {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
void LuaPlugin::run_raw_lua(const std::string& raw) {
|
||||||
|
if (raw.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::string id = "";
|
||||||
|
if (raw.size() < 5) {
|
||||||
|
id = raw;
|
||||||
|
} else {
|
||||||
|
id = raw.substr(0, 5) + "...";
|
||||||
|
}
|
||||||
|
boost::asio::post(m_io, [this, raw, id] {
|
||||||
|
try {
|
||||||
|
beammp_debugf("Running '{}'", raw);
|
||||||
|
auto res = m_state.safe_script(raw, id);
|
||||||
|
if (res.valid()) {
|
||||||
|
std::vector<sol::object> args;
|
||||||
|
args.push_back(res.get<sol::object>());
|
||||||
|
auto str = print_impl(args);
|
||||||
|
Application::Console().WriteRaw(fmt::format("=> {}", str));
|
||||||
|
}
|
||||||
|
} catch (const sol::error& err) {
|
||||||
|
beammp_lua_errorf("Error: {}", err.what());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -169,8 +169,7 @@ void TConsole::ChangeToLuaConsole(const std::string& LuaStateId) {
|
|||||||
mCommandline->set_prompt("lua> ");
|
mCommandline->set_prompt("lua> ");
|
||||||
}
|
}
|
||||||
mCachedRegularHistory = mCommandline->history();
|
mCachedRegularHistory = mCommandline->history();
|
||||||
mCommandline->set_history(mCachedLuaHistory);
|
mCommandline->set_history(mCachedLuaHistory);*/
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,6 +222,7 @@ void TConsole::Command_Lua(const std::string&, const std::vector<std::string>& a
|
|||||||
if (args.size() == 1) {
|
if (args.size() == 1) {
|
||||||
auto NewStateId = args.at(0);
|
auto NewStateId = args.at(0);
|
||||||
beammp_assert(!NewStateId.empty());
|
beammp_assert(!NewStateId.empty());
|
||||||
|
// TODO: This must be implemented
|
||||||
/*
|
/*
|
||||||
if (mLuaEngine->HasState(NewStateId)) {
|
if (mLuaEngine->HasState(NewStateId)) {
|
||||||
ChangeToLuaConsole(NewStateId);
|
ChangeToLuaConsole(NewStateId);
|
||||||
@ -232,6 +232,7 @@ void TConsole::Command_Lua(const std::string&, const std::vector<std::string>& a
|
|||||||
*/
|
*/
|
||||||
} else if (args.size() == 0) {
|
} else if (args.size() == 0) {
|
||||||
ChangeToLuaConsole(mDefaultStateId);
|
ChangeToLuaConsole(mDefaultStateId);
|
||||||
|
// CONTINUE HERE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +188,6 @@ TEST_CASE("ValueToStringVisitor") {
|
|||||||
|
|
||||||
static Result<Value> sol_obj_to_value_impl(const sol::object& obj, const std::function<Result<Value>(const sol::object&)>& invalid_provider, size_t max_depth, size_t depth) {
|
static Result<Value> sol_obj_to_value_impl(const sol::object& obj, const std::function<Result<Value>(const sol::object&)>& invalid_provider, size_t max_depth, size_t depth) {
|
||||||
if (depth == max_depth) {
|
if (depth == max_depth) {
|
||||||
beammp_errorf("Maximum depth reached for sol_obj_to_value_impl, assuming recursion and returning null for this branch");
|
|
||||||
return { Null {} };
|
return { Null {} };
|
||||||
}
|
}
|
||||||
++depth;
|
++depth;
|
||||||
|
@ -169,6 +169,10 @@ int BeamMPServerMain(MainArguments Arguments) {
|
|||||||
// TPluginMonitor PluginMonitor(fs::path(Application::Settings.Resource) / "Server", LuaEngine);
|
// TPluginMonitor PluginMonitor(fs::path(Application::Settings.Resource) / "Server", LuaEngine);
|
||||||
PluginManager PluginManager;
|
PluginManager PluginManager;
|
||||||
(void)PluginManager.add_plugin(Plugin::make_pointer<LuaPlugin>("Resources/Server/Test"));
|
(void)PluginManager.add_plugin(Plugin::make_pointer<LuaPlugin>("Resources/Server/Test"));
|
||||||
|
auto console = Plugin::make_pointer<LuaPlugin>(BEAMMP_MEMORY_STATE);
|
||||||
|
(void)PluginManager.add_plugin(console);
|
||||||
|
|
||||||
|
dynamic_cast<LuaPlugin&>(*console).run_raw_lua(R"(local n = 12; return n)");
|
||||||
|
|
||||||
PluginManager.trigger_event("onInit", std::make_shared<Value>(HashMap<std::string, Value> {
|
PluginManager.trigger_event("onInit", std::make_shared<Value>(HashMap<std::string, Value> {
|
||||||
{ "big", "balls" },
|
{ "big", "balls" },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user