Compare commits

..

27 Commits

Author SHA1 Message Date
Lion Kortlepel 3d0d5e9e4c minor fixes, version bump 2021-07-31 21:57:06 +03:00
Lion Kortlepel a1ca8e0576 bump vcpkg version 2021-07-31 12:34:25 +03:00
Lion Kortlepel b22f21a6b2 Revert "remove vcpkg commit id"
This reverts commit fef069c9df.
2021-07-31 12:34:25 +03:00
Lion Kortlepel 531a901431 remove vcpkg commit id
there's no need for it and it makes runs fail if not updated
2021-07-31 12:34:25 +03:00
Lion Kortlepel 46f778bd01 bump version to 2.1.4 2021-07-29 13:34:28 +02:00
Lion Kortlepel f3b6eea418 update vcpkg 2021-07-29 13:34:28 +02:00
Lion Kortlepel bceb3aefe4 TServer: Avoid blindly using std::string::find's result 2021-07-29 13:34:28 +02:00
Lion Kortlepel 6c72432992 possible fix #37 2021-07-29 13:34:28 +02:00
Lion 17d3f303ca Update README.md 2021-07-21 00:18:36 +02:00
Lion 2cbcf96282 Readme: clarify build instructions are for linux, too 2021-07-18 21:28:58 +02:00
Lion Kortlepel 7d4fd44dbf print heartbeat on heartbeat 2021-07-15 01:04:06 +02:00
Lion Kortlepel 71c2af1224 TNetwork: kick everyone before shutdown
in the future this can be used to show a message to the clients that the
server is shutting down
2021-07-11 20:27:35 +02:00
Lion Kortlepel 2e112fc5f1 fix typo that prevented TCP thread from shutting down properly
sometimes, i guess
2021-07-11 20:00:31 +02:00
Lion 96c93a6aa6 Update README.md
Remove unnecessary and wrong step 4 :)
2021-07-11 00:30:14 +02:00
Lion 9dbb91fd84 Update README.md 2021-07-11 00:29:27 +02:00
Lion 26c33ae2fb README: Add clarification on build steps 2021-07-11 00:28:21 +02:00
Lion Kortlepel 3eb943309e bump version number 2021-07-10 19:20:42 +02:00
Lion Kortlepel 3c8e8399cb Fix issue with not cancelling events on linux (fix #29) 2021-07-04 00:10:10 +02:00
Lion Kortlepel 5b500a3da5 bump version number 2021-07-03 01:04:55 +02:00
Lion Kortlepel ade19123b7 change default map to new gridmap 2021-07-03 01:01:56 +02:00
Lion Kortlepel 5ee18e0576 bump in-server version number 2021-07-02 00:01:58 +02:00
Lion 77d23caa63 Update README.md 2021-06-28 11:39:12 +02:00
Lion 79856cde8e Update README.md 2021-06-28 11:38:59 +02:00
Lion Kortlepel 7bc230974a fix typo 2021-06-23 23:50:18 +02:00
Anonymous-275 b1ab7e65da Possible windows compile fix 2021-06-23 20:03:42 +03:00
Lion Kortlepel c82c53e3d1 remove debug prints 2021-06-23 16:40:08 +02:00
Lion Kortlepel 9e861ab993 parse old Server.cfg if it exists 2021-06-23 16:39:08 +02:00
11 changed files with 153 additions and 56 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
with:
vcpkgArguments: 'lua zlib rapidjson boost-beast boost-asio openssl websocketpp'
vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg'
vcpkgGitCommitId: '75522bb1f2e7d863078bcd06322348f053a9e33f'
vcpkgGitCommitId: '8dddc6c899ce6fdbeab38b525a31e7f23cb2d5bb'
vcpkgTriplet: 'x64-windows-static'
- name: Create Build Environment
+1 -1
View File
@@ -86,7 +86,7 @@ jobs:
with:
vcpkgArguments: 'lua zlib rapidjson boost-beast boost-asio openssl websocketpp'
vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg'
vcpkgGitCommitId: '75522bb1f2e7d863078bcd06322348f053a9e33f'
vcpkgGitCommitId: '8dddc6c899ce6fdbeab38b525a31e7f23cb2d5bb'
vcpkgTriplet: 'x64-windows-static'
- name: Create Build Environment
+9 -10
View File
@@ -63,27 +63,26 @@ These package names are in the debian / ubuntu style. Feel free to PR your own g
- `g++`
Must support ISO C++17. If your distro's `g++` doesn't support C++17, chances are that it has a `g++-8` or `g++-10` package that does. If this is the case. you just need to run CMake with `-DCMAKE_CXX_COMPILER=g++-10` (replace `g++-10` with your compiler's name).
- `liblua5.3`
- `liblua5.3-dev`
Any 5.x version should work, but 5.3 is what we officially use. Any other version might break in the future.
You can also use any version of `libluajit`, but the same applies regarding the version.
- `libz-dev`
- `rapidjson-dev`
- `libopenssl-dev`
- `libopenssl-dev` or `libssl-dev`
**If** you're building it from source, you'll need `libboost1.70-dev` as well.
**If** you're building it from source, you'll need `libboost1.70-all-dev` or `libboost1.71-all-dev` or higher as well.
### How to build
On windows. use git-bash for these commands.
On windows. use git-bash for these commands. On linux, these should work in your shell.
1. Make sure you have all [prerequisites](#prerequisites) installed
2. Clone the repository in a location of your choice with `git clone --recursive https://github.com/BeamMP/BeamMP-Server`
3. Checkout the branch of the release you want to compile (`master` is often unstable), for example `git checkout tags/v1.20` for version 1.20.
4. `cd` into it with `cd BeamMP-Server`
5. Run `cmake .` (with `.`)
6. Run `make`
7. You will now have a `BeamMP-Server` file in your directory, which is executable with `./BeamMP-Server` (`.\BeamMP-Server.exe` for windows). Follow the (windows or linux, doesnt matter) instructions on the [wiki](https://wiki.beammp.com/en/home/Server_Mod) for further setup after installation (which we just did), such as port-forwarding and getting a key to actually run the server.
2. Clone the repository in a location of your choice with `git clone --recursive https://github.com/BeamMP/BeamMP-Server`. Now change into the cloned directory by running `cd BeamMP-Server`.
3. Checkout the branch of the release you want to compile (`master` is often unstable), for example `git checkout tags/v1.20` for version 1.20. You can find the latest version [here](https://github.com/BeamMP/BeamMP-Server/tags).
4. Run `cmake .` (with `.`)
5. Run `make`
6. You will now have a `BeamMP-Server` file in your directory, which is executable with `./BeamMP-Server` (`.\BeamMP-Server.exe` for windows). Follow the (windows or linux, doesnt matter) instructions on the [wiki](https://wiki.beammp.com/en/home/Server_Mod) for further setup after installation (which we just did), such as port-forwarding and getting a key to actually run the server.
*tip: to run the server in the background, simply (in bash, zsh, etc) run:* `nohup ./BeamMP-Server &`*.*
+11 -11
View File
@@ -17,16 +17,16 @@ class Application final {
public:
// types
struct TSettings {
TSettings() noexcept :
ServerName("BeamMP Server"),
ServerDesc("BeamMP Default Description"),
Resource("Resources"),
MapName("/levels/gridmap/info.json"),
MaxPlayers(10),
Private(false),
MaxCars(1),
DebugModeEnabled(false),
Port(30814){}
TSettings() noexcept
: ServerName("BeamMP Server")
, ServerDesc("BeamMP Default Description")
, Resource("Resources")
, MapName("/levels/gridmap_v2/info.json")
, MaxPlayers(10)
, Private(false)
, MaxCars(1)
, DebugModeEnabled(false)
, Port(30814) { }
std::string ServerName;
std::string ServerDesc;
std::string Resource;
@@ -50,7 +50,7 @@ public:
// Causes all threads to finish up and exit gracefull gracefully
static void GracefullyShutdown();
static TConsole& Console() { return *mConsole; }
static std::string ServerVersion() { return "2.0.4"; }
static std::string ServerVersion() { return "2.2.0"; }
static std::string ClientVersion() { return "2.0"; }
static std::string PPS() { return mPPS; }
static void SetPPS(std::string NewPPS) { mPPS = NewPPS; }
+3 -1
View File
@@ -8,12 +8,14 @@ class TConfig {
public:
explicit TConfig();
bool Failed() const { return mFailed; }
[[nodiscard]] bool Failed() const { return mFailed; }
private:
void CreateConfigFile(std::string_view name);
void ParseFromFile(std::string_view name);
void PrintDebug();
void ParseOldFormat();
bool mFailed { false };
};
+67 -1
View File
@@ -3,6 +3,8 @@
#include "TConfig.h"
#include <fstream>
#include <iostream>
#include <istream>
#include <sstream>
static const char* ConfigFileName = static_cast<const char*>("ServerConfig.toml");
@@ -31,6 +33,17 @@ TConfig::TConfig() {
}
void TConfig::CreateConfigFile(std::string_view name) {
// build from old config Server.cfg
try {
if (fs::exists("Server.cfg")) {
// parse it (this is weird and bad and should be removed in some future version)
ParseOldFormat();
}
} catch (const std::exception& e) {
error("an error occurred and was ignored during config transfer: " + std::string(e.what()));
}
toml::table tbl { {
{ "General",
@@ -57,7 +70,7 @@ void TConfig::CreateConfigFile(std::string_view name) {
"# IMPORTANT: Fill in the AuthKey with the key you got from `https://beammp.com/k/dashboard` on the left under \"Keys\"\n"
<< '\n';
ofs << tbl << '\n';
error("There was no \"" + std::string(ConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. Please open it and fill in your AuthKey and other settings, then restart the server. The old Server.cfg file will no longer be used and cause a warning if it exists from now on.");
error("There was no \"" + std::string(ConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. It was automatically filled with the settings from your Server.cfg, if you have one. Please open ServerConfig.toml and ensure your AuthKey and other settings are filled in and correct, then restart the server. The old Server.cfg file will no longer be used and causes a warning if it exists from now on.");
mFailed = true;
} else {
error("Couldn't create " + std::string(name) + ". Check permissions, try again, and contact support if it continues not to work.");
@@ -145,3 +158,56 @@ void TConfig::PrintDebug() {
// special!
debug("Key Length: " + std::to_string(Application::Settings.Key.length()) + "");
}
void TConfig::ParseOldFormat() {
std::ifstream File("Server.cfg");
// read all, strip comments
std::string Content;
for (;;) {
std::string Line;
std::getline(File, Line);
if (!Line.empty() && Line.at(0) != '#') {
Line = Line.substr(0, Line.find_first_of('#'));
Content += Line + "\n";
}
if (!File.good()) {
break;
}
}
std::stringstream Str(Content);
std::string Key, Ignore, Value;
for (;;) {
Str >> Key >> std::ws >> Ignore >> std::ws;
std::getline(Str, Value);
if (Str.eof()) {
break;
}
std::stringstream ValueStream(Value);
ValueStream >> std::ws; // strip leading whitespace if any
Value = ValueStream.str();
if (Key == "Debug") {
Application::Settings.DebugModeEnabled = Value.find("true") != std::string::npos;
} else if (Key == "Private") {
Application::Settings.Private = Value.find("true") != std::string::npos;
} else if (Key == "Port") {
ValueStream >> Application::Settings.Port;
} else if (Key == "Cars") {
ValueStream >> Application::Settings.MaxCars;
} else if (Key == "MaxPlayers") {
ValueStream >> Application::Settings.MaxPlayers;
} else if (Key == "Map") {
Application::Settings.MapName = Value.substr(1, Value.size() - 3);
} else if (Key == "Name") {
Application::Settings.ServerName = Value.substr(1, Value.size() - 3);
} else if (Key == "Desc") {
Application::Settings.ServerDesc = Value.substr(1, Value.size() - 3);
} else if (Key == "use") {
Application::Settings.Resource = Value.substr(1, Value.size() - 3);
} else if (Key == "AuthKey") {
Application::Settings.Key = Value.substr(1, Value.size() - 3);
} else {
warn("unknown key in old auth file (ignored): " + Key);
}
Str >> std::ws;
}
}
+1 -3
View File
@@ -26,9 +26,7 @@ void THeartbeatThread::operator()() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
}
#ifdef DEBUG
debug("heartbeat @ " + std::to_string(std::chrono::duration_cast<std::chrono::seconds>(TimePassed).count()));
#endif // DEBUG
debug("heartbeat (after " + std::to_string(std::chrono::duration_cast<std::chrono::seconds>(TimePassed).count()) + "s)");
Last = Body;
LastNormalUpdateTime = Now;
+2 -5
View File
@@ -74,15 +74,13 @@ std::any FutureWait(TLuaFile* lua, const std::string& R, std::shared_ptr<TLuaArg
std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaFile* Caller, std::shared_ptr<TLuaArg> arg, bool Wait) {
std::any R;
std::string Type;
int Ret = 0;
for (auto& Script : Engine().LuaFiles()) {
if (Script->IsRegistered(Event)) {
if (local) {
if (Script->GetPluginName() == Caller->GetPluginName()) {
R = FutureWait(Script.get(), Script->GetRegistered(Event), arg, Wait);
Type = R.type().name();
if (Type.find("int") != std::string::npos) {
if (R.type() == typeid(int)) {
if (std::any_cast<int>(R))
Ret++;
} else if (Event == "onPlayerAuth")
@@ -90,8 +88,7 @@ std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaFile* Caller,
}
} else {
R = FutureWait(Script.get(), Script->GetRegistered(Event), arg, Wait);
Type = R.type().name();
if (Type.find("int") != std::string::npos) {
if (R.type() == typeid(int)) {
if (std::any_cast<int>(R))
Ret++;
} else if (Event == "onPlayerAuth")
+31 -13
View File
@@ -9,6 +9,15 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R
: mServer(Server)
, mPPSMonitor(PPSMonitor)
, mResourceManager(ResourceManager) {
Application::RegisterShutdownHandler([&] {
debug("Kicking all players due to shutdown");
Server.ForEachClient([&](std::weak_ptr<TClient> client) -> bool {
if (!client.expired()) {
ClientKick(*client.lock(), "Server shutdown");
}
return true;
});
});
Application::RegisterShutdownHandler([&] {
if (mUDPThread.joinable()) {
debug("shutting down TCPServer");
@@ -18,7 +27,7 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R
}
});
Application::RegisterShutdownHandler([&] {
if (mUDPThread.joinable()) {
if (mTCPThread.joinable()) {
debug("shutting down TCPServer");
mShutdown = true;
mTCPThread.detach();
@@ -327,11 +336,10 @@ void TNetwork::Authentication(SOCKET TCPSock) {
auto arg = std::make_unique<TLuaArg>(TLuaArg { { Client->GetName(), Client->GetRoles(), Client->IsGuest() } });
std::any Res = TriggerLuaEvent("onPlayerAuth", false, nullptr, std::move(arg), true);
std::string Type = Res.type().name();
if (Type.find("int") != std::string::npos && std::any_cast<int>(Res)) {
if (Res.type() == typeid(int) && std::any_cast<int>(Res)) {
ClientKick(*Client, "you are not allowed on the server!");
return;
} else if (Type.find("string") != std::string::npos) {
} else if (Res.type() == typeid(std::string)) {
ClientKick(*Client, std::any_cast<std::string>(Res));
return;
}
@@ -694,19 +702,29 @@ void TNetwork::Parse(TClient& c, const std::string& Packet) {
}
}
void TNetwork::SendFile(TClient& c, const std::string& Name) {
info(c.GetName() + " requesting : " + Name.substr(Name.find_last_of('/')));
void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) {
info(c.GetName() + " requesting : " + UnsafeName.substr(UnsafeName.find_last_of('/')));
if (!std::filesystem::exists(Name)) {
if (!fs::path(UnsafeName).has_filename()) {
if (!TCPSend(c, "CO")) {
// TODO: handle
}
warn("File " + Name + " could not be accessed!");
warn("File " + UnsafeName + " is not a file!");
return;
} else {
if (!TCPSend(c, "AG")) {
}
auto FileName = fs::path(UnsafeName).filename().string();
FileName = Application::Settings.Resource + "/Client/" + FileName;
if (!std::filesystem::exists(FileName)) {
if (!TCPSend(c, "CO")) {
// TODO: handle
}
warn("File " + UnsafeName + " could not be accessed!");
return;
}
if (!TCPSend(c, "AG")) {
// TODO: handle
}
///Wait for connections
@@ -723,14 +741,14 @@ void TNetwork::SendFile(TClient& c, const std::string& Name) {
return;
}
size_t Size = size_t(std::filesystem::file_size(Name)), MSize = Size / 2;
size_t Size = size_t(std::filesystem::file_size(FileName)), MSize = Size / 2;
std::thread SplitThreads[2] {
std::thread([&] {
SplitLoad(c, 0, MSize, false, Name);
SplitLoad(c, 0, MSize, false, FileName);
}),
std::thread([&] {
SplitLoad(c, MSize, Size, true, Name);
SplitLoad(c, MSize, Size, true, FileName);
})
};
+1 -1
View File
@@ -19,7 +19,7 @@ TResourceManager::TResourceManager() {
++i;
File = File.substr(i,pos-i);
}
mTrimmedList += File + ';';
mTrimmedList += "/" + fs::path(File).filename().string() + ';';
mFileSizes += std::to_string(size_t(fs::file_size(entry.path()))) + ';';
mMaxModSize += size_t(fs::file_size(entry.path()));
mModsLoaded++;
+26 -9
View File
@@ -164,10 +164,10 @@ void TServer::HandleEvent(TClient& c, const std::string& Data) {
a++;
}
}
bool TServer::IsUnicycle(TClient &c, const std::string &CarJson) {
bool TServer::IsUnicycle(TClient& c, const std::string& CarJson) {
rapidjson::Document Car;
Car.Parse(CarJson.c_str(), CarJson.size());
if(Car.HasParseError()){
if (Car.HasParseError()) {
error("Failed to parse vehicle data -> " + CarJson);
} else if (Car["jbm"].IsString() && std::string(Car["jbm"].GetString()) == "unicycle") {
return true;
@@ -176,11 +176,11 @@ bool TServer::IsUnicycle(TClient &c, const std::string &CarJson) {
}
bool TServer::ShouldSpawn(TClient& c, const std::string& CarJson, int ID) {
if(c.GetUnicycleID() > -1 && (c.GetCarCount() - 1) < Application::Settings.MaxCars){
if (c.GetUnicycleID() > -1 && (c.GetCarCount() - 1) < Application::Settings.MaxCars) {
return true;
}
if(IsUnicycle(c,CarJson)){
if (IsUnicycle(c, CarJson)) {
c.SetUnicycleID(ID);
return true;
}
@@ -239,12 +239,14 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ
std::make_unique<TLuaArg>(TLuaArg { { c.GetID(), VID, Packet.substr(3) } }),
true);
if ((c.GetUnicycleID() != VID || IsUnicycle(c,Packet.substr(Packet.find('{'))))
auto FoundPos = Packet.find('{');
FoundPos = FoundPos == std::string::npos ? 0 : FoundPos; // attempt at sanitizing this
if ((c.GetUnicycleID() != VID || IsUnicycle(c, Packet.substr(FoundPos)))
&& std::any_cast<int>(Res) == 0) {
Network.SendToAll(&c, Packet, false, true);
Apply(c, VID, Packet);
} else {
if(c.GetUnicycleID() == VID){
if (c.GetUnicycleID() == VID) {
c.SetUnicycleID(-1);
}
std::string Destroy = "Od:" + std::to_string(c.GetID()) + "-" + std::to_string(VID);
@@ -266,7 +268,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ
VID = stoi(vid);
}
if (PID != -1 && VID != -1 && PID == c.GetID()) {
if(c.GetUnicycleID() == VID){
if (c.GetUnicycleID() == VID) {
c.SetUnicycleID(-1);
}
Network.SendToAll(nullptr, Packet, true, true);
@@ -312,10 +314,25 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Networ
}
void TServer::Apply(TClient& c, int VID, const std::string& pckt) {
std::string Packet = pckt.substr(pckt.find('{')), VD = c.GetCarData(VID);
auto FoundPos = pckt.find('{');
if (FoundPos == std::string::npos) {
error("Malformed packet received, no '{' found");
return;
}
std::string Packet = pckt.substr(FoundPos);
std::string VD = c.GetCarData(VID);
if (VD.empty()) {
error("Tried to apply change to vehicle that does not exist");
return;
}
std::string Header = VD.substr(0, VD.find('{'));
VD = VD.substr(VD.find('{'));
FoundPos = VD.find('{');
if (FoundPos == std::string::npos) {
error("Malformed packet received, no '{' found");
return;
}
VD = VD.substr(FoundPos);
rapidjson::Document Veh, Pack;
Veh.Parse(VD.c_str());
if (Veh.HasParseError()) {