mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2026-02-16 10:41:01 +00:00
Compare commits
63 Commits
release-v2
...
v2.1.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1ca8e0576 | ||
|
|
b22f21a6b2 | ||
|
|
531a901431 | ||
|
|
46f778bd01 | ||
|
|
f3b6eea418 | ||
|
|
bceb3aefe4 | ||
|
|
6c72432992 | ||
|
|
17d3f303ca | ||
|
|
2cbcf96282 | ||
|
|
7d4fd44dbf | ||
|
|
71c2af1224 | ||
|
|
2e112fc5f1 | ||
|
|
96c93a6aa6 | ||
|
|
9dbb91fd84 | ||
|
|
26c33ae2fb | ||
|
|
3eb943309e | ||
|
|
3c8e8399cb | ||
|
|
5b500a3da5 | ||
|
|
ade19123b7 | ||
|
|
5ee18e0576 | ||
|
|
77d23caa63 | ||
|
|
79856cde8e | ||
|
|
7bc230974a | ||
|
|
b1ab7e65da | ||
|
|
c82c53e3d1 | ||
|
|
9e861ab993 | ||
|
|
ae11ba5f0d | ||
|
|
1427966d1a | ||
|
|
db92f2867d | ||
|
|
208a41d45f | ||
|
|
f2915f9c2a | ||
|
|
1abf6d5adf | ||
|
|
f626474b4f | ||
|
|
6f3960d2c2 | ||
|
|
6cb19a7991 | ||
|
|
4fe3c50edd | ||
|
|
fe7335fb0e | ||
|
|
40cd203047 | ||
|
|
1fc03500f0 | ||
|
|
73729746ff | ||
|
|
ffdf4dce60 | ||
|
|
bb5d7fdcf4 | ||
|
|
2df2475b59 | ||
|
|
bb32b9cfea | ||
|
|
3f034264f9 | ||
|
|
c67fffed58 | ||
|
|
f50b821733 | ||
|
|
1e5d19bca4 | ||
|
|
1011de1971 | ||
|
|
7336d63f58 | ||
|
|
c5d7369088 | ||
|
|
c3a463552f | ||
|
|
ae9462898e | ||
|
|
529b7e2ae4 | ||
|
|
1bee72a175 | ||
|
|
f1e1b6cc28 | ||
|
|
573bd77bbd | ||
|
|
770e03e3c6 | ||
|
|
11d4522dc7 | ||
|
|
830bc47987 | ||
|
|
bec698fbdc | ||
|
|
60cc835daf | ||
|
|
a85ce18589 |
2
.github/workflows/cmake-linux.yml
vendored
2
.github/workflows/cmake-linux.yml
vendored
@@ -1,6 +1,6 @@
|
||||
name: CMake Linux Build
|
||||
|
||||
on: [push, pull_request]
|
||||
on: [push]
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
4
.github/workflows/cmake-windows.yml
vendored
4
.github/workflows/cmake-windows.yml
vendored
@@ -1,6 +1,6 @@
|
||||
name: CMake Windows Build
|
||||
|
||||
on: [push, pull_request]
|
||||
on: [push]
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
@@ -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
|
||||
|
||||
2
.github/workflows/release-build.yml
vendored
2
.github/workflows/release-build.yml
vendored
@@ -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
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
.idea/
|
||||
*.toml
|
||||
boost_*
|
||||
Resources
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
@@ -468,3 +470,9 @@ cmake-build-debug/include/commandline/Makefile
|
||||
*.manifest
|
||||
*.rc
|
||||
*.res
|
||||
BeamMP-Server
|
||||
*.patch
|
||||
callgrind.*
|
||||
notes/*
|
||||
compile_commands.json
|
||||
nohup.out
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -10,3 +10,6 @@
|
||||
[submodule "rapidjson"]
|
||||
path = rapidjson
|
||||
url = https://github.com/Tencent/rapidjson
|
||||
[submodule "include/tomlplusplus"]
|
||||
path = include/tomlplusplus
|
||||
url = https://github.com/marzer/tomlplusplus
|
||||
|
||||
1
.idea/.name
generated
1
.idea/.name
generated
@@ -1 +0,0 @@
|
||||
Server
|
||||
4
.idea/misc.xml
generated
4
.idea/misc.xml
generated
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
</project>
|
||||
16
.idea/vcs.xml
generated
16
.idea/vcs.xml
generated
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/asio" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/include/commandline" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/rapidjson" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/rapidjson/thirdparty/gtest" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/socket.io-client-cpp" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/socket.io-client-cpp/lib/asio" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/socket.io-client-cpp/lib/catch" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/socket.io-client-cpp/lib/rapidjson" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/socket.io-client-cpp/lib/rapidjson/thirdparty/gtest" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/socket.io-client-cpp/lib/websocketpp" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -53,16 +53,16 @@ add_executable(BeamMP-Server
|
||||
target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/commandline")
|
||||
|
||||
find_package(Lua REQUIRED)
|
||||
target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} "socket.io-client-cpp/src")
|
||||
target_include_directories(BeamMP-Server PUBLIC ${Boost_INCLUDE_DIRS} ${LUA_INCLUDE_DIR} "socket.io-client-cpp/src" "include/tomlplusplus")
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(BeamMP-Server z pthread stdc++fs ${Boost_LINK_DIRS} ${LUA_LIBRARIES} dl crypto ${OPENSSL_LIBRARIES} ${Boost_LIBRARIES} commandline sioclient_tls)
|
||||
target_link_libraries(BeamMP-Server z pthread stdc++fs ${LUA_LIBRARIES} crypto ${OPENSSL_LIBRARIES} commandline sioclient_tls)
|
||||
elseif (WIN32)
|
||||
include(FindLua)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(RapidJSON CONFIG REQUIRED)
|
||||
target_include_directories(BeamMP-Server PRIVATE ${RAPIDJSON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
|
||||
target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${LUA_LIBRARIES} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} commandline sioclient_tls)
|
||||
target_link_libraries(BeamMP-Server PRIVATE ws2_32 ZLIB::ZLIB ${LUA_LIBRARIES} ${OPENSSL_LIBRARIES} commandline sioclient_tls)
|
||||
endif ()
|
||||
|
||||
1
LICENSE
1
LICENSE
@@ -1 +1,2 @@
|
||||
Copyright (c) 2019-present Anonymous275 (@Anonymous-275), Lion Kortlepel (@lionkor). BeamMP-Server code is not in the public domain and is not free software. One must be granted explicit permission by the copyright holder(s) in order to modify or distribute any part of the source or binaries. Special permission to modify the source-code is implicitly granted only for the purpose of upstreaming those changes directly to github.com/BeamMP/BeamMP-Server via a GitHub pull-request.
|
||||
Commercial usage is prohibited, unless explicit permission has been granted prior to usage.
|
||||
|
||||
46
README.md
46
README.md
@@ -6,9 +6,30 @@
|
||||
This is the server for the multiplayer mod **[BeamMP](https://beammp.com/)** for the game [BeamNG.drive](https://www.beamng.com/).
|
||||
The server is the point throug which all clients communicate. You can write lua mods for the server, detailed instructions on the [BeamMP Wiki](https://wiki.beammp.com).
|
||||
|
||||
## Minimum Requirements
|
||||
|
||||
These values are guesstimated and are subject to change with each release.
|
||||
|
||||
* RAM: 50+ MiB usable (not counting OS overhead)
|
||||
* CPU: Any Hz, preferably multicore
|
||||
* OS: Windows, Linux (theoretically any POSIX)
|
||||
* GPU: None
|
||||
* HDD: 10 MiB + Mods/Plugins
|
||||
* Bandwidth: 5-10 Mb/s upload
|
||||
|
||||
## Contributing
|
||||
|
||||
TLDR; [Issues](https://github.com/BeamMP/BeamMP-Server/issues) with the "help wanted" label or with nobody assigned, any [trello](https://trello.com/b/Kw75j3zZ/beamngdrive-multiplayer) cards in the "To-Do" column.
|
||||
|
||||
To contribute, look at the active [issues](https://github.com/BeamMP/BeamMP-Server/issues) and at the [trello](https://trello.com/b/Kw75j3zZ/beamngdrive-multiplayer). Any issues that have the "help wanted" label or don't have anyone assigned and any trello cards that aren't assigned or in the "In-Progress" section are good tasks to take on. You can either contribute by programming or by testing and adding more info and ideas.
|
||||
|
||||
Fork this repository, make a new branch for your feature, implement your feature or fix, and then create a pull-request here. Even incomplete features and fixes can be pull-requested.
|
||||
|
||||
If you need support with understanding the codebase, please write us in the discord. You'll need to be proficient in modern C++.
|
||||
|
||||
## About Building from Source
|
||||
|
||||
We only allow building unmodified (original) source code. `master` is considered **unstable** and we will not provide technical support if such a build doesn't work, so always build from a tag. You can checkout a tag with `git checkout tags/TAGNAME`, where `TAGNAME` is the tag, for example `v1.20`.
|
||||
We only allow building unmodified (original) source code for public use. `master` is considered **unstable** and we will not provide technical support if such a build doesn't work, so always build from a tag. You can checkout a tag with `git checkout tags/TAGNAME`, where `TAGNAME` is the tag, for example `v1.20`.
|
||||
|
||||
## Supported Operating Systems
|
||||
|
||||
@@ -42,28 +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`
|
||||
- `libboost1.70-dev`
|
||||
|
||||
If your distro doesn't have 1.7x version of libboost, you'll have to compile it from source or find another way to get it for your distro.
|
||||
- `libopenssl-dev`
|
||||
- `libopenssl-dev` or `libssl-dev`
|
||||
|
||||
**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 &`*.*
|
||||
|
||||
@@ -71,3 +90,4 @@ On windows. use git-bash for these commands.
|
||||
|
||||
Copyright (c) 2019-present Anonymous275 (@Anonymous-275), Lion Kortlepel (@lionkor).
|
||||
BeamMP-Server code is not in the public domain and is not free software. One must be granted explicit permission by the copyright holder(s) in order to modify or distribute any part of the source or binaries. Special permission to modify the source-code is implicitly granted only for the purpose of upstreaming those changes directly to github.com/BeamMP/BeamMP-Server via a GitHub pull-request.
|
||||
Commercial usage is prohibited, unless explicit permission has been granted prior to usage.
|
||||
|
||||
@@ -83,7 +83,7 @@ private:
|
||||
std::mutex mVehicleDataMutex;
|
||||
TSetOfVehicleData mVehicleData;
|
||||
std::string mName = "Unknown Client";
|
||||
SOCKET mSocket[2] { SOCKET(-1) };
|
||||
SOCKET mSocket[2] { SOCKET(0), SOCKET(0) };
|
||||
sockaddr_in mUDPAddress {}; // is this initialization OK? yes it is
|
||||
int mUnicycleID = -1;
|
||||
std::string mRole;
|
||||
|
||||
@@ -18,17 +18,25 @@ public:
|
||||
// types
|
||||
struct TSettings {
|
||||
TSettings() noexcept
|
||||
: DebugModeEnabled(true) { }
|
||||
: 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;
|
||||
std::string MapName;
|
||||
std::string Key;
|
||||
int MaxPlayers {};
|
||||
bool Private {};
|
||||
int MaxCars {};
|
||||
int MaxPlayers;
|
||||
bool Private;
|
||||
int MaxCars;
|
||||
bool DebugModeEnabled;
|
||||
int Port {};
|
||||
int Port;
|
||||
std::string CustomIP;
|
||||
[[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); }
|
||||
};
|
||||
@@ -42,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.2"; }
|
||||
static std::string ServerVersion() { return "2.1.4"; }
|
||||
static std::string ClientVersion() { return "2.0"; }
|
||||
static std::string PPS() { return mPPS; }
|
||||
static void SetPPS(std::string NewPPS) { mPPS = NewPPS; }
|
||||
|
||||
9
include/Json.h
Normal file
9
include/Json.h
Normal file
@@ -0,0 +1,9 @@
|
||||
//
|
||||
// Created by anon on 4/21/21.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/writer.h"
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <shared_mutex>
|
||||
#include <mutex>
|
||||
|
||||
// Use ReadLock(m) and WriteLock(m) to lock it.
|
||||
using RWMutex = std::shared_mutex;
|
||||
|
||||
@@ -2,11 +2,20 @@
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
class TConfig {
|
||||
public:
|
||||
explicit TConfig(const std::string& ConfigFile);
|
||||
explicit TConfig();
|
||||
|
||||
bool Failed() const { return mFailed; }
|
||||
|
||||
private:
|
||||
static std::string RemoveComments(const std::string& Line);
|
||||
static void SetValues(const std::string& Line, int Index);
|
||||
void CreateConfigFile(std::string_view name);
|
||||
void ParseFromFile(std::string_view name);
|
||||
void PrintDebug();
|
||||
|
||||
void ParseOldFormat();
|
||||
|
||||
bool mFailed { false };
|
||||
};
|
||||
|
||||
@@ -44,6 +44,6 @@ private:
|
||||
void OnDisconnect(const std::weak_ptr<TClient>& ClientPtr, bool kicked);
|
||||
void Parse(TClient& c, const std::string& Packet);
|
||||
void SendFile(TClient& c, const std::string& Name);
|
||||
static bool TCPSendRaw(SOCKET C, char* Data, int32_t Size);
|
||||
static bool TCPSendRaw(TClient& C, SOCKET socket, char* Data, int32_t Size);
|
||||
static void SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std::string& Name);
|
||||
};
|
||||
|
||||
Submodule include/commandline updated: 412ece748d...c34703df11
1
include/tomlplusplus
Submodule
1
include/tomlplusplus
Submodule
Submodule include/tomlplusplus added at bc6891e1fb
313
src/TConfig.cpp
313
src/TConfig.cpp
@@ -1,126 +1,213 @@
|
||||
#include "../include/TConfig.h"
|
||||
#include <toml.hpp> // header-only version of TOML++
|
||||
|
||||
#include "TConfig.h"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
|
||||
TConfig::TConfig(const std::string& ConfigFile) {
|
||||
std::ifstream File(ConfigFile);
|
||||
if (File.good()) {
|
||||
std::string line;
|
||||
int index = 1;
|
||||
while (getline(File, line)) {
|
||||
index++;
|
||||
static const char* ConfigFileName = static_cast<const char*>("ServerConfig.toml");
|
||||
|
||||
static constexpr std::string_view StrDebug = "Debug";
|
||||
static constexpr std::string_view StrPrivate = "Private";
|
||||
static constexpr std::string_view StrPort = "Port";
|
||||
static constexpr std::string_view StrMaxCars = "MaxCars";
|
||||
static constexpr std::string_view StrMaxPlayers = "MaxPlayers";
|
||||
static constexpr std::string_view StrMap = "Map";
|
||||
static constexpr std::string_view StrName = "Name";
|
||||
static constexpr std::string_view StrDescription = "Description";
|
||||
static constexpr std::string_view StrResourceFolder = "ResourceFolder";
|
||||
static constexpr std::string_view StrAuthKey = "AuthKey";
|
||||
|
||||
TConfig::TConfig() {
|
||||
if (!fs::exists(ConfigFileName) || !fs::is_regular_file(ConfigFileName)) {
|
||||
info("No config file found! Generating one...");
|
||||
CreateConfigFile(ConfigFileName);
|
||||
}
|
||||
if (!mFailed) {
|
||||
if (fs::exists("Server.cfg")) {
|
||||
warn("An old \"Server.cfg\" file still exists. Please note that this is no longer used. Instead, \"" + std::string(ConfigFileName) + "\" is used. You can safely delete the \"Server.cfg\".");
|
||||
}
|
||||
if (index - 1 < 11) {
|
||||
error(("Outdated/Incorrect config please remove it server will close in 5 secs"));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
_Exit(0);
|
||||
}
|
||||
File.close();
|
||||
File.open(("Server.cfg"));
|
||||
info(("Config found updating values"));
|
||||
index = 1;
|
||||
while (std::getline(File, line)) {
|
||||
if (line.rfind('#', 0) != 0 && line.rfind(' ', 0) != 0) { //Checks if it starts as Comment
|
||||
std::string CleanLine = RemoveComments(line); //Cleans it from the Comments
|
||||
SetValues(CleanLine, index); //sets the values
|
||||
index++;
|
||||
}
|
||||
ParseFromFile(ConfigFileName);
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
toml::table { {
|
||||
|
||||
{ StrDebug, Application::Settings.DebugModeEnabled },
|
||||
{ StrPrivate, Application::Settings.Private },
|
||||
{ StrPort, Application::Settings.Port },
|
||||
{ StrMaxCars, Application::Settings.MaxCars },
|
||||
{ StrMaxPlayers, Application::Settings.MaxPlayers },
|
||||
{ StrMap, Application::Settings.MapName },
|
||||
{ StrName, Application::Settings.ServerName },
|
||||
{ StrDescription, Application::Settings.ServerDesc },
|
||||
{ StrResourceFolder, Application::Settings.Resource },
|
||||
{ StrAuthKey, Application::Settings.Key },
|
||||
|
||||
} } },
|
||||
|
||||
} };
|
||||
std::ofstream ofs { std::string(name) };
|
||||
if (ofs.good()) {
|
||||
ofs << "# This is the BeamMP-Server config file.\n"
|
||||
"# Help & Documentation: `https://wiki.beammp.com/en/home/server-maintenance`\n"
|
||||
"# 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. 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 {
|
||||
info(("Config not found generating default"));
|
||||
std::ofstream FileStream;
|
||||
FileStream.open(ConfigFile);
|
||||
// TODO REPLACE THIS SHIT OMG
|
||||
FileStream << ("# This is the BeamMP Server Configuration File v0.60\n"
|
||||
"Debug = false # true or false to enable debug console output\n"
|
||||
"Private = true # Private?\n"
|
||||
"Port = 30814 # Port to run the server on UDP and TCP\n"
|
||||
"Cars = 1 # Max cars for every player\n"
|
||||
"MaxPlayers = 10 # Maximum Amount of Clients\n"
|
||||
"Map = \"/levels/gridmap/info.json\" # Default Map\n"
|
||||
"Name = \"BeamMP New Server\" # Server Name\n"
|
||||
"Desc = \"BeamMP Default Description\" # Server Description\n"
|
||||
"use = \"Resources\" # Resource file name\n"
|
||||
"AuthKey = \"\" # Auth Key");
|
||||
FileStream.close();
|
||||
error(("You are required to input the AuthKey"));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
_Exit(0);
|
||||
error("Couldn't create " + std::string(name) + ". Check permissions, try again, and contact support if it continues not to work.");
|
||||
mFailed = true;
|
||||
}
|
||||
debug("Debug : " + std::string(Application::Settings.DebugModeEnabled ? "true" : "false"));
|
||||
debug("Private : " + std::string(Application::Settings.Private ? "true" : "false"));
|
||||
debug("Port : " + std::to_string(Application::Settings.Port));
|
||||
debug("Max Cars : " + std::to_string(Application::Settings.MaxCars));
|
||||
debug("MaxPlayers : " + std::to_string(Application::Settings.MaxPlayers));
|
||||
debug("MapName : \"" + Application::Settings.MapName + "\"");
|
||||
debug("ServerName : \"" + Application::Settings.ServerName + "\"");
|
||||
debug("ServerDesc : \"" + Application::Settings.ServerDesc + "\"");
|
||||
debug("File : \"" + Application::Settings.Resource + "\"");
|
||||
debug("Key length : " + std::to_string(Application::Settings.Key.length()) + "");
|
||||
}
|
||||
|
||||
std::string TConfig::RemoveComments(const std::string& Line) {
|
||||
std::string Return;
|
||||
for (char c : Line) {
|
||||
if (c == '#')
|
||||
break;
|
||||
Return += c;
|
||||
}
|
||||
return Return;
|
||||
}
|
||||
|
||||
void TConfig::SetValues(const std::string& Line, int Index) {
|
||||
int state = 0;
|
||||
std::string Data;
|
||||
bool Switch = false;
|
||||
if (Index > 5)
|
||||
Switch = true;
|
||||
for (char c : Line) {
|
||||
if (Switch) {
|
||||
if (c == '\"')
|
||||
state++;
|
||||
if (state > 0 && state < 2)
|
||||
Data += c;
|
||||
void TConfig::ParseFromFile(std::string_view name) {
|
||||
try {
|
||||
toml::table FullTable = toml::parse_file(name);
|
||||
toml::table GeneralTable = *FullTable["General"].as_table();
|
||||
if (auto val = GeneralTable[StrDebug].value<bool>(); val.has_value()) {
|
||||
Application::Settings.DebugModeEnabled = val.value();
|
||||
} else {
|
||||
if (c == ' ')
|
||||
state++;
|
||||
if (state > 1)
|
||||
Data += c;
|
||||
throw std::runtime_error(std::string(StrDebug));
|
||||
}
|
||||
if (auto val = GeneralTable[StrPrivate].value<bool>(); val.has_value()) {
|
||||
Application::Settings.Private = val.value();
|
||||
} else {
|
||||
throw std::runtime_error(std::string(StrPrivate));
|
||||
}
|
||||
if (auto val = GeneralTable[StrPort].value<int>(); val.has_value()) {
|
||||
Application::Settings.Port = val.value();
|
||||
} else {
|
||||
throw std::runtime_error(std::string(StrPort));
|
||||
}
|
||||
if (auto val = GeneralTable[StrMaxCars].value<int>(); val.has_value()) {
|
||||
Application::Settings.MaxCars = val.value();
|
||||
} else {
|
||||
throw std::runtime_error(std::string(StrMaxCars));
|
||||
}
|
||||
if (auto val = GeneralTable[StrMaxPlayers].value<int>(); val.has_value()) {
|
||||
Application::Settings.MaxPlayers = val.value();
|
||||
} else {
|
||||
throw std::runtime_error(std::string(StrMaxPlayers));
|
||||
}
|
||||
if (auto val = GeneralTable[StrMap].value<std::string>(); val.has_value()) {
|
||||
Application::Settings.MapName = val.value();
|
||||
} else {
|
||||
throw std::runtime_error(std::string(StrMap));
|
||||
}
|
||||
if (auto val = GeneralTable[StrName].value<std::string>(); val.has_value()) {
|
||||
Application::Settings.ServerName = val.value();
|
||||
} else {
|
||||
throw std::runtime_error(std::string(StrName));
|
||||
}
|
||||
if (auto val = GeneralTable[StrDescription].value<std::string>(); val.has_value()) {
|
||||
Application::Settings.ServerDesc = val.value();
|
||||
} else {
|
||||
throw std::runtime_error(std::string(StrDescription));
|
||||
}
|
||||
if (auto val = GeneralTable[StrResourceFolder].value<std::string>(); val.has_value()) {
|
||||
Application::Settings.Resource = val.value();
|
||||
} else {
|
||||
throw std::runtime_error(std::string(StrResourceFolder));
|
||||
}
|
||||
if (auto val = GeneralTable[StrAuthKey].value<std::string>(); val.has_value()) {
|
||||
Application::Settings.Key = val.value();
|
||||
} else {
|
||||
throw std::runtime_error(std::string(StrAuthKey));
|
||||
}
|
||||
} catch (const std::exception& err) {
|
||||
error("Error parsing config file value: " + std::string(err.what()));
|
||||
mFailed = true;
|
||||
return;
|
||||
}
|
||||
PrintDebug();
|
||||
// all good so far, let's check if there's a key
|
||||
if (Application::Settings.Key.empty()) {
|
||||
error("No AuthKey specified in the \"" + std::string(ConfigFileName) + "\" file. Please get an AuthKey, enter it into the config file, and restart this server.");
|
||||
mFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void TConfig::PrintDebug() {
|
||||
debug(std::string(StrDebug) + ": " + std::string(Application::Settings.DebugModeEnabled ? "true" : "false"));
|
||||
debug(std::string(StrPrivate) + ": " + std::string(Application::Settings.Private ? "true" : "false"));
|
||||
debug(std::string(StrPort) + ": " + std::to_string(Application::Settings.Port));
|
||||
debug(std::string(StrMaxCars) + ": " + std::to_string(Application::Settings.MaxCars));
|
||||
debug(std::string(StrMaxPlayers) + ": " + std::to_string(Application::Settings.MaxPlayers));
|
||||
debug(std::string(StrMap) + ": \"" + Application::Settings.MapName + "\"");
|
||||
debug(std::string(StrName) + ": \"" + Application::Settings.ServerName + "\"");
|
||||
debug(std::string(StrDescription) + ": \"" + Application::Settings.ServerDesc + "\"");
|
||||
debug(std::string(StrResourceFolder) + ": \"" + Application::Settings.Resource + "\"");
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
Data = Data.substr(1);
|
||||
std::string::size_type sz;
|
||||
bool FoundTrue = std::string(Data).find("true") != std::string::npos; //searches for "true"
|
||||
switch (Index) {
|
||||
case 1:
|
||||
Application::Settings.DebugModeEnabled = FoundTrue; //checks and sets the Debug Value
|
||||
break;
|
||||
case 2:
|
||||
Application::Settings.Private = FoundTrue; //checks and sets the Private Value
|
||||
break;
|
||||
case 3:
|
||||
Application::Settings.Port = std::stoi(Data, &sz); //sets the Port
|
||||
break;
|
||||
case 4:
|
||||
Application::Settings.MaxCars = std::stoi(Data, &sz); //sets the Max Car amount
|
||||
break;
|
||||
case 5:
|
||||
Application::Settings.MaxPlayers = std::stoi(Data, &sz); //sets the Max Amount of player
|
||||
break;
|
||||
case 6:
|
||||
Application::Settings.MapName = Data; //Map
|
||||
break;
|
||||
case 7:
|
||||
Application::Settings.ServerName = Data; //Name
|
||||
break;
|
||||
case 8:
|
||||
Application::Settings.ServerDesc = Data; //desc
|
||||
break;
|
||||
case 9:
|
||||
Application::Settings.Resource = Data; //File name
|
||||
break;
|
||||
case 10:
|
||||
Application::Settings.Key = Data; //File name
|
||||
default:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -56,6 +56,7 @@ std::any Trigger(TLuaFile* lua, const std::string& R, std::shared_ptr<TLuaArg> a
|
||||
SendError(lua->Engine(), lua->GetState(), R + " took too long to respond");
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::any FutureWait(TLuaFile* lua, const std::string& R, std::shared_ptr<TLuaArg> arg, bool Wait) {
|
||||
Assert(lua);
|
||||
std::packaged_task<std::any(std::shared_ptr<TLuaArg>)> task([lua, R](std::shared_ptr<TLuaArg> arg) { return Trigger(lua, R, arg); });
|
||||
@@ -70,17 +71,16 @@ std::any FutureWait(TLuaFile* lua, const std::string& R, std::shared_ptr<TLuaArg
|
||||
return f1.get();
|
||||
return 0;
|
||||
}
|
||||
|
||||
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")
|
||||
@@ -88,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")
|
||||
@@ -99,6 +98,7 @@ std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaFile* Caller,
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
|
||||
bool ConsoleCheck(lua_State* L, int r) {
|
||||
if (r != LUA_OK) {
|
||||
std::string msg = lua_tostring(L, -1);
|
||||
@@ -107,6 +107,7 @@ bool ConsoleCheck(lua_State* L, int r) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckLua(lua_State* L, int r) {
|
||||
if (r != LUA_OK) {
|
||||
std::string msg = lua_tostring(L, -1);
|
||||
@@ -134,6 +135,7 @@ int lua_RegisterEvent(lua_State* L) {
|
||||
SendError(Engine(), L, "RegisterEvent invalid argument count expected 2 got " + std::to_string(Args));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_TriggerEventL(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
auto MaybeScript = Engine().GetScript(L);
|
||||
@@ -197,6 +199,7 @@ int lua_StopThread(lua_State* L) {
|
||||
MaybeScript.value().get().SetStopThread(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_CreateThread(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
if (Args > 1) {
|
||||
@@ -220,6 +223,7 @@ int lua_CreateThread(lua_State* L) {
|
||||
SendError(Engine(), L, ("CreateThread not enough arguments"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_Sleep(lua_State* L) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
int t = int(lua_tonumber(L, 1));
|
||||
@@ -230,6 +234,7 @@ int lua_Sleep(lua_State* L) {
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::optional<std::weak_ptr<TClient>> GetClient(TServer& Server, int ID) {
|
||||
std::optional<std::weak_ptr<TClient>> MaybeClient { std::nullopt };
|
||||
Server.ForEachClient([&](std::weak_ptr<TClient> CPtr) -> bool {
|
||||
@@ -245,7 +250,7 @@ std::optional<std::weak_ptr<TClient>> GetClient(TServer& Server, int ID) {
|
||||
});
|
||||
return MaybeClient;
|
||||
}
|
||||
// CONTINUE
|
||||
|
||||
int lua_isConnected(lua_State* L) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
int ID = int(lua_tonumber(L, 1));
|
||||
@@ -260,6 +265,7 @@ int lua_isConnected(lua_State* L) {
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_GetPlayerName(lua_State* L) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
int ID = int(lua_tonumber(L, 1));
|
||||
@@ -274,10 +280,12 @@ int lua_GetPlayerName(lua_State* L) {
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_GetPlayerCount(lua_State* L) {
|
||||
lua_pushinteger(L, Engine().Server().ClientCount());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_GetGuest(lua_State* L) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
int ID = int(lua_tonumber(L, 1));
|
||||
@@ -292,6 +300,7 @@ int lua_GetGuest(lua_State* L) {
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_GetAllPlayers(lua_State* L) {
|
||||
lua_newtable(L);
|
||||
Engine().Server().ForEachClient([&](const std::weak_ptr<TClient>& ClientPtr) -> bool {
|
||||
@@ -311,6 +320,7 @@ int lua_GetAllPlayers(lua_State* L) {
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_GetIdentifiers(lua_State* L) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
auto MaybeClient = GetClient(Engine().Server(), int(lua_tonumber(L, 1)));
|
||||
@@ -360,6 +370,7 @@ int lua_GetCars(lua_State* L) {
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_dropPlayer(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
if (lua_isnumber(L, 1)) {
|
||||
@@ -380,6 +391,7 @@ int lua_dropPlayer(lua_State* L) {
|
||||
SendError(Engine(), L, ("DropPlayer not enough arguments"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_sendChat(lua_State* L) {
|
||||
if (lua_isinteger(L, 1) || lua_isnumber(L, 1)) {
|
||||
if (lua_isstring(L, 2)) {
|
||||
@@ -404,6 +416,7 @@ int lua_sendChat(lua_State* L) {
|
||||
SendError(Engine(), L, ("SendChatMessage invalid argument [1] expected number"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_RemoveVehicle(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
if (Args != 2) {
|
||||
@@ -428,10 +441,12 @@ int lua_RemoveVehicle(lua_State* L) {
|
||||
SendError(Engine(), L, ("RemoveVehicle invalid argument expected number"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_HWID(lua_State* L) {
|
||||
lua_pushinteger(L, -1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int lua_RemoteEvent(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
if (Args != 3) {
|
||||
@@ -465,14 +480,12 @@ int lua_RemoteEvent(lua_State* L) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int lua_ServerExit(lua_State* L) {
|
||||
if (lua_gettop(L) > 0) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
_Exit(int(lua_tointeger(L, 1)));
|
||||
}
|
||||
}
|
||||
_Exit(0);
|
||||
|
||||
int lua_ServerExit(lua_State*) {
|
||||
Application::GracefullyShutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_Set(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
if (Args != 2) {
|
||||
@@ -548,6 +561,7 @@ int lua_Set(lua_State* L) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int lua_Print(lua_State* L) {
|
||||
int Arg = lua_gettop(L);
|
||||
@@ -619,11 +633,13 @@ void TLuaFile::Execute(const std::string& Command) {
|
||||
lua_settop(mLuaState, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void TLuaFile::Reload() {
|
||||
if (CheckLua(mLuaState, luaL_dofile(mLuaState, mFileName.c_str()))) {
|
||||
CallFunction(this, ("onInit"), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::string TLuaFile::GetOrigin() {
|
||||
return fs::path(GetFileName()).filename().string();
|
||||
}
|
||||
@@ -641,9 +657,13 @@ std::any CallFunction(TLuaFile* lua, const std::string& FuncName, std::shared_pt
|
||||
int R = lua_pcall(luaState, Size, 1, 0);
|
||||
if (CheckLua(luaState, R)) {
|
||||
if (lua_isnumber(luaState, -1)) {
|
||||
return int(lua_tointeger(luaState, -1));
|
||||
auto ret = int(lua_tointeger(luaState, -1));
|
||||
ClearStack(luaState);
|
||||
return ret;
|
||||
} else if (lua_isstring(luaState, -1)) {
|
||||
return std::string(lua_tostring(luaState, -1));
|
||||
auto ret = std::string(lua_tostring(luaState, -1));
|
||||
ClearStack(luaState);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -691,6 +711,7 @@ void TLuaFile::Load() {
|
||||
void TLuaFile::RegisterEvent(const std::string& Event, const std::string& FunctionName) {
|
||||
mRegisteredEvents.insert(std::make_pair(Event, FunctionName));
|
||||
}
|
||||
|
||||
void TLuaFile::UnRegisterEvent(const std::string& Event) {
|
||||
for (const std::pair<std::string, std::string>& a : mRegisteredEvents) {
|
||||
if (a.first == Event) {
|
||||
@@ -699,6 +720,7 @@ void TLuaFile::UnRegisterEvent(const std::string& Event) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TLuaFile::IsRegistered(const std::string& Event) {
|
||||
for (const std::pair<std::string, std::string>& a : mRegisteredEvents) {
|
||||
if (a.first == Event)
|
||||
@@ -706,6 +728,7 @@ bool TLuaFile::IsRegistered(const std::string& Event) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string TLuaFile::GetRegistered(const std::string& Event) const {
|
||||
for (const std::pair<std::string, std::string>& a : mRegisteredEvents) {
|
||||
if (a.first == Event)
|
||||
@@ -713,12 +736,15 @@ std::string TLuaFile::GetRegistered(const std::string& Event) const {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string TLuaFile::GetFileName() const {
|
||||
return mFileName;
|
||||
}
|
||||
|
||||
std::string TLuaFile::GetPluginName() const {
|
||||
return mPluginName;
|
||||
}
|
||||
|
||||
lua_State* TLuaFile::GetState() {
|
||||
return mLuaState;
|
||||
}
|
||||
@@ -751,6 +777,7 @@ void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) {
|
||||
}
|
||||
warn(a + (" | Incorrect Call of ") + msg);
|
||||
}
|
||||
|
||||
int lua_TempFix(lua_State* L) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
int ID = int(lua_tonumber(L, 1));
|
||||
@@ -771,20 +798,26 @@ int lua_TempFix(lua_State* L) {
|
||||
|
||||
void TLuaArg::PushArgs(lua_State* State) {
|
||||
for (std::any arg : args) {
|
||||
if (!arg.has_value())
|
||||
if (!arg.has_value()) {
|
||||
error("arg didn't have a value, this is not expected, bad");
|
||||
return;
|
||||
std::string Type = arg.type().name();
|
||||
if (Type.find("bool") != std::string::npos) {
|
||||
}
|
||||
const auto& Type = arg.type();
|
||||
if (Type == typeid(bool)) {
|
||||
lua_pushboolean(State, std::any_cast<bool>(arg));
|
||||
}
|
||||
if (Type.find("basic_string") != std::string::npos || Type.find("char") != std::string::npos) {
|
||||
} else if (Type == typeid(std::string)) {
|
||||
lua_pushstring(State, std::any_cast<std::string>(arg).c_str());
|
||||
}
|
||||
if (Type.find("int") != std::string::npos) {
|
||||
} else if (Type == typeid(const char*)) {
|
||||
lua_pushstring(State, std::any_cast<const char*>(arg));
|
||||
} else if (Type == typeid(int)) {
|
||||
lua_pushinteger(State, std::any_cast<int>(arg));
|
||||
}
|
||||
if (Type.find("float") != std::string::npos) {
|
||||
} else if (Type == typeid(float)) {
|
||||
lua_pushnumber(State, std::any_cast<float>(arg));
|
||||
} else if (Type == typeid(double)) {
|
||||
lua_pushnumber(State, std::any_cast<double>(arg));
|
||||
} else {
|
||||
// if this happens, implement a sane behavior for that value
|
||||
error("what in the hell is " + std::string(arg.type().name()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -204,9 +213,7 @@ void TNetwork::TCPServerMain() {
|
||||
|
||||
#undef GetObject //Fixes Windows
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "Json.h"
|
||||
namespace json = rapidjson;
|
||||
|
||||
void TNetwork::Identify(SOCKET TCPSock) {
|
||||
@@ -329,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;
|
||||
}
|
||||
@@ -390,8 +396,8 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) {
|
||||
return false;
|
||||
}
|
||||
Sent += Temp;
|
||||
c.UpdatePingTime();
|
||||
} while (Sent < Size);
|
||||
c.UpdatePingTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -486,7 +492,12 @@ void TNetwork::ClientKick(TClient& c, const std::string& R) {
|
||||
// TODO handle
|
||||
}
|
||||
c.SetStatus(-2);
|
||||
CloseSocketProper(c.GetTCPSock());
|
||||
|
||||
if (c.GetTCPSock())
|
||||
CloseSocketProper(c.GetTCPSock());
|
||||
|
||||
if (c.GetDownSock())
|
||||
CloseSocketProper(c.GetDownSock());
|
||||
}
|
||||
void TNetwork::Looper(const std::weak_ptr<TClient>& c) {
|
||||
while (!c.expired()) {
|
||||
@@ -757,7 +768,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
|
||||
if (Diff > Split) {
|
||||
f.seekg(Sent, std::ios_base::beg);
|
||||
f.read(Data, Split);
|
||||
if (!TCPSendRaw(TCPSock, Data, Split)) {
|
||||
if (!TCPSendRaw(c, TCPSock, Data, Split)) {
|
||||
if (c.GetStatus() > -1)
|
||||
c.SetStatus(-1);
|
||||
break;
|
||||
@@ -766,7 +777,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
|
||||
} else {
|
||||
f.seekg(Sent, std::ios_base::beg);
|
||||
f.read(Data, Diff);
|
||||
if (!TCPSendRaw(TCPSock, Data, int32_t(Diff))) {
|
||||
if (!TCPSendRaw(c, TCPSock, Data, int32_t(Diff))) {
|
||||
if (c.GetStatus() > -1)
|
||||
c.SetStatus(-1);
|
||||
break;
|
||||
@@ -778,16 +789,17 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
|
||||
f.close();
|
||||
}
|
||||
|
||||
bool TNetwork::TCPSendRaw(SOCKET C, char* Data, int32_t Size) {
|
||||
bool TNetwork::TCPSendRaw(TClient& C, SOCKET socket, char* Data, int32_t Size) {
|
||||
intmax_t Sent = 0;
|
||||
do {
|
||||
intmax_t Temp = send(C, &Data[Sent], int(Size - Sent), 0);
|
||||
intmax_t Temp = send(socket, &Data[Sent], int(Size - Sent), 0);
|
||||
if (Temp < 1) {
|
||||
info("Socket Closed! " + std::to_string(C));
|
||||
CloseSocketProper(C);
|
||||
info("Socket Closed! " + std::to_string(socket));
|
||||
CloseSocketProper(socket);
|
||||
return false;
|
||||
}
|
||||
Sent += Temp;
|
||||
C.UpdatePingTime();
|
||||
} while (Sent < Size);
|
||||
return true;
|
||||
}
|
||||
@@ -854,7 +866,6 @@ bool TNetwork::SyncClient(const std::weak_ptr<TClient>& c) {
|
||||
return false;
|
||||
}
|
||||
res = Respond(*LockedClient, v.Data(), true, true);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,17 +36,15 @@ void TPPSMonitor::operator()() {
|
||||
ReadLock Lock(mServer.GetClientMutex());
|
||||
if (!ClientPtr.expired()) {
|
||||
c = ClientPtr.lock();
|
||||
} else return true;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
if (c->GetCarCount() > 0) {
|
||||
C++;
|
||||
V += c->GetCarCount();
|
||||
}
|
||||
if (!c->IsSynced() || c->IsSyncing()) {
|
||||
c->UpdatePingTime();
|
||||
}
|
||||
// kick on "no ping"
|
||||
if (c->SecondsSinceLastPing() > 30 && c->IsSynced() && !c->IsSyncing()) {
|
||||
if (c->SecondsSinceLastPing() > (5 * 60)) {
|
||||
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);
|
||||
}
|
||||
@@ -54,7 +52,7 @@ void TPPSMonitor::operator()() {
|
||||
return true;
|
||||
});
|
||||
for (auto& ClientToKick : TimedOutClients) {
|
||||
Network().ClientKick(*ClientToKick, "Timeout (no ping for >30 seconds)");
|
||||
Network().ClientKick(*ClientToKick, "Timeout (no ping for >5 min)");
|
||||
}
|
||||
TimedOutClients.clear();
|
||||
if (C == 0 || mInternalPPS == 0) {
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
|
||||
#undef GetObject //Fixes Windows
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "Json.h"
|
||||
|
||||
namespace json = rapidjson;
|
||||
|
||||
@@ -138,6 +136,9 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::string Pac
|
||||
#endif
|
||||
HandleEvent(*LockedClient, Packet);
|
||||
return;
|
||||
case 'N':
|
||||
debug("got 'N' packet (" + std::to_string(Packet.size()) + ")");
|
||||
Network.SendToAll(LockedClient.get(), Packet, false, true);
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@@ -163,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;
|
||||
@@ -175,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;
|
||||
}
|
||||
@@ -238,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);
|
||||
@@ -265,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);
|
||||
@@ -311,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()) {
|
||||
|
||||
@@ -50,7 +50,14 @@ int main(int argc, char** argv) {
|
||||
Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; });
|
||||
|
||||
TServer Server(argc, argv);
|
||||
[[maybe_unused]] TConfig Config("Server.cfg");
|
||||
TConfig Config;
|
||||
|
||||
if (Config.Failed()) {
|
||||
info("Closing in 10 seconds");
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
return 1;
|
||||
}
|
||||
|
||||
RegisterThread("Main");
|
||||
TResourceManager ResourceManager;
|
||||
TPPSMonitor PPSMonitor(Server);
|
||||
|
||||
Reference in New Issue
Block a user