mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2026-07-14 10:44:30 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 76a432981c | |||
| 26b1445ad1 |
@@ -1 +0,0 @@
|
|||||||
patreon: BeamMP
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<!--
|
||||||
|
The following is a disclaimer. Since all content in the repository is licensed under AGPL-3.0,
|
||||||
|
the terms of the license apply to your contributions as well.
|
||||||
|
Please make sure that all code or other content you're contributing is your own, or is licensed under
|
||||||
|
an AGPL-3.0 compatible license.
|
||||||
|
-->
|
||||||
|
These contributions are my own and I own all rights to them. I understand and agree that these contributions are licensed under [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.en.html).
|
||||||
@@ -1,11 +1,7 @@
|
|||||||
name: Linux
|
name: Linux
|
||||||
|
|
||||||
on:
|
on: [push]
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'develop'
|
|
||||||
- 'minor'
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
|
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
name: Windows
|
name: Windows
|
||||||
|
|
||||||
on:
|
on: [push]
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- 'develop'
|
|
||||||
- 'minor'
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
VCPKG_DEFAULT_TRIPLET: x64-windows-static
|
VCPKG_DEFAULT_TRIPLET: x64-windows-static
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ set(PRJ_HEADERS
|
|||||||
include/TServer.h
|
include/TServer.h
|
||||||
include/VehicleData.h
|
include/VehicleData.h
|
||||||
include/Env.h
|
include/Env.h
|
||||||
include/Profiling.h
|
|
||||||
)
|
)
|
||||||
# add all source files (.cpp) to this, except the one with main()
|
# add all source files (.cpp) to this, except the one with main()
|
||||||
set(PRJ_SOURCES
|
set(PRJ_SOURCES
|
||||||
@@ -73,7 +72,6 @@ set(PRJ_SOURCES
|
|||||||
src/TServer.cpp
|
src/TServer.cpp
|
||||||
src/VehicleData.cpp
|
src/VehicleData.cpp
|
||||||
src/Env.cpp
|
src/Env.cpp
|
||||||
src/Profiling.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(Lua REQUIRED)
|
find_package(Lua REQUIRED)
|
||||||
@@ -143,7 +141,6 @@ endif(UNIX)
|
|||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
add_compile_options("-D_WIN32_WINNT=0x0601")
|
add_compile_options("-D_WIN32_WINNT=0x0601")
|
||||||
add_compile_options("/bigobj")
|
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
||||||
|
|
||||||
@@ -197,7 +194,6 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE ${PRJ_DEFINITIONS} ${PRJ_WARN
|
|||||||
)
|
)
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
target_compile_options(${PROJECT_NAME} PUBLIC "/bigobj")
|
|
||||||
target_link_options(${PROJECT_NAME} PRIVATE "/SUBSYSTEM:CONSOLE")
|
target_link_options(${PROJECT_NAME} PRIVATE "/SUBSYSTEM:CONSOLE")
|
||||||
endif(MSVC)
|
endif(MSVC)
|
||||||
|
|
||||||
|
|||||||
+3
-20
@@ -53,28 +53,11 @@ Do **NOT** pull with merge. This is the default git behavior for `git pull`, but
|
|||||||
|
|
||||||
The only acceptable merge commits are those which actually merge functionally different branches into each other, for example for merging one feature branch into another.
|
The only acceptable merge commits are those which actually merge functionally different branches into each other, for example for merging one feature branch into another.
|
||||||
|
|
||||||
## Workflow
|
|
||||||
|
|
||||||
### Making an issue and fixing it
|
|
||||||
|
|
||||||
1. Create an issue detailing the feature or bug.
|
|
||||||
2. Assign a milestone to the issue, or wait for a maintainer to add a milestone to your issue.
|
|
||||||
3. Fork the repository and base your work on the branch mentioned in the milestone attached to your issue (e.g. `v3.0.0 (develop)` -> `develop`).
|
|
||||||
4. Program your feature or bug fix.
|
|
||||||
5. Open a PR that references the issue by number in the format: `#12345`.
|
|
||||||
6. Someone will review your PR and merge it, or ask for changes.
|
|
||||||
|
|
||||||
### Fixing an existing issue
|
|
||||||
|
|
||||||
1. Fork the repository and base your work on the branch mentioned in the milestone attached to your issue (e.g. `v3.0.0 (develop)` -> `develop`).
|
|
||||||
2. Program your feature or bug fix.
|
|
||||||
3. Open a PR that references the issue by number in the format: `#12345`.
|
|
||||||
4. Someone will review your PR and merge it, or ask for changes.
|
|
||||||
|
|
||||||
## Branches
|
## Branches
|
||||||
|
|
||||||
- `minor`: Minor releases, like `v1.2.3` -> `v1.3.0` or `v1.2.3` -> `v1.2.4`.
|
### Which branch should I base my work on?
|
||||||
- `develop`: Major releases, like `v1.2.3` -> `v2.0.0`, and larger feature/minor releases.
|
|
||||||
|
Each *feature* or *bug-fix* is implemented on a new Git branch, branched off of the branch it should be based on. The `master` branch is usually stable, so we don't do development on it. It is always a safe bet to branch off of `master`, but it may be more work to merge later. Branches to base your work on are usually branches like `rc-v3.3.0`, when the latest public version is `3.2.0`, for example. These can often be found in Pull-Requests on GitHub which are tagged `Release Candidate`.
|
||||||
|
|
||||||
## Unit tests & CI/CD
|
## Unit tests & CI/CD
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
Submodule deps/commandline updated: 04952e4811...b2a29733f9
+3
-6
@@ -106,6 +106,8 @@ public:
|
|||||||
static std::vector<std::string> GetBackendUrlsInOrder() {
|
static std::vector<std::string> GetBackendUrlsInOrder() {
|
||||||
return {
|
return {
|
||||||
"backend.beammp.com",
|
"backend.beammp.com",
|
||||||
|
"backup1.beammp.com",
|
||||||
|
"backup2.beammp.com"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +152,7 @@ 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, 4, 0 };
|
static inline Version mVersion { 3, 2, 2 };
|
||||||
};
|
};
|
||||||
|
|
||||||
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);
|
||||||
@@ -212,10 +214,6 @@ void RegisterThread(const std::string& str);
|
|||||||
do { \
|
do { \
|
||||||
Application::Console().Write(_this_location + std::string("[LUA ERROR] ") + (x)); \
|
Application::Console().Write(_this_location + std::string("[LUA ERROR] ") + (x)); \
|
||||||
} while (false)
|
} while (false)
|
||||||
#define beammp_lua_log(level, plugin, x) \
|
|
||||||
do { \
|
|
||||||
Application::Console().Write(_this_location + fmt::format("[{}] [{}] ", plugin, level) + (x)); \
|
|
||||||
} while (false)
|
|
||||||
#define beammp_lua_warn(x) \
|
#define beammp_lua_warn(x) \
|
||||||
do { \
|
do { \
|
||||||
Application::Console().Write(_this_location + std::string("[LUA WARN] ") + (x)); \
|
Application::Console().Write(_this_location + std::string("[LUA WARN] ") + (x)); \
|
||||||
@@ -271,7 +269,6 @@ void RegisterThread(const std::string& str);
|
|||||||
#define beammp_tracef(...) beammp_trace(fmt::format(__VA_ARGS__))
|
#define beammp_tracef(...) beammp_trace(fmt::format(__VA_ARGS__))
|
||||||
#define beammp_lua_errorf(...) beammp_lua_error(fmt::format(__VA_ARGS__))
|
#define beammp_lua_errorf(...) beammp_lua_error(fmt::format(__VA_ARGS__))
|
||||||
#define beammp_lua_warnf(...) beammp_lua_warn(fmt::format(__VA_ARGS__))
|
#define beammp_lua_warnf(...) beammp_lua_warn(fmt::format(__VA_ARGS__))
|
||||||
#define beammp_lua_log(level, plugin, x) /* x */
|
|
||||||
|
|
||||||
#endif // DOCTEST_CONFIG_DISABLE
|
#endif // DOCTEST_CONFIG_DISABLE
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ namespace Env {
|
|||||||
enum class Key {
|
enum class Key {
|
||||||
// provider settings
|
// provider settings
|
||||||
PROVIDER_UPDATE_MESSAGE,
|
PROVIDER_UPDATE_MESSAGE,
|
||||||
PROVIDER_DISABLE_CONFIG,
|
|
||||||
PROVIDER_PORT_ENV,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<std::string> Get(Key key);
|
std::optional<std::string> Get(Key key);
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <boost/thread/synchronized_value.hpp>
|
|
||||||
#include <chrono>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <limits>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace prof {
|
|
||||||
|
|
||||||
using Duration = std::chrono::duration<double, std::milli>;
|
|
||||||
using TimePoint = std::chrono::high_resolution_clock::time_point;
|
|
||||||
|
|
||||||
/// Returns the current time.
|
|
||||||
TimePoint now();
|
|
||||||
|
|
||||||
/// Returns a sub-millisecond resolution duration between start and end.
|
|
||||||
Duration duration(const TimePoint& start, const TimePoint& end);
|
|
||||||
|
|
||||||
struct Stats {
|
|
||||||
double mean;
|
|
||||||
double stdev;
|
|
||||||
double min;
|
|
||||||
double max;
|
|
||||||
size_t n;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Calculates and stores the moving average over K samples of execution time data
|
|
||||||
/// for some single unit of code. Threadsafe.
|
|
||||||
struct UnitExecutionTime {
|
|
||||||
UnitExecutionTime();
|
|
||||||
|
|
||||||
/// Adds a sample to the collection, overriding the oldest sample if needed.
|
|
||||||
void add_sample(const Duration& dur);
|
|
||||||
|
|
||||||
/// Calculates the mean duration over the `measurement_count()` measurements,
|
|
||||||
/// as well as the standard deviation.
|
|
||||||
Stats stats() const;
|
|
||||||
|
|
||||||
/// Returns the number of elements the moving average is calculated over.
|
|
||||||
size_t measurement_count() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable std::mutex m_mtx {};
|
|
||||||
size_t m_total_calls {};
|
|
||||||
double m_sum {};
|
|
||||||
// sum of measurements squared (for running stdev)
|
|
||||||
double m_measurement_sqr_sum {};
|
|
||||||
double m_min { std::numeric_limits<double>::max() };
|
|
||||||
double m_max { std::numeric_limits<double>::min() };
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Holds profiles for multiple units by name. Threadsafe.
|
|
||||||
struct UnitProfileCollection {
|
|
||||||
/// Adds a sample to the collection, overriding the oldest sample if needed.
|
|
||||||
void add_sample(const std::string& unit, const Duration& duration);
|
|
||||||
|
|
||||||
/// Calculates the mean duration over the `measurement_count()` measurements,
|
|
||||||
/// as well as the standard deviation.
|
|
||||||
Stats stats(const std::string& unit);
|
|
||||||
|
|
||||||
/// Returns the number of elements the moving average is calculated over.
|
|
||||||
size_t measurement_count(const std::string& unit);
|
|
||||||
|
|
||||||
/// Returns the stats for all stored units.
|
|
||||||
std::unordered_map<std::string, Stats> all_stats();
|
|
||||||
|
|
||||||
private:
|
|
||||||
boost::synchronized_value<std::unordered_map<std::string, UnitExecutionTime>> m_map;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
+1
-2
@@ -35,11 +35,11 @@ public:
|
|||||||
[[nodiscard]] bool Failed() const { return mFailed; }
|
[[nodiscard]] bool Failed() const { return mFailed; }
|
||||||
|
|
||||||
void FlushToFile();
|
void FlushToFile();
|
||||||
void PrintDebug();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CreateConfigFile();
|
void CreateConfigFile();
|
||||||
void ParseFromFile(std::string_view name);
|
void ParseFromFile(std::string_view name);
|
||||||
|
void PrintDebug();
|
||||||
void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, std::string& OutValue);
|
void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, std::string& OutValue);
|
||||||
void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, bool& OutValue);
|
void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, bool& OutValue);
|
||||||
void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, int& OutValue);
|
void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, int& OutValue);
|
||||||
@@ -48,6 +48,5 @@ private:
|
|||||||
std::string TagsAsPrettyArray() const;
|
std::string TagsAsPrettyArray() const;
|
||||||
bool IsDefault();
|
bool IsDefault();
|
||||||
bool mFailed { false };
|
bool mFailed { false };
|
||||||
bool mDisableConfig { false };
|
|
||||||
std::string mConfigFileName;
|
std::string mConfigFileName;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ private:
|
|||||||
void Command_Status(const std::string& cmd, const std::vector<std::string>& args);
|
void Command_Status(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_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_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);
|
||||||
@@ -76,7 +75,6 @@ private:
|
|||||||
{ "settings", [this](const auto& a, const auto& b) { Command_Settings(a, b); } },
|
{ "settings", [this](const auto& a, const auto& b) { Command_Settings(a, b); } },
|
||||||
{ "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); } },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Commandline> mCommandline { nullptr };
|
std::unique_ptr<Commandline> mCommandline { nullptr };
|
||||||
|
|||||||
+12
-34
@@ -18,11 +18,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Profiling.h"
|
|
||||||
#include "TNetwork.h"
|
#include "TNetwork.h"
|
||||||
#include "TServer.h"
|
#include "TServer.h"
|
||||||
#include <any>
|
#include <any>
|
||||||
#include <chrono>
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
@@ -30,7 +28,6 @@
|
|||||||
#include <lua.hpp>
|
#include <lua.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <set>
|
#include <set>
|
||||||
@@ -39,34 +36,19 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define SOL_ALL_SAFETIES_ON 1
|
#define SOL_ALL_SAFETIES_ON 1
|
||||||
#define SOL_USER_C_ASSERT SOL_ON
|
|
||||||
#define SOL_C_ASSERT(...) \
|
|
||||||
beammp_lua_errorf("SOL2 assertion failure: Assertion `{}` failed in {}:{}. This *should* be a fatal error, but BeamMP Server overrides it to not be fatal. This may cause the Lua Engine to crash, or cause other issues.", #__VA_ARGS__, __FILE__, __LINE__)
|
|
||||||
#include <sol/sol.hpp>
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
struct JsonString {
|
|
||||||
std::string value;
|
|
||||||
};
|
|
||||||
|
|
||||||
// value used to keep nils in a table or array, across serialization boundaries like
|
|
||||||
// JsonEncode, so that the nil stays at the same index and isn't treated like a special
|
|
||||||
// value (e.g. one that can be ignored or discarded).
|
|
||||||
const inline std::string BEAMMP_INTERNAL_NIL = "BEAMMP_SERVER_INTERNAL_NIL_VALUE";
|
|
||||||
|
|
||||||
using TLuaStateId = std::string;
|
using TLuaStateId = std::string;
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
/**
|
/**
|
||||||
* std::variant means, that TLuaArgTypes may be one of the Types listed as template args
|
* std::variant means, that TLuaArgTypes may be one of the Types listed as template args
|
||||||
*/
|
*/
|
||||||
using TLuaValue = std::variant<std::string, int, JsonString, bool, std::unordered_map<std::string, std::string>, float>;
|
using TLuaArgTypes = std::variant<std::string, int, sol::variadic_args, bool, std::unordered_map<std::string, std::string>>;
|
||||||
enum TLuaType {
|
static constexpr size_t TLuaArgTypes_String = 0;
|
||||||
String = 0,
|
static constexpr size_t TLuaArgTypes_Int = 1;
|
||||||
Int = 1,
|
static constexpr size_t TLuaArgTypes_VariadicArgs = 2;
|
||||||
Json = 2,
|
static constexpr size_t TLuaArgTypes_Bool = 3;
|
||||||
Bool = 3,
|
static constexpr size_t TLuaArgTypes_StringStringMap = 4;
|
||||||
StringStringMap = 4,
|
|
||||||
Float = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
class TLuaPlugin;
|
class TLuaPlugin;
|
||||||
|
|
||||||
@@ -114,7 +96,7 @@ public:
|
|||||||
struct QueuedFunction {
|
struct QueuedFunction {
|
||||||
std::string FunctionName;
|
std::string FunctionName;
|
||||||
std::shared_ptr<TLuaResult> Result;
|
std::shared_ptr<TLuaResult> Result;
|
||||||
std::vector<TLuaValue> Args;
|
std::vector<TLuaArgTypes> Args;
|
||||||
std::string EventName; // optional, may be empty
|
std::string EventName; // optional, may be empty
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -167,7 +149,7 @@ public:
|
|||||||
void ReportErrors(const std::vector<std::shared_ptr<TLuaResult>>& Results);
|
void ReportErrors(const std::vector<std::shared_ptr<TLuaResult>>& Results);
|
||||||
bool HasState(TLuaStateId StateId);
|
bool HasState(TLuaStateId StateId);
|
||||||
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script);
|
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueScript(TLuaStateId StateID, const TLuaChunk& Script);
|
||||||
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector<TLuaValue>& Args);
|
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector<TLuaArgTypes>& Args);
|
||||||
void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false);
|
void EnsureStateExists(TLuaStateId StateId, const std::string& Name, bool DontCallOnInit = false);
|
||||||
void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName);
|
void RegisterEvent(const std::string& EventName, TLuaStateId StateId, const std::string& FunctionName);
|
||||||
/**
|
/**
|
||||||
@@ -187,7 +169,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<TLuaResult>> Results;
|
std::vector<std::shared_ptr<TLuaResult>> Results;
|
||||||
std::vector<TLuaValue> Arguments { TLuaValue { std::forward<ArgsT>(Args) }... };
|
std::vector<TLuaArgTypes> Arguments { TLuaArgTypes { std::forward<ArgsT>(Args) }... };
|
||||||
|
|
||||||
for (const auto& Event : mLuaEvents.at(EventName)) {
|
for (const auto& Event : mLuaEvents.at(EventName)) {
|
||||||
for (const auto& Function : Event.second) {
|
for (const auto& Function : Event.second) {
|
||||||
@@ -206,7 +188,7 @@ public:
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
std::vector<std::shared_ptr<TLuaResult>> Results;
|
std::vector<std::shared_ptr<TLuaResult>> Results;
|
||||||
std::vector<TLuaValue> Arguments { TLuaValue { std::forward<ArgsT>(Args) }... };
|
std::vector<TLuaArgTypes> Arguments { TLuaArgTypes { std::forward<ArgsT>(Args) }... };
|
||||||
const auto Handlers = GetEventHandlersForState(EventName, StateId);
|
const auto Handlers = GetEventHandlersForState(EventName, StateId);
|
||||||
for (const auto& Handler : Handlers) {
|
for (const auto& Handler : Handlers) {
|
||||||
Results.push_back(EnqueueFunctionCall(StateId, Handler, Arguments));
|
Results.push_back(EnqueueFunctionCall(StateId, Handler, Arguments));
|
||||||
@@ -243,8 +225,8 @@ private:
|
|||||||
StateThreadData(const StateThreadData&) = delete;
|
StateThreadData(const StateThreadData&) = delete;
|
||||||
virtual ~StateThreadData() noexcept { beammp_debug("\"" + mStateId + "\" destroyed"); }
|
virtual ~StateThreadData() noexcept { beammp_debug("\"" + mStateId + "\" destroyed"); }
|
||||||
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueScript(const TLuaChunk& Script);
|
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueScript(const TLuaChunk& Script);
|
||||||
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCall(const std::string& FunctionName, const std::vector<TLuaValue>& Args);
|
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCall(const std::string& FunctionName, const std::vector<TLuaArgTypes>& Args);
|
||||||
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCallFromCustomEvent(const std::string& FunctionName, const std::vector<TLuaValue>& Args, const std::string& EventName, CallStrategy Strategy);
|
[[nodiscard]] std::shared_ptr<TLuaResult> EnqueueFunctionCallFromCustomEvent(const std::string& FunctionName, const std::vector<TLuaArgTypes>& Args, const std::string& EventName, CallStrategy Strategy);
|
||||||
void RegisterEvent(const std::string& EventName, const std::string& FunctionName);
|
void RegisterEvent(const std::string& EventName, const std::string& FunctionName);
|
||||||
void AddPath(const fs::path& Path); // to be added to path and cpath
|
void AddPath(const fs::path& Path); // to be added to path and cpath
|
||||||
void operator()() override;
|
void operator()() override;
|
||||||
@@ -271,9 +253,6 @@ private:
|
|||||||
sol::table Lua_FS_ListFiles(const std::string& Path);
|
sol::table Lua_FS_ListFiles(const std::string& Path);
|
||||||
sol::table Lua_FS_ListDirectories(const std::string& Path);
|
sol::table Lua_FS_ListDirectories(const std::string& Path);
|
||||||
|
|
||||||
prof::UnitProfileCollection mProfile {};
|
|
||||||
std::unordered_map<std::string, prof::TimePoint> mProfileStarts;
|
|
||||||
|
|
||||||
std::string mName;
|
std::string mName;
|
||||||
TLuaStateId mStateId;
|
TLuaStateId mStateId;
|
||||||
lua_State* mState;
|
lua_State* mState;
|
||||||
@@ -289,7 +268,6 @@ private:
|
|||||||
std::recursive_mutex mPathsMutex;
|
std::recursive_mutex mPathsMutex;
|
||||||
std::mt19937 mMersenneTwister;
|
std::mt19937 mMersenneTwister;
|
||||||
std::uniform_real_distribution<double> mUniformRealDistribution01;
|
std::uniform_real_distribution<double> mUniformRealDistribution01;
|
||||||
std::vector<sol::object> JsonStringToArray(JsonString Str);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TimedEvent {
|
struct TimedEvent {
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ private:
|
|||||||
TResourceManager& mResourceManager;
|
TResourceManager& mResourceManager;
|
||||||
std::thread mUDPThread;
|
std::thread mUDPThread;
|
||||||
std::thread mTCPThread;
|
std::thread mTCPThread;
|
||||||
std::mutex mOpenIDMutex;
|
|
||||||
|
|
||||||
std::vector<uint8_t> UDPRcvFromClient(ip::udp::endpoint& ClientEndpoint);
|
std::vector<uint8_t> UDPRcvFromClient(ip::udp::endpoint& ClientEndpoint);
|
||||||
void HandleDownload(TConnection&& TCPSock);
|
void HandleDownload(TConnection&& TCPSock);
|
||||||
|
|||||||
@@ -121,14 +121,6 @@ void TClient::SetCarData(int Ident, const std::string& Data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int TClient::GetCarCount() const {
|
int TClient::GetCarCount() const {
|
||||||
// mVechileData holds both unicycle and cars which both count towards the maximum car count
|
|
||||||
// spawning a unicycle meant reaching the max, hence being unable to spawn car. this dirty fixes the problem for now.
|
|
||||||
std::unique_lock lock(mVehicleDataMutex);
|
|
||||||
for (auto& v : mVehicleData) {
|
|
||||||
if (v.ID() == mUnicycleID) {
|
|
||||||
return int(mVehicleData.size() - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return int(mVehicleData.size());
|
return int(mVehicleData.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -222,7 +222,7 @@ void Application::CheckForUpdates() {
|
|||||||
auto RemoteVersion = Version(VersionStrToInts(Response));
|
auto RemoteVersion = Version(VersionStrToInts(Response));
|
||||||
if (IsOutdated(MyVersion, RemoteVersion)) {
|
if (IsOutdated(MyVersion, RemoteVersion)) {
|
||||||
std::string RealVersionString = std::string("v") + RemoteVersion.AsString();
|
std::string RealVersionString = std::string("v") + RemoteVersion.AsString();
|
||||||
const std::string DefaultUpdateMsg = "NEW VERSION IS OUT! Please update to the new version ({}) of the BeamMP-Server! Download it here: https://beammp.com/! For a guide on how to update, visit: https://docs.beammp.com/server/server-maintenance/#updating-the-server";
|
const std::string DefaultUpdateMsg = "NEW VERSION IS OUT! Please update to the new version ({}) of the BeamMP-Server! Download it here: https://beammp.com/! For a guide on how to update, visit: https://wiki.beammp.com/en/home/server-maintenance#updating-the-server";
|
||||||
auto UpdateMsg = Env::Get(Env::Key::PROVIDER_UPDATE_MESSAGE).value_or(DefaultUpdateMsg);
|
auto UpdateMsg = Env::Get(Env::Key::PROVIDER_UPDATE_MESSAGE).value_or(DefaultUpdateMsg);
|
||||||
UpdateMsg = fmt::vformat(std::string_view(UpdateMsg), fmt::make_format_args(RealVersionString));
|
UpdateMsg = fmt::vformat(std::string_view(UpdateMsg), fmt::make_format_args(RealVersionString));
|
||||||
beammp_warnf("{}{}{}", ANSI_YELLOW_BOLD, UpdateMsg, ANSI_RESET);
|
beammp_warnf("{}{}{}", ANSI_YELLOW_BOLD, UpdateMsg, ANSI_RESET);
|
||||||
|
|||||||
@@ -33,12 +33,6 @@ std::string_view Env::ToString(Env::Key key) {
|
|||||||
case Key::PROVIDER_UPDATE_MESSAGE:
|
case Key::PROVIDER_UPDATE_MESSAGE:
|
||||||
return "BEAMMP_PROVIDER_UPDATE_MESSAGE";
|
return "BEAMMP_PROVIDER_UPDATE_MESSAGE";
|
||||||
break;
|
break;
|
||||||
case Key::PROVIDER_DISABLE_CONFIG:
|
|
||||||
return "BEAMMP_PROVIDER_DISABLE_CONFIG";
|
|
||||||
break;
|
|
||||||
case Key::PROVIDER_PORT_ENV:
|
|
||||||
return "BEAMMP_PROVIDER_PORT_ENV";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
#include "Profiling.h"
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
prof::Duration prof::duration(const TimePoint& start, const TimePoint& end) {
|
|
||||||
return end - start;
|
|
||||||
}
|
|
||||||
prof::TimePoint prof::now() {
|
|
||||||
return std::chrono::high_resolution_clock::now();
|
|
||||||
}
|
|
||||||
prof::Stats prof::UnitProfileCollection::stats(const std::string& unit) {
|
|
||||||
return m_map->operator[](unit).stats();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t prof::UnitProfileCollection::measurement_count(const std::string& unit) {
|
|
||||||
return m_map->operator[](unit).measurement_count();
|
|
||||||
}
|
|
||||||
|
|
||||||
void prof::UnitProfileCollection::add_sample(const std::string& unit, const Duration& duration) {
|
|
||||||
m_map->operator[](unit).add_sample(duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
prof::Stats prof::UnitExecutionTime::stats() const {
|
|
||||||
std::unique_lock lock(m_mtx);
|
|
||||||
Stats result {};
|
|
||||||
// calculate sum
|
|
||||||
result.n = m_total_calls;
|
|
||||||
result.max = m_min;
|
|
||||||
result.min = m_max;
|
|
||||||
// calculate mean: mean = sum_x / n
|
|
||||||
result.mean = m_sum / double(m_total_calls);
|
|
||||||
// calculate stdev: stdev = sqrt((sum_x2 / n) - (mean * mean))
|
|
||||||
result.stdev = std::sqrt((m_measurement_sqr_sum / double(result.n)) - (result.mean * result.mean));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void prof::UnitExecutionTime::add_sample(const Duration& dur) {
|
|
||||||
std::unique_lock lock(m_mtx);
|
|
||||||
m_sum += dur.count();
|
|
||||||
m_measurement_sqr_sum += dur.count() * dur.count();
|
|
||||||
m_min = std::min(dur.count(), m_min);
|
|
||||||
m_max = std::max(dur.count(), m_max);
|
|
||||||
++m_total_calls;
|
|
||||||
}
|
|
||||||
|
|
||||||
prof::UnitExecutionTime::UnitExecutionTime() {
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unordered_map<std::string, prof::Stats> prof::UnitProfileCollection::all_stats() {
|
|
||||||
auto map = m_map.synchronize();
|
|
||||||
std::unordered_map<std::string, Stats> result {};
|
|
||||||
for (const auto& [name, time] : *map) {
|
|
||||||
result[name] = time.stats();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
size_t prof::UnitExecutionTime::measurement_count() const {
|
|
||||||
std::unique_lock lock(m_mtx);
|
|
||||||
return m_total_calls;
|
|
||||||
}
|
|
||||||
|
|
||||||
+8
-37
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
#include "Env.h"
|
|
||||||
#include "TConfig.h"
|
#include "TConfig.h"
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@@ -88,9 +87,7 @@ TEST_CASE("TConfig::TConfig") {
|
|||||||
TConfig::TConfig(const std::string& ConfigFileName)
|
TConfig::TConfig(const std::string& ConfigFileName)
|
||||||
: mConfigFileName(ConfigFileName) {
|
: mConfigFileName(ConfigFileName) {
|
||||||
Application::SetSubsystemStatus("Config", Application::Status::Starting);
|
Application::SetSubsystemStatus("Config", Application::Status::Starting);
|
||||||
auto DisableConfig = Env::Get(Env::Key::PROVIDER_DISABLE_CONFIG).value_or("false");
|
if (!fs::exists(mConfigFileName) || !fs::is_regular_file(mConfigFileName)) {
|
||||||
mDisableConfig = DisableConfig == "true" || DisableConfig == "1";
|
|
||||||
if (!mDisableConfig && (!fs::exists(mConfigFileName) || !fs::is_regular_file(mConfigFileName))) {
|
|
||||||
beammp_info("No config file found! Generating one...");
|
beammp_info("No config file found! Generating one...");
|
||||||
CreateConfigFile();
|
CreateConfigFile();
|
||||||
}
|
}
|
||||||
@@ -146,7 +143,7 @@ void TConfig::FlushToFile() {
|
|||||||
SetComment(data["Misc"][StrSendErrorsMessageEnabled.data()].comments(), " You can turn on/off the SendErrors message you get on startup here");
|
SetComment(data["Misc"][StrSendErrorsMessageEnabled.data()].comments(), " You can turn on/off the SendErrors message you get on startup here");
|
||||||
std::stringstream Ss;
|
std::stringstream Ss;
|
||||||
Ss << "# This is the BeamMP-Server config file.\n"
|
Ss << "# This is the BeamMP-Server config file.\n"
|
||||||
"# Help & Documentation: `https://docs.beammp.com/server/server-maintenance/`\n"
|
"# Help & Documentation: `https://wiki.beammp.com/en/home/server-maintenance`\n"
|
||||||
"# IMPORTANT: Fill in the AuthKey with the key you got from `https://keymaster.beammp.com/` on the left under \"Keys\"\n"
|
"# IMPORTANT: Fill in the AuthKey with the key you got from `https://keymaster.beammp.com/` on the left under \"Keys\"\n"
|
||||||
<< data;
|
<< data;
|
||||||
auto File = std::fopen(mConfigFileName.c_str(), "w+");
|
auto File = std::fopen(mConfigFileName.c_str(), "w+");
|
||||||
@@ -164,9 +161,7 @@ void TConfig::FlushToFile() {
|
|||||||
|
|
||||||
void TConfig::CreateConfigFile() {
|
void TConfig::CreateConfigFile() {
|
||||||
// build from old config Server.cfg
|
// build from old config Server.cfg
|
||||||
if (mDisableConfig) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
if (fs::exists("Server.cfg")) {
|
if (fs::exists("Server.cfg")) {
|
||||||
// parse it (this is weird and bad and should be removed in some future version)
|
// parse it (this is weird and bad and should be removed in some future version)
|
||||||
@@ -186,9 +181,6 @@ void TConfig::TryReadValue(toml::value& Table, const std::string& Category, cons
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mDisableConfig) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Table[Category.c_str()][Key.data()].is_string()) {
|
if (Table[Category.c_str()][Key.data()].is_string()) {
|
||||||
OutValue = Table[Category.c_str()][Key.data()].as_string();
|
OutValue = Table[Category.c_str()][Key.data()].as_string();
|
||||||
}
|
}
|
||||||
@@ -202,9 +194,6 @@ void TConfig::TryReadValue(toml::value& Table, const std::string& Category, cons
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mDisableConfig) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Table[Category.c_str()][Key.data()].is_boolean()) {
|
if (Table[Category.c_str()][Key.data()].is_boolean()) {
|
||||||
OutValue = Table[Category.c_str()][Key.data()].as_boolean();
|
OutValue = Table[Category.c_str()][Key.data()].as_boolean();
|
||||||
}
|
}
|
||||||
@@ -217,9 +206,6 @@ void TConfig::TryReadValue(toml::value& Table, const std::string& Category, cons
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mDisableConfig) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Table[Category.c_str()][Key.data()].is_integer()) {
|
if (Table[Category.c_str()][Key.data()].is_integer()) {
|
||||||
OutValue = int(Table[Category.c_str()][Key.data()].as_integer());
|
OutValue = int(Table[Category.c_str()][Key.data()].as_integer());
|
||||||
}
|
}
|
||||||
@@ -227,18 +213,11 @@ void TConfig::TryReadValue(toml::value& Table, const std::string& Category, cons
|
|||||||
|
|
||||||
void TConfig::ParseFromFile(std::string_view name) {
|
void TConfig::ParseFromFile(std::string_view name) {
|
||||||
try {
|
try {
|
||||||
toml::value data {};
|
toml::value data = toml::parse<toml::preserve_comments>(name.data());
|
||||||
if (!mDisableConfig) {
|
|
||||||
data = toml::parse<toml::preserve_comments>(name.data());
|
|
||||||
}
|
|
||||||
// GENERAL
|
// GENERAL
|
||||||
TryReadValue(data, "General", StrDebug, EnvStrDebug, Application::Settings.DebugModeEnabled);
|
TryReadValue(data, "General", StrDebug, EnvStrDebug, Application::Settings.DebugModeEnabled);
|
||||||
TryReadValue(data, "General", StrPrivate, EnvStrPrivate, Application::Settings.Private);
|
TryReadValue(data, "General", StrPrivate, EnvStrPrivate, Application::Settings.Private);
|
||||||
if (Env::Get(Env::Key::PROVIDER_PORT_ENV).has_value()) {
|
TryReadValue(data, "General", StrPort, EnvStrPort, Application::Settings.Port);
|
||||||
TryReadValue(data, "General", StrPort, Env::Get(Env::Key::PROVIDER_PORT_ENV).value(), Application::Settings.Port);
|
|
||||||
} else {
|
|
||||||
TryReadValue(data, "General", StrPort, EnvStrPort, Application::Settings.Port);
|
|
||||||
}
|
|
||||||
TryReadValue(data, "General", StrMaxCars, EnvStrMaxCars, Application::Settings.MaxCars);
|
TryReadValue(data, "General", StrMaxCars, EnvStrMaxCars, Application::Settings.MaxCars);
|
||||||
TryReadValue(data, "General", StrMaxPlayers, EnvStrMaxPlayers, Application::Settings.MaxPlayers);
|
TryReadValue(data, "General", StrMaxPlayers, EnvStrMaxPlayers, Application::Settings.MaxPlayers);
|
||||||
TryReadValue(data, "General", StrMap, EnvStrMap, Application::Settings.MapName);
|
TryReadValue(data, "General", StrMap, EnvStrMap, Application::Settings.MapName);
|
||||||
@@ -259,18 +238,13 @@ void TConfig::ParseFromFile(std::string_view name) {
|
|||||||
Application::SetSubsystemStatus("Config", Application::Status::Bad);
|
Application::SetSubsystemStatus("Config", Application::Status::Bad);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
PrintDebug();
|
||||||
|
|
||||||
// Update in any case
|
// Update in any case
|
||||||
if (!mDisableConfig) {
|
FlushToFile();
|
||||||
FlushToFile();
|
|
||||||
}
|
|
||||||
// all good so far, let's check if there's a key
|
// all good so far, let's check if there's a key
|
||||||
if (Application::Settings.Key.empty()) {
|
if (Application::Settings.Key.empty()) {
|
||||||
if (mDisableConfig) {
|
beammp_error("No AuthKey specified in the \"" + std::string(mConfigFileName) + "\" file. Please get an AuthKey, enter it into the config file, and restart this server.");
|
||||||
beammp_error("No AuthKey specified in the environment.");
|
|
||||||
} else {
|
|
||||||
beammp_error("No AuthKey specified in the \"" + std::string(mConfigFileName) + "\" file. Please get an AuthKey, enter it into the config file, and restart this server.");
|
|
||||||
}
|
|
||||||
Application::SetSubsystemStatus("Config", Application::Status::Bad);
|
Application::SetSubsystemStatus("Config", Application::Status::Bad);
|
||||||
mFailed = true;
|
mFailed = true;
|
||||||
return;
|
return;
|
||||||
@@ -282,9 +256,6 @@ void TConfig::ParseFromFile(std::string_view name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TConfig::PrintDebug() {
|
void TConfig::PrintDebug() {
|
||||||
if (mDisableConfig) {
|
|
||||||
beammp_debug("Provider turned off the generation and parsing of the ServerConfig.toml");
|
|
||||||
}
|
|
||||||
beammp_debug(std::string(StrDebug) + ": " + std::string(Application::Settings.DebugModeEnabled ? "true" : "false"));
|
beammp_debug(std::string(StrDebug) + ": " + std::string(Application::Settings.DebugModeEnabled ? "true" : "false"));
|
||||||
beammp_debug(std::string(StrPrivate) + ": " + std::string(Application::Settings.Private ? "true" : "false"));
|
beammp_debug(std::string(StrPrivate) + ": " + std::string(Application::Settings.Private ? "true" : "false"));
|
||||||
beammp_debug(std::string(StrPort) + ": " + std::to_string(Application::Settings.Port));
|
beammp_debug(std::string(StrPort) + ": " + std::to_string(Application::Settings.Port));
|
||||||
|
|||||||
+1
-10
@@ -247,8 +247,7 @@ void TConsole::Command_Help(const std::string&, const std::vector<std::string>&
|
|||||||
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)";
|
|
||||||
Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString));
|
Application::Console().WriteRaw("BeamMP-Server Console: " + std::string(sHelpString));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,14 +267,6 @@ void TConsole::Command_Clear(const std::string&, const std::vector<std::string>&
|
|||||||
mCommandline->write("\x1b[;H\x1b[2J");
|
mCommandline->write("\x1b[;H\x1b[2J");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TConsole::Command_Version(const std::string& cmd, const std::vector<std::string>& args) {
|
|
||||||
if (!EnsureArgsCount(args, 0)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Application::Console().WriteRaw("Current version: v" + Application::ServerVersionString());
|
|
||||||
}
|
|
||||||
|
|
||||||
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))) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+20
-138
@@ -18,17 +18,14 @@
|
|||||||
|
|
||||||
#include "TLuaEngine.h"
|
#include "TLuaEngine.h"
|
||||||
#include "Client.h"
|
#include "Client.h"
|
||||||
#include "Common.h"
|
|
||||||
#include "CustomAssert.h"
|
#include "CustomAssert.h"
|
||||||
#include "Http.h"
|
#include "Http.h"
|
||||||
#include "LuaAPI.h"
|
#include "LuaAPI.h"
|
||||||
#include "Profiling.h"
|
|
||||||
#include "TLuaPlugin.h"
|
#include "TLuaPlugin.h"
|
||||||
#include "sol/object.hpp"
|
#include "sol/object.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <fmt/core.h>
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@@ -353,7 +350,7 @@ std::shared_ptr<TLuaResult> TLuaEngine::EnqueueScript(TLuaStateId StateID, const
|
|||||||
return mLuaStates.at(StateID)->EnqueueScript(Script);
|
return mLuaStates.at(StateID)->EnqueueScript(Script);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<TLuaResult> TLuaEngine::EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector<TLuaValue>& Args) {
|
std::shared_ptr<TLuaResult> TLuaEngine::EnqueueFunctionCall(TLuaStateId StateID, const std::string& FunctionName, const std::vector<TLuaArgTypes>& Args) {
|
||||||
std::unique_lock Lock(mLuaStatesMutex);
|
std::unique_lock Lock(mLuaStatesMutex);
|
||||||
return mLuaStates.at(StateID)->EnqueueFunctionCall(FunctionName, Args);
|
return mLuaStates.at(StateID)->EnqueueFunctionCall(FunctionName, Args);
|
||||||
}
|
}
|
||||||
@@ -362,30 +359,17 @@ void TLuaEngine::CollectAndInitPlugins() {
|
|||||||
if (!fs::exists(mResourceServerPath)) {
|
if (!fs::exists(mResourceServerPath)) {
|
||||||
fs::create_directories(mResourceServerPath);
|
fs::create_directories(mResourceServerPath);
|
||||||
}
|
}
|
||||||
|
for (const auto& Dir : fs::directory_iterator(mResourceServerPath)) {
|
||||||
std::vector<fs::path> PluginsEntries;
|
auto Path = Dir.path();
|
||||||
for (const auto& Entry : fs::directory_iterator(mResourceServerPath)) {
|
Path = fs::relative(Path);
|
||||||
if (Entry.is_directory()) {
|
if (!Dir.is_directory()) {
|
||||||
PluginsEntries.push_back(Entry);
|
beammp_error("\"" + Dir.path().string() + "\" is not a directory, skipping");
|
||||||
} else {
|
} else {
|
||||||
beammp_error("\"" + Entry.path().string() + "\" is not a directory, skipping");
|
TLuaPluginConfig Config { Path.stem().string() };
|
||||||
|
FindAndParseConfig(Path, Config);
|
||||||
|
InitializePlugin(Path, Config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(PluginsEntries.begin(), PluginsEntries.end(), [](const fs::path& first, const fs::path& second) {
|
|
||||||
auto firstStr = first.string();
|
|
||||||
auto secondStr = second.string();
|
|
||||||
std::transform(firstStr.begin(), firstStr.end(), firstStr.begin(), ::tolower);
|
|
||||||
std::transform(secondStr.begin(), secondStr.end(), secondStr.begin(), ::tolower);
|
|
||||||
return firstStr < secondStr;
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const auto& Dir : PluginsEntries) {
|
|
||||||
auto Path = fs::relative(Dir);
|
|
||||||
TLuaPluginConfig Config { Path.stem().string() };
|
|
||||||
FindAndParseConfig(Path, Config);
|
|
||||||
InitializePlugin(Path, Config);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TLuaEngine::InitializePlugin(const fs::path& Folder, const TLuaPluginConfig& Config) {
|
void TLuaEngine::InitializePlugin(const fs::path& Folder, const TLuaPluginConfig& Config) {
|
||||||
@@ -446,50 +430,13 @@ std::set<std::string> TLuaEngine::GetEventHandlersForState(const std::string& Ev
|
|||||||
return mLuaEvents[EventName][StateId];
|
return mLuaEvents[EventName][StateId];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<sol::object> TLuaEngine::StateThreadData::JsonStringToArray(JsonString Str) {
|
|
||||||
auto LocalTable = Lua_JsonDecode(Str.value).as<std::vector<sol::object>>();
|
|
||||||
for (auto& value : LocalTable) {
|
|
||||||
if (value.is<std::string>() && value.as<std::string>() == BEAMMP_INTERNAL_NIL) {
|
|
||||||
value = sol::object {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return LocalTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string& EventName, sol::variadic_args EventArgs) {
|
sol::table TLuaEngine::StateThreadData::Lua_TriggerGlobalEvent(const std::string& EventName, sol::variadic_args EventArgs) {
|
||||||
auto Table = mStateView.create_table();
|
auto Return = mEngine->TriggerEvent(EventName, mStateId, EventArgs);
|
||||||
for (const sol::stack_proxy& Arg : EventArgs) {
|
|
||||||
switch (Arg.get_type()) {
|
|
||||||
case sol::type::none:
|
|
||||||
case sol::type::userdata:
|
|
||||||
case sol::type::lightuserdata:
|
|
||||||
case sol::type::thread:
|
|
||||||
case sol::type::function:
|
|
||||||
case sol::type::poly:
|
|
||||||
Table.add(BEAMMP_INTERNAL_NIL);
|
|
||||||
beammp_warnf("Passed a value of type '{}' to TriggerGlobalEvent(\"{}\", ...). This type can not be serialized, and cannot be passed between states. It will arrive as <nil> in handlers.", sol::type_name(EventArgs.lua_state(), Arg.get_type()), EventName);
|
|
||||||
break;
|
|
||||||
case sol::type::lua_nil:
|
|
||||||
Table.add(BEAMMP_INTERNAL_NIL);
|
|
||||||
break;
|
|
||||||
case sol::type::string:
|
|
||||||
case sol::type::number:
|
|
||||||
case sol::type::boolean:
|
|
||||||
case sol::type::table:
|
|
||||||
Table.add(Arg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
JsonString Str { LuaAPI::MP::JsonEncode(Table) };
|
|
||||||
beammp_debugf("json: {}", Str.value);
|
|
||||||
auto Return = mEngine->TriggerEvent(EventName, mStateId, Str);
|
|
||||||
auto MyHandlers = mEngine->GetEventHandlersForState(EventName, mStateId);
|
auto MyHandlers = mEngine->GetEventHandlersForState(EventName, mStateId);
|
||||||
|
|
||||||
sol::variadic_results LocalArgs = JsonStringToArray(Str);
|
|
||||||
for (const auto& Handler : MyHandlers) {
|
for (const auto& Handler : MyHandlers) {
|
||||||
auto Fn = mStateView[Handler];
|
auto Fn = mStateView[Handler];
|
||||||
if (Fn.valid()) {
|
if (Fn.valid()) {
|
||||||
auto LuaResult = Fn(LocalArgs);
|
auto LuaResult = Fn(EventArgs);
|
||||||
auto Result = std::make_shared<TLuaResult>();
|
auto Result = std::make_shared<TLuaResult>();
|
||||||
if (LuaResult.valid()) {
|
if (LuaResult.valid()) {
|
||||||
Result->Error = false;
|
Result->Error = false;
|
||||||
@@ -711,7 +658,6 @@ static void AddToTable(sol::table& table, const std::string& left, const T& valu
|
|||||||
static void JsonDecodeRecursive(sol::state_view& StateView, sol::table& table, const std::string& left, const nlohmann::json& right) {
|
static void JsonDecodeRecursive(sol::state_view& StateView, sol::table& table, const std::string& left, const nlohmann::json& right) {
|
||||||
switch (right.type()) {
|
switch (right.type()) {
|
||||||
case nlohmann::detail::value_t::null:
|
case nlohmann::detail::value_t::null:
|
||||||
AddToTable(table, left, sol::lua_nil_t {});
|
|
||||||
return;
|
return;
|
||||||
case nlohmann::detail::value_t::object: {
|
case nlohmann::detail::value_t::object: {
|
||||||
auto value = table.create();
|
auto value = table.create();
|
||||||
@@ -883,40 +829,6 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI
|
|||||||
MPTable.set_function("Set", &LuaAPI::MP::Set);
|
MPTable.set_function("Set", &LuaAPI::MP::Set);
|
||||||
|
|
||||||
auto UtilTable = StateView.create_named_table("Util");
|
auto UtilTable = StateView.create_named_table("Util");
|
||||||
UtilTable.set_function("LogDebug", [this](sol::variadic_args args) {
|
|
||||||
std::string ToPrint = "";
|
|
||||||
for (const auto& arg : args) {
|
|
||||||
ToPrint += LuaAPI::LuaToString(static_cast<const sol::object>(arg));
|
|
||||||
ToPrint += "\t";
|
|
||||||
}
|
|
||||||
if (Application::Settings.DebugModeEnabled) {
|
|
||||||
beammp_lua_log("DEBUG", mStateId, ToPrint);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
UtilTable.set_function("LogInfo", [this](sol::variadic_args args) {
|
|
||||||
std::string ToPrint = "";
|
|
||||||
for (const auto& arg : args) {
|
|
||||||
ToPrint += LuaAPI::LuaToString(static_cast<const sol::object>(arg));
|
|
||||||
ToPrint += "\t";
|
|
||||||
}
|
|
||||||
beammp_lua_log("INFO", mStateId, ToPrint);
|
|
||||||
});
|
|
||||||
UtilTable.set_function("LogWarn", [this](sol::variadic_args args) {
|
|
||||||
std::string ToPrint = "";
|
|
||||||
for (const auto& arg : args) {
|
|
||||||
ToPrint += LuaAPI::LuaToString(static_cast<const sol::object>(arg));
|
|
||||||
ToPrint += "\t";
|
|
||||||
}
|
|
||||||
beammp_lua_log("WARN", mStateId, ToPrint);
|
|
||||||
});
|
|
||||||
UtilTable.set_function("LogError", [this](sol::variadic_args args) {
|
|
||||||
std::string ToPrint = "";
|
|
||||||
for (const auto& arg : args) {
|
|
||||||
ToPrint += LuaAPI::LuaToString(static_cast<const sol::object>(arg));
|
|
||||||
ToPrint += "\t";
|
|
||||||
}
|
|
||||||
beammp_lua_log("ERROR", mStateId, ToPrint);
|
|
||||||
});
|
|
||||||
UtilTable.set_function("JsonEncode", &LuaAPI::MP::JsonEncode);
|
UtilTable.set_function("JsonEncode", &LuaAPI::MP::JsonEncode);
|
||||||
UtilTable.set_function("JsonDecode", [this](const std::string& str) {
|
UtilTable.set_function("JsonDecode", [this](const std::string& str) {
|
||||||
return Lua_JsonDecode(str);
|
return Lua_JsonDecode(str);
|
||||||
@@ -935,30 +847,6 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, TLuaStateI
|
|||||||
UtilTable.set_function("RandomIntRange", [this](int64_t min, int64_t max) -> int64_t {
|
UtilTable.set_function("RandomIntRange", [this](int64_t min, int64_t max) -> int64_t {
|
||||||
return std::uniform_int_distribution(min, max)(mMersenneTwister);
|
return std::uniform_int_distribution(min, max)(mMersenneTwister);
|
||||||
});
|
});
|
||||||
UtilTable.set_function("DebugExecutionTime", [this]() -> sol::table {
|
|
||||||
sol::state_view StateView(mState);
|
|
||||||
sol::table Result = StateView.create_table();
|
|
||||||
auto stats = mProfile.all_stats();
|
|
||||||
for (const auto& [name, stat] : stats) {
|
|
||||||
Result[name] = StateView.create_table();
|
|
||||||
Result[name]["mean"] = stat.mean;
|
|
||||||
Result[name]["stdev"] = stat.stdev;
|
|
||||||
Result[name]["min"] = stat.min;
|
|
||||||
Result[name]["max"] = stat.max;
|
|
||||||
Result[name]["n"] = stat.n;
|
|
||||||
}
|
|
||||||
return Result;
|
|
||||||
});
|
|
||||||
UtilTable.set_function("DebugStartProfile", [this](const std::string& name) {
|
|
||||||
mProfileStarts[name] = prof::now();
|
|
||||||
});
|
|
||||||
UtilTable.set_function("DebugStopProfile", [this](const std::string& name) {
|
|
||||||
if (!mProfileStarts.contains(name)) {
|
|
||||||
beammp_lua_errorf("DebugStopProfile('{}') failed, because a profile for '{}' wasn't started", name, name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mProfile.add_sample(name, prof::duration(mProfileStarts.at(name), prof::now()));
|
|
||||||
});
|
|
||||||
|
|
||||||
auto HttpTable = StateView.create_named_table("Http");
|
auto HttpTable = StateView.create_named_table("Http");
|
||||||
HttpTable.set_function("CreateConnection", [this](const std::string& host, uint16_t port) {
|
HttpTable.set_function("CreateConnection", [this](const std::string& host, uint16_t port) {
|
||||||
@@ -1006,7 +894,7 @@ std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueScript(const TLu
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCallFromCustomEvent(const std::string& FunctionName, const std::vector<TLuaValue>& Args, const std::string& EventName, CallStrategy Strategy) {
|
std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCallFromCustomEvent(const std::string& FunctionName, const std::vector<TLuaArgTypes>& Args, const std::string& EventName, CallStrategy Strategy) {
|
||||||
// TODO: Document all this
|
// TODO: Document all this
|
||||||
decltype(mStateFunctionQueue)::iterator Iter = mStateFunctionQueue.end();
|
decltype(mStateFunctionQueue)::iterator Iter = mStateFunctionQueue.end();
|
||||||
if (Strategy == CallStrategy::BestEffort) {
|
if (Strategy == CallStrategy::BestEffort) {
|
||||||
@@ -1028,7 +916,7 @@ std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCallFrom
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCall(const std::string& FunctionName, const std::vector<TLuaValue>& Args) {
|
std::shared_ptr<TLuaResult> TLuaEngine::StateThreadData::EnqueueFunctionCall(const std::string& FunctionName, const std::vector<TLuaArgTypes>& Args) {
|
||||||
auto Result = std::make_shared<TLuaResult>();
|
auto Result = std::make_shared<TLuaResult>();
|
||||||
Result->StateId = mStateId;
|
Result->StateId = mStateId;
|
||||||
Result->Function = FunctionName;
|
Result->Function = FunctionName;
|
||||||
@@ -1096,7 +984,6 @@ void TLuaEngine::StateThreadData::operator()() {
|
|||||||
std::chrono::milliseconds(500),
|
std::chrono::milliseconds(500),
|
||||||
[&]() -> bool { return !mStateFunctionQueue.empty(); });
|
[&]() -> bool { return !mStateFunctionQueue.empty(); });
|
||||||
if (NotExpired) {
|
if (NotExpired) {
|
||||||
auto ProfStart = prof::now();
|
|
||||||
auto TheQueuedFunction = std::move(mStateFunctionQueue.front());
|
auto TheQueuedFunction = std::move(mStateFunctionQueue.front());
|
||||||
mStateFunctionQueue.erase(mStateFunctionQueue.begin());
|
mStateFunctionQueue.erase(mStateFunctionQueue.begin());
|
||||||
Lock.unlock();
|
Lock.unlock();
|
||||||
@@ -1114,21 +1001,19 @@ void TLuaEngine::StateThreadData::operator()() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (Arg.index()) {
|
switch (Arg.index()) {
|
||||||
case TLuaType::String:
|
case TLuaArgTypes_String:
|
||||||
LuaArgs.push_back(sol::make_object(StateView, std::get<std::string>(Arg)));
|
LuaArgs.push_back(sol::make_object(StateView, std::get<std::string>(Arg)));
|
||||||
break;
|
break;
|
||||||
case TLuaType::Int:
|
case TLuaArgTypes_Int:
|
||||||
LuaArgs.push_back(sol::make_object(StateView, std::get<int>(Arg)));
|
LuaArgs.push_back(sol::make_object(StateView, std::get<int>(Arg)));
|
||||||
break;
|
break;
|
||||||
case TLuaType::Json: {
|
case TLuaArgTypes_VariadicArgs:
|
||||||
auto LocalArgs = JsonStringToArray(std::get<JsonString>(Arg));
|
LuaArgs.push_back(sol::make_object(StateView, std::get<sol::variadic_args>(Arg)));
|
||||||
LuaArgs.insert(LuaArgs.end(), LocalArgs.begin(), LocalArgs.end());
|
|
||||||
break;
|
break;
|
||||||
}
|
case TLuaArgTypes_Bool:
|
||||||
case TLuaType::Bool:
|
|
||||||
LuaArgs.push_back(sol::make_object(StateView, std::get<bool>(Arg)));
|
LuaArgs.push_back(sol::make_object(StateView, std::get<bool>(Arg)));
|
||||||
break;
|
break;
|
||||||
case TLuaType::StringStringMap: {
|
case TLuaArgTypes_StringStringMap: {
|
||||||
auto Map = std::get<std::unordered_map<std::string, std::string>>(Arg);
|
auto Map = std::get<std::unordered_map<std::string, std::string>>(Arg);
|
||||||
auto Table = StateView.create_table();
|
auto Table = StateView.create_table();
|
||||||
for (const auto& [k, v] : Map) {
|
for (const auto& [k, v] : Map) {
|
||||||
@@ -1157,9 +1042,6 @@ void TLuaEngine::StateThreadData::operator()() {
|
|||||||
Result->ErrorMessage = BeamMPFnNotFoundError; // special error kind that we can ignore later
|
Result->ErrorMessage = BeamMPFnNotFoundError; // special error kind that we can ignore later
|
||||||
Result->MarkAsReady();
|
Result->MarkAsReady();
|
||||||
}
|
}
|
||||||
auto ProfEnd = prof::now();
|
|
||||||
auto ProfDuration = prof::duration(ProfStart, ProfEnd);
|
|
||||||
mProfile.add_sample(FnName, ProfDuration);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1219,7 +1101,7 @@ void TLuaResult::MarkAsReady() {
|
|||||||
void TLuaResult::WaitUntilReady() {
|
void TLuaResult::WaitUntilReady() {
|
||||||
std::unique_lock readyLock(*this->ReadyMutex);
|
std::unique_lock readyLock(*this->ReadyMutex);
|
||||||
// wait if not ready yet
|
// wait if not ready yet
|
||||||
if (!this->Ready)
|
if(!this->Ready)
|
||||||
this->ReadyCondition->wait(readyLock);
|
this->ReadyCondition->wait(readyLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -630,7 +630,6 @@ void TNetwork::OnDisconnect(const std::weak_ptr<TClient>& ClientPtr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int TNetwork::OpenID() {
|
int TNetwork::OpenID() {
|
||||||
std::unique_lock OpenIDLock(mOpenIDMutex);
|
|
||||||
int ID = 0;
|
int ID = 0;
|
||||||
bool found;
|
bool found;
|
||||||
do {
|
do {
|
||||||
|
|||||||
+3
-6
@@ -65,13 +65,10 @@ void TPPSMonitor::operator()() {
|
|||||||
V += c->GetCarCount();
|
V += c->GetCarCount();
|
||||||
}
|
}
|
||||||
// kick on "no ping"
|
// kick on "no ping"
|
||||||
if (c->SecondsSinceLastPing() > (20 * 60) ){
|
if (c->SecondsSinceLastPing() > (20 * 60)) {
|
||||||
beammp_debugf("client {} ({}) timing out: {}", c->GetID(), c->GetName(), c->SecondsSinceLastPing());
|
beammp_debug("client " + std::string("(") + std::to_string(c->GetID()) + ")" + c->GetName() + " timing out: " + std::to_string(c->SecondsSinceLastPing()) + ", pps: " + Application::PPS());
|
||||||
TimedOutClients.push_back(c);
|
TimedOutClients.push_back(c);
|
||||||
} else if (c->IsSynced() && c->SecondsSinceLastPing() > (1 * 60)) {
|
}
|
||||||
beammp_debugf("client {} ({}) timing out: {}", c->GetName(), c->GetID(), c->SecondsSinceLastPing());
|
|
||||||
TimedOutClients.push_back(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-24
@@ -30,7 +30,6 @@
|
|||||||
#include "TResourceManager.h"
|
#include "TResourceManager.h"
|
||||||
#include "TServer.h"
|
#include "TServer.h"
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
@@ -41,9 +40,6 @@ USAGE:
|
|||||||
ARGUMENTS:
|
ARGUMENTS:
|
||||||
--help
|
--help
|
||||||
Displays this help and exits.
|
Displays this help and exits.
|
||||||
--port=1234
|
|
||||||
Sets the server's listening TCP and
|
|
||||||
UDP port. Overrides ENV and ServerConfig.
|
|
||||||
--config=/path/to/ServerConfig.toml
|
--config=/path/to/ServerConfig.toml
|
||||||
Absolute or relative path to the
|
Absolute or relative path to the
|
||||||
Server Config file, including the
|
Server Config file, including the
|
||||||
@@ -95,7 +91,6 @@ int BeamMPServerMain(MainArguments Arguments) {
|
|||||||
Parser.RegisterArgument({ "help" }, ArgsParser::NONE);
|
Parser.RegisterArgument({ "help" }, ArgsParser::NONE);
|
||||||
Parser.RegisterArgument({ "version" }, ArgsParser::NONE);
|
Parser.RegisterArgument({ "version" }, ArgsParser::NONE);
|
||||||
Parser.RegisterArgument({ "config" }, ArgsParser::HAS_VALUE);
|
Parser.RegisterArgument({ "config" }, ArgsParser::HAS_VALUE);
|
||||||
Parser.RegisterArgument({ "port" }, ArgsParser::HAS_VALUE);
|
|
||||||
Parser.RegisterArgument({ "working-directory" }, ArgsParser::HAS_VALUE);
|
Parser.RegisterArgument({ "working-directory" }, ArgsParser::HAS_VALUE);
|
||||||
Parser.Parse(Arguments.List);
|
Parser.Parse(Arguments.List);
|
||||||
if (!Parser.Verify()) {
|
if (!Parser.Verify()) {
|
||||||
@@ -129,7 +124,7 @@ int BeamMPServerMain(MainArguments Arguments) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TConfig Config(ConfigPath);
|
TConfig Config(ConfigPath);
|
||||||
|
|
||||||
if (Config.Failed()) {
|
if (Config.Failed()) {
|
||||||
@@ -140,24 +135,6 @@ int BeamMPServerMain(MainArguments Arguments) {
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// override port if provided via arguments
|
|
||||||
if (Parser.FoundArgument({ "port" })) {
|
|
||||||
auto Port = Parser.GetValueOfArgument({ "port" });
|
|
||||||
if (Port.has_value()) {
|
|
||||||
auto P = int(std::strtoul(Port.value().c_str(), nullptr, 10));
|
|
||||||
if (P == 0 || P < 0 || P > UINT16_MAX) {
|
|
||||||
beammp_errorf("Custom port requested via --port is invalid: '{}'", Port.value());
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
Application::Settings.Port = P;
|
|
||||||
beammp_info("Custom port requested via commandline arguments: " + Port.value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Config.PrintDebug();
|
|
||||||
|
|
||||||
Application::InitializeConsole();
|
Application::InitializeConsole();
|
||||||
Application::Console().StartLoggingToFile();
|
Application::Console().StartLoggingToFile();
|
||||||
|
|
||||||
|
|||||||
+1
-1
Submodule vcpkg updated: 326d8b43e3...8397227251
Reference in New Issue
Block a user