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 fef069c9df72a0473c6eed6b767199633327e4db.
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

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

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

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 &`*.*

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; }

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 };
};

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;
}
}

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;

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")

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);
})
};

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++;

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()) {