Compare commits

..

1 Commits

20 changed files with 76 additions and 259 deletions
+1 -1
View File
@@ -84,7 +84,7 @@ jobs:
run: ./bin/BeamMP-Server-tests run: ./bin/BeamMP-Server-tests
arm64-matrix: arm64-matrix:
runs-on: ubuntu-22.04-arm runs-on: [Linux, ARM64]
env: env:
VCPKG_DEFAULT_TRIPLET: "arm64-linux" VCPKG_DEFAULT_TRIPLET: "arm64-linux"
strategy: strategy:
+1 -1
View File
@@ -104,7 +104,7 @@ jobs:
asset_content_type: application/x-elf asset_content_type: application/x-elf
arm64-matrix: arm64-matrix:
runs-on: ubuntu-22.04-arm runs-on: [Linux, ARM64]
needs: create-release needs: create-release
strategy: strategy:
matrix: matrix:
+1 -2
View File
@@ -127,11 +127,10 @@ private:
static inline std::mutex mShutdownHandlersMutex {}; static inline std::mutex mShutdownHandlersMutex {};
static inline std::deque<TShutdownHandler> mShutdownHandlers {}; static inline std::deque<TShutdownHandler> mShutdownHandlers {};
static inline Version mVersion { 3, 8, 4 }; static inline Version mVersion { 3, 8, 1 };
}; };
void SplitString(std::string const& str, const char delim, std::vector<std::string>& out); void SplitString(std::string const& str, const char delim, std::vector<std::string>& out);
std::string LowerString(std::string str);
std::string ThreadName(bool DebugModeOverride = false); std::string ThreadName(bool DebugModeOverride = false);
void RegisterThread(const std::string& str); void RegisterThread(const std::string& str);
-1
View File
@@ -27,7 +27,6 @@ enum class Key {
PROVIDER_UPDATE_MESSAGE, PROVIDER_UPDATE_MESSAGE,
PROVIDER_DISABLE_CONFIG, PROVIDER_DISABLE_CONFIG,
PROVIDER_PORT_ENV, PROVIDER_PORT_ENV,
PROVIDER_IP_ENV
}; };
std::optional<std::string> Get(Key key); std::optional<std::string> Get(Key key);
-1
View File
@@ -79,7 +79,6 @@ struct Settings {
General_Map, General_Map,
General_AuthKey, General_AuthKey,
General_Private, General_Private,
General_IP,
General_Port, General_Port,
General_MaxCars, General_MaxCars,
General_LogChat, General_LogChat,
-4
View File
@@ -59,8 +59,6 @@ private:
void Command_Settings(const std::string& cmd, const std::vector<std::string>& args); void Command_Settings(const std::string& cmd, const std::vector<std::string>& args);
void Command_Clear(const std::string&, const std::vector<std::string>& args); void Command_Clear(const std::string&, const std::vector<std::string>& args);
void Command_Version(const std::string& cmd, const std::vector<std::string>& args); void Command_Version(const std::string& cmd, const std::vector<std::string>& args);
void Command_ProtectMod(const std::string& cmd, const std::vector<std::string>& args);
void Command_ReloadMods(const std::string& cmd, const std::vector<std::string>& args);
void Command_Say(const std::string& FullCommand); void Command_Say(const std::string& FullCommand);
bool EnsureArgsCount(const std::vector<std::string>& args, size_t n); bool EnsureArgsCount(const std::vector<std::string>& args, size_t n);
@@ -79,8 +77,6 @@ private:
{ "clear", [this](const auto& a, const auto& b) { Command_Clear(a, b); } }, { "clear", [this](const auto& a, const auto& b) { Command_Clear(a, b); } },
{ "say", [this](const auto&, const auto&) { Command_Say(""); } }, // shouldn't actually be called { "say", [this](const auto&, const auto&) { Command_Say(""); } }, // shouldn't actually be called
{ "version", [this](const auto& a, const auto& b) { Command_Version(a, b); } }, { "version", [this](const auto& a, const auto& b) { Command_Version(a, b); } },
{ "protectmod", [this](const auto& a, const auto& b) { Command_ProtectMod(a, b); } },
{ "reloadmods", [this](const auto& a, const auto& b) { Command_ReloadMods(a, b); } },
}; };
std::unique_ptr<Commandline> mCommandline { nullptr }; std::unique_ptr<Commandline> mCommandline { nullptr };
-2
View File
@@ -45,8 +45,6 @@ public:
void SendToAll(TClient* c, const std::vector<uint8_t>& Data, bool Self, bool Rel); void SendToAll(TClient* c, const std::vector<uint8_t>& Data, bool Self, bool Rel);
void UpdatePlayer(TClient& Client); void UpdatePlayer(TClient& Client);
TResourceManager& ResourceManager() const { return mResourceManager; }
private: private:
void UDPServerMain(); void UDPServerMain();
void TCPServerMain(); void TCPServerMain();
+2 -2
View File
@@ -30,10 +30,10 @@ public:
[[nodiscard]] std::string TrimmedList() const { return mTrimmedList; } [[nodiscard]] std::string TrimmedList() const { return mTrimmedList; }
[[nodiscard]] std::string FileSizes() const { return mFileSizes; } [[nodiscard]] std::string FileSizes() const { return mFileSizes; }
[[nodiscard]] int ModsLoaded() const { return mModsLoaded; } [[nodiscard]] int ModsLoaded() const { return mModsLoaded; }
[[nodiscard]] nlohmann::json GetMods() const { return mMods; }
[[nodiscard]] std::string NewFileList() const;
void RefreshFiles(); void RefreshFiles();
void SetProtected(const std::string& ModName, bool Protected);
private: private:
size_t mMaxModSize = 0; size_t mMaxModSize = 0;
+1
View File
@@ -84,6 +84,7 @@ void TClient::Disconnect(std::string_view Reason) {
if (ec) { if (ec) {
beammp_debugf("Failed to shutdown client socket: {}", ec.message()); beammp_debugf("Failed to shutdown client socket: {}", ec.message());
} }
mSocket.cancel();
mSocket.close(ec); mSocket.close(ec);
if (ec) { if (ec) {
beammp_debugf("Failed to close client socket: {}", ec.message()); beammp_debugf("Failed to close client socket: {}", ec.message());
-7
View File
@@ -384,13 +384,6 @@ void SplitString(const std::string& str, const char delim, std::vector<std::stri
out.push_back(str.substr(start, end - start)); out.push_back(str.substr(start, end - start));
} }
} }
std::string LowerString(std::string str) {
std::ranges::transform(str, str.begin(), ::tolower);
return str;
}
static constexpr size_t STARTING_MAX_DECOMPRESSION_BUFFER_SIZE = 15 * 1024 * 1024; static constexpr size_t STARTING_MAX_DECOMPRESSION_BUFFER_SIZE = 15 * 1024 * 1024;
static constexpr size_t MAX_DECOMPRESSION_BUFFER_SIZE = 30 * 1024 * 1024; static constexpr size_t MAX_DECOMPRESSION_BUFFER_SIZE = 30 * 1024 * 1024;
-3
View File
@@ -39,9 +39,6 @@ std::string_view Env::ToString(Env::Key key) {
case Key::PROVIDER_PORT_ENV: case Key::PROVIDER_PORT_ENV:
return "BEAMMP_PROVIDER_PORT_ENV"; return "BEAMMP_PROVIDER_PORT_ENV";
break; break;
case Key::PROVIDER_IP_ENV:
return "BEAMMP_PROVIDER_IP_ENV";
break;
} }
return ""; return "";
} }
-5
View File
@@ -148,11 +148,6 @@ static inline std::pair<bool, std::string> InternalTriggerClientEvent(int Player
return { false, "Invalid Player ID" }; return { false, "Invalid Player ID" };
} }
auto c = MaybeClient.value().lock(); auto c = MaybeClient.value().lock();
if (!c->IsSyncing() && !c->IsSynced()) {
return { false, "Player hasn't joined yet" };
}
if (!LuaAPI::MP::Engine->Network().Respond(*c, StringToVector(Packet), true)) { if (!LuaAPI::MP::Engine->Network().Respond(*c, StringToVector(Packet), true)) {
beammp_lua_errorf("Respond failed, dropping client {}", PlayerID); beammp_lua_errorf("Respond failed, dropping client {}", PlayerID);
LuaAPI::MP::Engine->Network().ClientKick(*c, "Disconnected after failing to receive packets"); LuaAPI::MP::Engine->Network().ClientKick(*c, "Disconnected after failing to receive packets");
-2
View File
@@ -28,7 +28,6 @@ Settings::Settings() {
{ General_Map, std::string("/levels/gridmap_v2/info.json") }, { General_Map, std::string("/levels/gridmap_v2/info.json") },
{ General_AuthKey, std::string("") }, { General_AuthKey, std::string("") },
{ General_Private, true }, { General_Private, true },
{ General_IP, "::"},
{ General_Port, 30814 }, { General_Port, 30814 },
{ General_MaxCars, 1 }, { General_MaxCars, 1 },
{ General_LogChat, true }, { General_LogChat, true },
@@ -48,7 +47,6 @@ Settings::Settings() {
{ { "General", "Map" }, { General_Map, READ_WRITE } }, { { "General", "Map" }, { General_Map, READ_WRITE } },
{ { "General", "AuthKey" }, { General_AuthKey, NO_ACCESS } }, { { "General", "AuthKey" }, { General_AuthKey, NO_ACCESS } },
{ { "General", "Private" }, { General_Private, READ_ONLY } }, { { "General", "Private" }, { General_Private, READ_ONLY } },
{ { "General", "IP" }, { General_IP, READ_ONLY } },
{ { "General", "Port" }, { General_Port, READ_ONLY } }, { { "General", "Port" }, { General_Port, READ_ONLY } },
{ { "General", "MaxCars" }, { General_MaxCars, READ_WRITE } }, { { "General", "MaxCars" }, { General_MaxCars, READ_WRITE } },
{ { "General", "LogChat" }, { General_LogChat, READ_ONLY } }, { { "General", "LogChat" }, { General_LogChat, READ_ONLY } },
-10
View File
@@ -34,8 +34,6 @@ static constexpr std::string_view StrDebug = "Debug";
static constexpr std::string_view EnvStrDebug = "BEAMMP_DEBUG"; static constexpr std::string_view EnvStrDebug = "BEAMMP_DEBUG";
static constexpr std::string_view StrPrivate = "Private"; static constexpr std::string_view StrPrivate = "Private";
static constexpr std::string_view EnvStrPrivate = "BEAMMP_PRIVATE"; static constexpr std::string_view EnvStrPrivate = "BEAMMP_PRIVATE";
static constexpr std::string_view StrIP = "IP";
static constexpr std::string_view EnvStrIP = "BEAMMP_IP";
static constexpr std::string_view StrPort = "Port"; static constexpr std::string_view StrPort = "Port";
static constexpr std::string_view EnvStrPort = "BEAMMP_PORT"; static constexpr std::string_view EnvStrPort = "BEAMMP_PORT";
static constexpr std::string_view StrMaxCars = "MaxCars"; static constexpr std::string_view StrMaxCars = "MaxCars";
@@ -140,8 +138,6 @@ void TConfig::FlushToFile() {
data["General"][StrInformationPacket.data()] = Application::Settings.getAsBool(Settings::Key::General_InformationPacket); data["General"][StrInformationPacket.data()] = Application::Settings.getAsBool(Settings::Key::General_InformationPacket);
data["General"][StrAllowGuests.data()] = Application::Settings.getAsBool(Settings::Key::General_AllowGuests); data["General"][StrAllowGuests.data()] = Application::Settings.getAsBool(Settings::Key::General_AllowGuests);
SetComment(data["General"][StrAllowGuests.data()].comments(), " Whether to allow guests"); SetComment(data["General"][StrAllowGuests.data()].comments(), " Whether to allow guests");
data["General"][StrIP.data()] = Application::Settings.getAsString(Settings::Key::General_IP);
SetComment(data["General"][StrIP.data()].comments(), " The IP address to bind the server to, this is NOT related to your public IP. Can be used if your machine has multiple network interfaces");
data["General"][StrPort.data()] = Application::Settings.getAsInt(Settings::Key::General_Port); data["General"][StrPort.data()] = Application::Settings.getAsInt(Settings::Key::General_Port);
data["General"][StrName.data()] = Application::Settings.getAsString(Settings::Key::General_Name); data["General"][StrName.data()] = Application::Settings.getAsString(Settings::Key::General_Name);
SetComment(data["General"][StrTags.data()].comments(), " Add custom identifying tags to your server to make it easier to find. Format should be TagA,TagB,TagC. Note the comma seperation."); SetComment(data["General"][StrTags.data()].comments(), " Add custom identifying tags to your server to make it easier to find. Format should be TagA,TagB,TagC. Note the comma seperation.");
@@ -258,11 +254,6 @@ void TConfig::ParseFromFile(std::string_view name) {
} else { } else {
TryReadValue(data, "General", StrPort, EnvStrPort, Settings::Key::General_Port); TryReadValue(data, "General", StrPort, EnvStrPort, Settings::Key::General_Port);
} }
if (Env::Get(Env::Key::PROVIDER_IP_ENV).has_value()) {
TryReadValue(data, "General", StrIP, Env::Get(Env::Key::PROVIDER_IP_ENV).value(), Settings::Key::General_IP);
} else {
TryReadValue(data, "General", StrIP, EnvStrIP, Settings::Key::General_IP);
}
TryReadValue(data, "General", StrMaxCars, EnvStrMaxCars, Settings::Key::General_MaxCars); TryReadValue(data, "General", StrMaxCars, EnvStrMaxCars, Settings::Key::General_MaxCars);
TryReadValue(data, "General", StrMaxPlayers, EnvStrMaxPlayers, Settings::Key::General_MaxPlayers); TryReadValue(data, "General", StrMaxPlayers, EnvStrMaxPlayers, Settings::Key::General_MaxPlayers);
TryReadValue(data, "General", StrMap, EnvStrMap, Settings::Key::General_Map); TryReadValue(data, "General", StrMap, EnvStrMap, Settings::Key::General_Map);
@@ -313,7 +304,6 @@ void TConfig::PrintDebug() {
beammp_debug(std::string(StrPrivate) + ": " + std::string(Application::Settings.getAsBool(Settings::Key::General_Private) ? "true" : "false")); beammp_debug(std::string(StrPrivate) + ": " + std::string(Application::Settings.getAsBool(Settings::Key::General_Private) ? "true" : "false"));
beammp_debug(std::string(StrInformationPacket) + ": " + std::string(Application::Settings.getAsBool(Settings::Key::General_InformationPacket) ? "true" : "false")); beammp_debug(std::string(StrInformationPacket) + ": " + std::string(Application::Settings.getAsBool(Settings::Key::General_InformationPacket) ? "true" : "false"));
beammp_debug(std::string(StrPort) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_Port))); beammp_debug(std::string(StrPort) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_Port)));
beammp_debug(std::string(StrIP) + ": \"" + Application::Settings.getAsString(Settings::Key::General_IP) + "\"");
beammp_debug(std::string(StrMaxCars) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxCars))); beammp_debug(std::string(StrMaxCars) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxCars)));
beammp_debug(std::string(StrMaxPlayers) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers))); beammp_debug(std::string(StrMaxPlayers) + ": " + std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)));
beammp_debug(std::string(StrMap) + ": \"" + Application::Settings.getAsString(Settings::Key::General_Map) + "\""); beammp_debug(std::string(StrMap) + ": \"" + Application::Settings.getAsString(Settings::Key::General_Map) + "\"");
+10 -38
View File
@@ -208,18 +208,16 @@ void TConsole::Command_Help(const std::string&, const std::vector<std::string>&
} }
static constexpr const char* sHelpString = R"( static constexpr const char* sHelpString = R"(
Commands: Commands:
help displays this help help displays this help
exit shuts down the server exit shuts down the server
kick <name> [reason] kicks specified player with an optional reason kick <name> [reason] kicks specified player with an optional reason
list lists all players and info about them list lists all players and info about them
say <message> sends the message to all players in chat say <message> sends the message to all players in chat
lua [state id] switches to lua, optionally into a specific state id's lua lua [state id] switches to lua, optionally into a specific state id's lua
settings [command] sets or gets settings for the server, run `settings help` for more info settings [command] sets or gets settings for the server, run `settings help` for more info
status how the server is doing and what it's up to status how the server is doing and what it's up to
clear clears the console window clear clears the console window
version displays the server version version displays the server version)";
protectmod <name> <value> sets whether a mod is protected, value can be true or false
reloadmods reloads all mods from the Resources Client folder)";
Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString)); Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString));
} }
@@ -264,32 +262,6 @@ void TConsole::Command_Version(const std::string& cmd, const std::vector<std::st
std::string openssl_version = fmt::format("OpenSSL: v{}.{}.{}", OPENSSL_VERSION_MAJOR, OPENSSL_VERSION_MINOR, OPENSSL_VERSION_PATCH); std::string openssl_version = fmt::format("OpenSSL: v{}.{}.{}", OPENSSL_VERSION_MAJOR, OPENSSL_VERSION_MINOR, OPENSSL_VERSION_PATCH);
Application::Console().WriteRaw(openssl_version); Application::Console().WriteRaw(openssl_version);
} }
void TConsole::Command_ProtectMod(const std::string& cmd, const std::vector<std::string>& args) {
if (!EnsureArgsCount(args, 2)) {
return;
}
const auto& ModName = args.at(0);
const auto& Protect = args.at(1);
for (auto mod : mLuaEngine->Network().ResourceManager().GetMods()) {
if (mod["file_name"].get<std::string>() == ModName) {
mLuaEngine->Network().ResourceManager().SetProtected(ModName, Protect == "true");
Application::Console().WriteRaw("Mod " + ModName + " is now " + (Protect == "true" ? "protected" : "unprotected"));
return;
}
}
Application::Console().WriteRaw("Mod " + ModName + " not found.");
}
void TConsole::Command_ReloadMods(const std::string& cmd, const std::vector<std::string>& args) {
if (!EnsureArgsCount(args, 0)) {
return;
}
mLuaEngine->Network().ResourceManager().RefreshFiles();
Application::Console().WriteRaw("Mods reloaded.");
}
void TConsole::Command_Kick(const std::string&, const std::vector<std::string>& args) { void TConsole::Command_Kick(const std::string&, const std::vector<std::string>& args) {
if (!EnsureArgsCount(args, 1, size_t(-1))) { if (!EnsureArgsCount(args, 1, size_t(-1))) {
+28 -10
View File
@@ -40,6 +40,20 @@ TLuaEngine* LuaAPI::MP::Engine;
static sol::protected_function AddTraceback(sol::state_view StateView, sol::protected_function RawFn); static sol::protected_function AddTraceback(sol::state_view StateView, sol::protected_function RawFn);
static std::optional<sol::function> GetLuaHandler(sol::state_view StateView, const std::string Handler, const std::string EventName);
static std::optional<sol::function> GetLuaHandler(sol::state_view StateView, const std::string Handler, const std::string EventName) {
if (!StateView)
return std::nullopt;
auto Res = StateView.safe_script("return " + Handler, sol::script_pass_on_error);
if (!Res.valid()) {
beammp_errorf("invalid handler for event \"{}\". handler: \"{}\"", EventName, Handler);
} else if (Res.get_type() == sol::type::function) {
return Res.get<sol::function>();
}
return std::nullopt;
}
TLuaEngine::TLuaEngine() TLuaEngine::TLuaEngine()
: mResourceServerPath(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server") { : mResourceServerPath(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server") {
Application::SetSubsystemStatus("LuaEngine", Application::Status::Starting); Application::SetSubsystemStatus("LuaEngine", Application::Status::Starting);
@@ -68,11 +82,10 @@ TEST_CASE("TLuaEngine ctor & dtor") {
void TLuaEngine::operator()() { void TLuaEngine::operator()() {
RegisterThread("LuaEngine"); RegisterThread("LuaEngine");
Application::SetSubsystemStatus("LuaEngine", Application::Status::Good);
// lua engine main thread // lua engine main thread
beammp_infof("Lua v{}.{}.{}", LUA_VERSION_MAJOR, LUA_VERSION_MINOR, LUA_VERSION_RELEASE); beammp_infof("Lua v{}.{}.{}", LUA_VERSION_MAJOR, LUA_VERSION_MINOR, LUA_VERSION_RELEASE);
CollectAndInitPlugins(); CollectAndInitPlugins();
Application::SetSubsystemStatus("LuaEngine", Application::Status::Good);
// now call all onInit's // now call all onInit's
auto Futures = TriggerEvent("onInit", ""); auto Futures = TriggerEvent("onInit", "");
WaitForAll(Futures, std::chrono::seconds(5)); WaitForAll(Futures, std::chrono::seconds(5));
@@ -495,9 +508,11 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string
sol::variadic_results LocalArgs = JsonStringToArray(Str); sol::variadic_results LocalArgs = JsonStringToArray(Str);
for (const auto& Handler : MyHandlers) { for (const auto& Handler : MyHandlers) {
auto Fn = mStateView[Handler]; auto Res = GetLuaHandler(mStateView, Handler, EventName);
Fn = AddTraceback(mStateView, Fn); if (Res.has_value()) {
if (Fn.valid()) { sol::function Fn = Res.value();
Fn = AddTraceback(mStateView, Fn);
auto LuaResult = Fn(LocalArgs); auto LuaResult = Fn(LocalArgs);
auto Result = std::make_shared<TLuaResult>(); auto Result = std::make_shared<TLuaResult>();
if (LuaResult.valid()) { if (LuaResult.valid()) {
@@ -549,8 +564,9 @@ sol::table TLuaEngine::StateThreadData::Lua_TriggerLocalEvent(const std::string&
sol::table Result = mStateView.create_table(); sol::table Result = mStateView.create_table();
int i = 1; int i = 1;
for (const auto& Handler : mEngine->GetEventHandlersForState(EventName, mStateId)) { for (const auto& Handler : mEngine->GetEventHandlersForState(EventName, mStateId)) {
auto Fn = mStateView[Handler]; auto Res = GetLuaHandler(mStateView, Handler, EventName);
if (Fn.valid() && Fn.get_type() == sol::type::function) { if (Res.has_value()) {
sol::function Fn = Res.value();
auto FnRet = Fn(EventArgs); auto FnRet = Fn(EventArgs);
if (FnRet.valid()) { if (FnRet.valid()) {
Result.set(i, FnRet); Result.set(i, FnRet);
@@ -1162,8 +1178,10 @@ void TLuaEngine::StateThreadData::operator()() {
// TODO: Use TheQueuedFunction.EventName for errors, warnings, etc // TODO: Use TheQueuedFunction.EventName for errors, warnings, etc
Result->StateId = mStateId; Result->StateId = mStateId;
sol::state_view StateView(mState); sol::state_view StateView(mState);
auto RawFn = StateView[FnName];
if (RawFn.valid() && RawFn.get_type() == sol::type::function) { auto Res = GetLuaHandler(StateView, FnName, TheQueuedFunction.EventName);
if (Res.has_value()) {
sol::function Fn = Res.value();
std::vector<sol::object> LuaArgs; std::vector<sol::object> LuaArgs;
for (const auto& Arg : Args) { for (const auto& Arg : Args) {
if (Arg.valueless_by_exception()) { if (Arg.valueless_by_exception()) {
@@ -1198,7 +1216,7 @@ void TLuaEngine::StateThreadData::operator()() {
break; break;
} }
} }
auto Fn = AddTraceback(StateView, RawFn); Fn = AddTraceback(StateView, Fn);
auto Res = Fn(sol::as_args(LuaArgs)); auto Res = Fn(sol::as_args(LuaArgs));
if (Res.valid()) { if (Res.valid()) {
Result->Error = false; Result->Error = false;
+9 -37
View File
@@ -85,17 +85,9 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R
void TNetwork::UDPServerMain() { void TNetwork::UDPServerMain() {
RegisterThread("UDPServer"); RegisterThread("UDPServer");
// listen on all ipv6 addresses
ip::udp::endpoint UdpListenEndpoint(ip::make_address("::"), Application::Settings.getAsInt(Settings::Key::General_Port));
boost::system::error_code ec; boost::system::error_code ec;
auto address = ip::make_address(Application::Settings.getAsString(Settings::Key::General_IP), ec);
if (ec) {
beammp_errorf("Failed to parse IP: {}", ec.message());
Application::GracefullyShutdown();
}
ip::udp::endpoint UdpListenEndpoint(address, Application::Settings.getAsInt(Settings::Key::General_Port));
mUDPSock.open(UdpListenEndpoint.protocol(), ec); mUDPSock.open(UdpListenEndpoint.protocol(), ec);
if (ec) { if (ec) {
beammp_error("open() failed: " + ec.message()); beammp_error("open() failed: " + ec.message());
@@ -115,7 +107,7 @@ void TNetwork::UDPServerMain() {
Application::GracefullyShutdown(); Application::GracefullyShutdown();
} }
Application::SetSubsystemStatus("UDPNetwork", Application::Status::Good); Application::SetSubsystemStatus("UDPNetwork", Application::Status::Good);
beammp_info(("Vehicle data network online on port ") + std::to_string(UdpListenEndpoint.port()) + (" with a Max of ") beammp_info(("Vehicle data network online on port ") + std::to_string(Application::Settings.getAsInt(Settings::Key::General_Port)) + (" with a Max of ")
+ std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)) + (" Clients")); + std::to_string(Application::Settings.getAsInt(Settings::Key::General_MaxPlayers)) + (" Clients"));
while (!Application::IsShuttingDown()) { while (!Application::IsShuttingDown()) {
try { try {
@@ -178,17 +170,12 @@ void TNetwork::UDPServerMain() {
void TNetwork::TCPServerMain() { void TNetwork::TCPServerMain() {
RegisterThread("TCPServer"); RegisterThread("TCPServer");
boost::system::error_code ec; // listen on all ipv6 addresses
auto address = ip::make_address(Application::Settings.getAsString(Settings::Key::General_IP), ec); auto port = uint16_t(Application::Settings.getAsInt(Settings::Key::General_Port));
if (ec) { ip::tcp::endpoint ListenEp(ip::make_address("::"), port);
beammp_errorf("Failed to parse IP: {}", ec.message()); beammp_infof("Listening on 0.0.0.0:{0} and [::]:{0}", port);
return;
}
ip::tcp::endpoint ListenEp(address,
uint16_t(Application::Settings.getAsInt(Settings::Key::General_Port)));
ip::tcp::socket Listener(mServer.IoCtx()); ip::tcp::socket Listener(mServer.IoCtx());
boost::system::error_code ec;
Listener.open(ListenEp.protocol(), ec); Listener.open(ListenEp.protocol(), ec);
if (ec) { if (ec) {
beammp_errorf("Failed to open socket: {}", ec.message()); beammp_errorf("Failed to open socket: {}", ec.message());
@@ -222,7 +209,6 @@ void TNetwork::TCPServerMain() {
Application::GracefullyShutdown(); Application::GracefullyShutdown();
} }
Application::SetSubsystemStatus("TCPNetwork", Application::Status::Good); Application::SetSubsystemStatus("TCPNetwork", Application::Status::Good);
beammp_infof("Listening on {0} port {1}", ListenEp.address().to_string(), static_cast<uint16_t>(ListenEp.port()));
beammp_info("Vehicle event network online"); beammp_info("Vehicle event network online");
do { do {
try { try {
@@ -321,11 +307,6 @@ std::shared_ptr<TClient> TNetwork::Authentication(TConnection&& RawConnection) {
Client->SetIdentifier("ip", ip); Client->SetIdentifier("ip", ip);
beammp_tracef("This thread is ip {} ({})", ip, RawConnection.SockAddr.address().to_v6().is_v4_mapped() ? "IPv4 mapped IPv6" : "IPv6"); beammp_tracef("This thread is ip {} ({})", ip, RawConnection.SockAddr.address().to_v6().is_v4_mapped() ? "IPv4 mapped IPv6" : "IPv6");
if (Application::GetSubsystemStatuses().at("Main") == Application::Status::Starting) {
ClientKick(*Client, "The server is still starting, please try joining again later.");
return nullptr;
}
beammp_info("Identifying new ClientConnection..."); beammp_info("Identifying new ClientConnection...");
auto Data = TCPRcv(*Client); auto Data = TCPRcv(*Client);
@@ -786,7 +767,7 @@ void TNetwork::Parse(TClient& c, const std::vector<uint8_t>& Packet) {
case 'S': case 'S':
if (SubCode == 'R') { if (SubCode == 'R') {
beammp_debug("Sending Mod Info"); beammp_debug("Sending Mod Info");
std::string ToSend = mResourceManager.GetMods().dump(); std::string ToSend = mResourceManager.NewFileList();
beammp_debugf("Mod Info: {}", ToSend); beammp_debugf("Mod Info: {}", ToSend);
if (!TCPSend(c, StringToVector(ToSend))) { if (!TCPSend(c, StringToVector(ToSend))) {
ClientKick(c, "TCP Send 'SY' failed"); ClientKick(c, "TCP Send 'SY' failed");
@@ -808,15 +789,6 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) {
return; return;
} }
auto FileName = fs::path(UnsafeName).filename().string(); auto FileName = fs::path(UnsafeName).filename().string();
for (auto mod : mResourceManager.GetMods()) {
if (mod["file_name"].get<std::string>() == FileName && mod["protected"] == true) {
beammp_warn("Client tried to access protected file " + UnsafeName);
c.Disconnect("Mod is protected thus cannot be downloaded");
return;
}
}
FileName = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client/" + FileName; FileName = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client/" + FileName;
if (!std::filesystem::exists(FileName)) { if (!std::filesystem::exists(FileName)) {
+14 -19
View File
@@ -57,26 +57,21 @@ void TPluginMonitor::operator()() {
mFileTimes[Pair.first] = CurrentTime; mFileTimes[Pair.first] = CurrentTime;
// grandparent of the path should be Resources/Server // grandparent of the path should be Resources/Server
if (fs::equivalent(fs::path(Pair.first).parent_path().parent_path(), mPath)) { if (fs::equivalent(fs::path(Pair.first).parent_path().parent_path(), mPath)) {
if (LowerString(fs::path(Pair.first).extension().string()) == ".lua") { beammp_infof("File \"{}\" changed, reloading", Pair.first);
beammp_infof("File \"{}\" changed, reloading", Pair.first); // is in root folder, so reload
// is in root folder, so reload std::ifstream FileStream(Pair.first, std::ios::in | std::ios::binary);
std::ifstream FileStream(Pair.first, std::ios::in | std::ios::binary); auto Size = std::filesystem::file_size(Pair.first);
auto Size = std::filesystem::file_size(Pair.first); auto Contents = std::make_shared<std::string>();
auto Contents = std::make_shared<std::string>(); Contents->resize(Size);
Contents->resize(Size); FileStream.read(Contents->data(), Contents->size());
FileStream.read(Contents->data(), Contents->size()); TLuaChunk Chunk(Contents, Pair.first, fs::path(Pair.first).parent_path().string());
TLuaChunk Chunk(Contents, Pair.first, fs::path(Pair.first).parent_path().string()); auto StateID = mEngine->GetStateIDForPlugin(fs::path(Pair.first).parent_path());
auto StateID = mEngine->GetStateIDForPlugin(fs::path(Pair.first).parent_path()); auto Res = mEngine->EnqueueScript(StateID, Chunk);
auto Res = mEngine->EnqueueScript(StateID, Chunk); Res->WaitUntilReady();
Res->WaitUntilReady(); if (Res->Error) {
if (Res->Error) { beammp_lua_errorf("Error while hot-reloading \"{}\": {}", Pair.first, Res->ErrorMessage);
beammp_lua_errorf("Error while hot-reloading \"{}\": {}", Pair.first, Res->ErrorMessage);
} else {
mEngine->ReportErrors(mEngine->TriggerLocalEvent(StateID, "onInit"));
mEngine->ReportErrors(mEngine->TriggerEvent("onFileChanged", "", Pair.first));
}
} else { } else {
beammp_debugf("File \"{}\" changed, not reloading because it's not a lua file. Triggering 'onFileChanged' event instead", Pair.first); mEngine->ReportErrors(mEngine->TriggerLocalEvent(StateID, "onInit"));
mEngine->ReportErrors(mEngine->TriggerEvent("onFileChanged", "", Pair.first)); mEngine->ReportErrors(mEngine->TriggerEvent("onFileChanged", "", Pair.first));
} }
} else { } else {
+4 -104
View File
@@ -58,58 +58,22 @@ TResourceManager::TResourceManager() {
Application::SetSubsystemStatus("ResourceManager", Application::Status::Good); Application::SetSubsystemStatus("ResourceManager", Application::Status::Good);
} }
std::string TResourceManager::NewFileList() const {
return mMods.dump();
}
void TResourceManager::RefreshFiles() { void TResourceManager::RefreshFiles() {
mMods.clear(); mMods.clear();
std::unique_lock Lock(mModsMutex); std::unique_lock Lock(mModsMutex);
std::string Path = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client"; std::string Path = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client";
nlohmann::json modsDB;
if (std::filesystem::exists(Path + "/mods.json")) {
try {
std::ifstream stream(Path + "/mods.json");
stream >> modsDB;
stream.close();
} catch (const std::exception& e) {
beammp_errorf("Failed to load mods.json: {}", e.what());
}
}
for (const auto& entry : fs::directory_iterator(Path)) { for (const auto& entry : fs::directory_iterator(Path)) {
std::string File(entry.path().string()); std::string File(entry.path().string());
if (entry.path().filename().string() == "mods.json") {
continue;
}
if (entry.path().extension() != ".zip" || std::filesystem::is_directory(entry.path())) { if (entry.path().extension() != ".zip" || std::filesystem::is_directory(entry.path())) {
beammp_warnf("'{}' is not a ZIP file and will be ignored", File); beammp_warnf("'{}' is not a ZIP file and will be ignored", File);
continue; continue;
} }
if (modsDB.contains(entry.path().filename().string())) {
auto& dbEntry = modsDB[entry.path().filename().string()];
if (entry.last_write_time().time_since_epoch().count() > dbEntry["lastwrite"] || std::filesystem::file_size(File) != dbEntry["filesize"].get<size_t>()) {
beammp_infof("File '{}' has been modified, rehashing", File);
} else {
dbEntry["exists"] = true;
mMods.push_back(nlohmann::json {
{ "file_name", std::filesystem::path(File).filename() },
{ "file_size", std::filesystem::file_size(File) },
{ "hash_algorithm", "sha256" },
{ "hash", dbEntry["hash"] },
{ "protected", dbEntry["protected"] } });
beammp_debugf("Mod '{}' loaded from cache", File);
continue;
}
}
try { try {
EVP_MD_CTX* mdctx; EVP_MD_CTX* mdctx;
const EVP_MD* md; const EVP_MD* md;
@@ -169,73 +133,9 @@ void TResourceManager::RefreshFiles() {
{ "file_size", std::filesystem::file_size(File) }, { "file_size", std::filesystem::file_size(File) },
{ "hash_algorithm", "sha256" }, { "hash_algorithm", "sha256" },
{ "hash", result }, { "hash", result },
{ "protected", false } }); });
modsDB[std::filesystem::path(File).filename().string()] = {
{ "lastwrite", entry.last_write_time().time_since_epoch().count() },
{ "hash", result },
{ "filesize", std::filesystem::file_size(File) },
{ "protected", false },
{ "exists", true }
};
} catch (const std::exception& e) { } catch (const std::exception& e) {
beammp_errorf("Sha256 hashing of '{}' failed: {}", File, e.what()); beammp_errorf("Sha256 hashing of '{}' failed: {}", File, e.what());
} }
} }
for (auto it = modsDB.begin(); it != modsDB.end();) {
if (!it.value().contains("exists")) {
it = modsDB.erase(it);
} else {
it.value().erase("exists");
++it;
}
}
try {
std::ofstream stream(Path + "/mods.json");
stream << modsDB.dump(4);
stream.close();
} catch (std::exception& e) {
beammp_error("Failed to update mod DB: " + std::string(e.what()));
}
}
void TResourceManager::SetProtected(const std::string& ModName, bool Protected) {
std::unique_lock Lock(mModsMutex);
for (auto& mod : mMods) {
if (mod["file_name"].get<std::string>() == ModName) {
mod["protected"] = Protected;
break;
}
}
auto modsDBPath = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client/mods.json";
if (std::filesystem::exists(modsDBPath)) {
try {
nlohmann::json modsDB;
std::fstream stream(modsDBPath);
stream >> modsDB;
if (modsDB.contains(ModName)) {
modsDB[ModName]["protected"] = Protected;
}
stream.clear();
stream.seekp(0, std::ios::beg);
stream << modsDB.dump(4);
stream.close();
} catch (const std::exception& e) {
beammp_errorf("Failed to update mods.json: {}", e.what());
}
}
} }
+5 -10
View File
@@ -182,6 +182,10 @@ int BeamMPServerMain(MainArguments Arguments) {
TServer Server(Arguments.List); TServer Server(Arguments.List);
auto LuaEngine = std::make_shared<TLuaEngine>();
LuaEngine->SetServer(&Server);
Application::Console().InitializeLuaConsole(*LuaEngine);
RegisterThread("Main"); RegisterThread("Main");
beammp_trace("Running in debug mode on a debug build"); beammp_trace("Running in debug mode on a debug build");
@@ -190,16 +194,13 @@ int BeamMPServerMain(MainArguments Arguments) {
TPPSMonitor PPSMonitor(Server); TPPSMonitor PPSMonitor(Server);
THeartbeatThread Heartbeat(ResourceManager, Server); THeartbeatThread Heartbeat(ResourceManager, Server);
TNetwork Network(Server, PPSMonitor, ResourceManager); TNetwork Network(Server, PPSMonitor, ResourceManager);
auto LuaEngine = std::make_shared<TLuaEngine>();
LuaEngine->SetServer(&Server);
Application::Console().InitializeLuaConsole(*LuaEngine);
LuaEngine->SetNetwork(&Network); LuaEngine->SetNetwork(&Network);
PPSMonitor.SetNetwork(Network); PPSMonitor.SetNetwork(Network);
Application::CheckForUpdates(); Application::CheckForUpdates();
TPluginMonitor PluginMonitor(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server", LuaEngine); TPluginMonitor PluginMonitor(fs::path(Application::Settings.getAsString(Settings::Key::General_ResourceFolder)) / "Server", LuaEngine);
Application::SetSubsystemStatus("Main", Application::Status::Good);
RegisterThread("Main(Waiting)"); RegisterThread("Main(Waiting)");
std::set<std::string> IgnoreSubsystems { std::set<std::string> IgnoreSubsystems {
@@ -214,10 +215,6 @@ int BeamMPServerMain(MainArguments Arguments) {
std::string SystemsBadList {}; std::string SystemsBadList {};
auto Statuses = Application::GetSubsystemStatuses(); auto Statuses = Application::GetSubsystemStatuses();
for (const auto& NameStatusPair : Statuses) { for (const auto& NameStatusPair : Statuses) {
if (NameStatusPair.first == "Main") {
continue;
}
if (IgnoreSubsystems.count(NameStatusPair.first) > 0) { if (IgnoreSubsystems.count(NameStatusPair.first) > 0) {
continue; // ignore continue; // ignore
} }
@@ -231,8 +228,6 @@ int BeamMPServerMain(MainArguments Arguments) {
// remove ", " // remove ", "
SystemsBadList = SystemsBadList.substr(0, SystemsBadList.size() - 2); SystemsBadList = SystemsBadList.substr(0, SystemsBadList.size() - 2);
if (FullyStarted) { if (FullyStarted) {
Application::SetSubsystemStatus("Main", Application::Status::Good);
if (!WithErrors) { if (!WithErrors) {
beammp_info("ALL SYSTEMS STARTED SUCCESSFULLY, EVERYTHING IS OKAY"); beammp_info("ALL SYSTEMS STARTED SUCCESSFULLY, EVERYTHING IS OKAY");
} else { } else {