mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2026-07-15 11:13:45 +00:00
Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
@@ -1,6 +1,6 @@
|
|||||||
name: CMake Linux Build
|
name: CMake Linux Build
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BUILD_TYPE: Release
|
BUILD_TYPE: Release
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: CMake Windows Build
|
name: CMake Windows Build
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BUILD_TYPE: Release
|
BUILD_TYPE: Release
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
.idea/
|
||||||
|
*.toml
|
||||||
boost_*
|
boost_*
|
||||||
Resources
|
Resources
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
@@ -468,3 +470,9 @@ cmake-build-debug/include/commandline/Makefile
|
|||||||
*.manifest
|
*.manifest
|
||||||
*.rc
|
*.rc
|
||||||
*.res
|
*.res
|
||||||
|
BeamMP-Server
|
||||||
|
*.patch
|
||||||
|
callgrind.*
|
||||||
|
notes/*
|
||||||
|
compile_commands.json
|
||||||
|
nohup.out
|
||||||
|
|||||||
@@ -10,3 +10,6 @@
|
|||||||
[submodule "rapidjson"]
|
[submodule "rapidjson"]
|
||||||
path = rapidjson
|
path = rapidjson
|
||||||
url = https://github.com/Tencent/rapidjson
|
url = https://github.com/Tencent/rapidjson
|
||||||
|
[submodule "include/tomlplusplus"]
|
||||||
|
path = include/tomlplusplus
|
||||||
|
url = https://github.com/marzer/tomlplusplus
|
||||||
|
|||||||
Generated
-1
@@ -1 +0,0 @@
|
|||||||
Server
|
|
||||||
Generated
-4
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
|
||||||
</project>
|
|
||||||
Generated
-16
@@ -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>
|
|
||||||
+3
-3
@@ -53,16 +53,16 @@ add_executable(BeamMP-Server
|
|||||||
target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/commandline")
|
target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/commandline")
|
||||||
|
|
||||||
find_package(Lua REQUIRED)
|
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)
|
find_package(OpenSSL REQUIRED)
|
||||||
|
|
||||||
if (UNIX)
|
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)
|
elseif (WIN32)
|
||||||
include(FindLua)
|
include(FindLua)
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
find_package(RapidJSON CONFIG REQUIRED)
|
find_package(RapidJSON CONFIG REQUIRED)
|
||||||
target_include_directories(BeamMP-Server PRIVATE ${RAPIDJSON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
|
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 ()
|
endif ()
|
||||||
|
|||||||
@@ -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.
|
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.
|
||||||
|
|||||||
@@ -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/).
|
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).
|
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
|
## 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
|
## Supported Operating Systems
|
||||||
|
|
||||||
@@ -48,11 +69,10 @@ These package names are in the debian / ubuntu style. Feel free to PR your own g
|
|||||||
You can also use any version of `libluajit`, but the same applies regarding the version.
|
You can also use any version of `libluajit`, but the same applies regarding the version.
|
||||||
- `libz-dev`
|
- `libz-dev`
|
||||||
- `rapidjson-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`
|
||||||
|
|
||||||
|
**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
|
### How to build
|
||||||
|
|
||||||
On windows. use git-bash for these commands.
|
On windows. use git-bash for these commands.
|
||||||
@@ -71,3 +91,4 @@ On windows. use git-bash for these commands.
|
|||||||
|
|
||||||
Copyright (c) 2019-present Anonymous275 (@Anonymous-275), Lion Kortlepel (@lionkor).
|
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.
|
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.
|
||||||
|
|||||||
+1
-1
@@ -83,7 +83,7 @@ private:
|
|||||||
std::mutex mVehicleDataMutex;
|
std::mutex mVehicleDataMutex;
|
||||||
TSetOfVehicleData mVehicleData;
|
TSetOfVehicleData mVehicleData;
|
||||||
std::string mName = "Unknown Client";
|
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
|
sockaddr_in mUDPAddress {}; // is this initialization OK? yes it is
|
||||||
int mUnicycleID = -1;
|
int mUnicycleID = -1;
|
||||||
std::string mRole;
|
std::string mRole;
|
||||||
|
|||||||
+14
-6
@@ -18,17 +18,25 @@ public:
|
|||||||
// types
|
// types
|
||||||
struct TSettings {
|
struct TSettings {
|
||||||
TSettings() noexcept
|
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 ServerName;
|
||||||
std::string ServerDesc;
|
std::string ServerDesc;
|
||||||
std::string Resource;
|
std::string Resource;
|
||||||
std::string MapName;
|
std::string MapName;
|
||||||
std::string Key;
|
std::string Key;
|
||||||
int MaxPlayers {};
|
int MaxPlayers;
|
||||||
bool Private {};
|
bool Private;
|
||||||
int MaxCars {};
|
int MaxCars;
|
||||||
bool DebugModeEnabled;
|
bool DebugModeEnabled;
|
||||||
int Port {};
|
int Port;
|
||||||
std::string CustomIP;
|
std::string CustomIP;
|
||||||
[[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); }
|
[[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); }
|
||||||
};
|
};
|
||||||
@@ -42,7 +50,7 @@ public:
|
|||||||
// Causes all threads to finish up and exit gracefull gracefully
|
// Causes all threads to finish up and exit gracefull gracefully
|
||||||
static void GracefullyShutdown();
|
static void GracefullyShutdown();
|
||||||
static TConsole& Console() { return *mConsole; }
|
static TConsole& Console() { return *mConsole; }
|
||||||
static std::string ServerVersion() { return "2.0.2"; }
|
static std::string ServerVersion() { return "2.1.2"; }
|
||||||
static std::string ClientVersion() { return "2.0"; }
|
static std::string ClientVersion() { return "2.0"; }
|
||||||
static std::string PPS() { return mPPS; }
|
static std::string PPS() { return mPPS; }
|
||||||
static void SetPPS(std::string NewPPS) { mPPS = NewPPS; }
|
static void SetPPS(std::string NewPPS) { mPPS = NewPPS; }
|
||||||
|
|||||||
@@ -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 <shared_mutex>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
// Use ReadLock(m) and WriteLock(m) to lock it.
|
// Use ReadLock(m) and WriteLock(m) to lock it.
|
||||||
using RWMutex = std::shared_mutex;
|
using RWMutex = std::shared_mutex;
|
||||||
|
|||||||
+12
-3
@@ -2,11 +2,20 @@
|
|||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
class TConfig {
|
class TConfig {
|
||||||
public:
|
public:
|
||||||
explicit TConfig(const std::string& ConfigFile);
|
explicit TConfig();
|
||||||
|
|
||||||
|
bool Failed() const { return mFailed; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::string RemoveComments(const std::string& Line);
|
void CreateConfigFile(std::string_view name);
|
||||||
static void SetValues(const std::string& Line, int Index);
|
void ParseFromFile(std::string_view name);
|
||||||
|
void PrintDebug();
|
||||||
|
|
||||||
|
void ParseOldFormat();
|
||||||
|
|
||||||
|
bool mFailed { false };
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -44,6 +44,6 @@ private:
|
|||||||
void OnDisconnect(const std::weak_ptr<TClient>& ClientPtr, bool kicked);
|
void OnDisconnect(const std::weak_ptr<TClient>& ClientPtr, bool kicked);
|
||||||
void Parse(TClient& c, const std::string& Packet);
|
void Parse(TClient& c, const std::string& Packet);
|
||||||
void SendFile(TClient& c, const std::string& Name);
|
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);
|
static void SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std::string& Name);
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
Submodule include/commandline updated: 412ece748d...c34703df11
Submodule
+1
Submodule include/tomlplusplus added at bc6891e1fb
+200
-113
@@ -1,126 +1,213 @@
|
|||||||
#include "../include/TConfig.h"
|
#include <toml.hpp> // header-only version of TOML++
|
||||||
|
|
||||||
|
#include "TConfig.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <istream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
TConfig::TConfig(const std::string& ConfigFile) {
|
static const char* ConfigFileName = static_cast<const char*>("ServerConfig.toml");
|
||||||
std::ifstream File(ConfigFile);
|
|
||||||
if (File.good()) {
|
static constexpr std::string_view StrDebug = "Debug";
|
||||||
std::string line;
|
static constexpr std::string_view StrPrivate = "Private";
|
||||||
int index = 1;
|
static constexpr std::string_view StrPort = "Port";
|
||||||
while (getline(File, line)) {
|
static constexpr std::string_view StrMaxCars = "MaxCars";
|
||||||
index++;
|
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) {
|
ParseFromFile(ConfigFileName);
|
||||||
error(("Outdated/Incorrect config please remove it server will close in 5 secs"));
|
}
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
}
|
||||||
_Exit(0);
|
|
||||||
}
|
void TConfig::CreateConfigFile(std::string_view name) {
|
||||||
File.close();
|
// build from old config Server.cfg
|
||||||
File.open(("Server.cfg"));
|
|
||||||
info(("Config found updating values"));
|
try {
|
||||||
index = 1;
|
if (fs::exists("Server.cfg")) {
|
||||||
while (std::getline(File, line)) {
|
// parse it (this is weird and bad and should be removed in some future version)
|
||||||
if (line.rfind('#', 0) != 0 && line.rfind(' ', 0) != 0) { //Checks if it starts as Comment
|
ParseOldFormat();
|
||||||
std::string CleanLine = RemoveComments(line); //Cleans it from the Comments
|
|
||||||
SetValues(CleanLine, index); //sets the values
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} 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 {
|
} else {
|
||||||
info(("Config not found generating default"));
|
error("Couldn't create " + std::string(name) + ". Check permissions, try again, and contact support if it continues not to work.");
|
||||||
std::ofstream FileStream;
|
mFailed = true;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
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) {
|
void TConfig::ParseFromFile(std::string_view name) {
|
||||||
std::string Return;
|
try {
|
||||||
for (char c : Line) {
|
toml::table FullTable = toml::parse_file(name);
|
||||||
if (c == '#')
|
toml::table GeneralTable = *FullTable["General"].as_table();
|
||||||
break;
|
if (auto val = GeneralTable[StrDebug].value<bool>(); val.has_value()) {
|
||||||
Return += c;
|
Application::Settings.DebugModeEnabled = val.value();
|
||||||
}
|
|
||||||
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;
|
|
||||||
} else {
|
} else {
|
||||||
if (c == ' ')
|
throw std::runtime_error(std::string(StrDebug));
|
||||||
state++;
|
}
|
||||||
if (state > 1)
|
if (auto val = GeneralTable[StrPrivate].value<bool>(); val.has_value()) {
|
||||||
Data += c;
|
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::stringstream Str(Content);
|
||||||
std::string::size_type sz;
|
std::string Key, Ignore, Value;
|
||||||
bool FoundTrue = std::string(Data).find("true") != std::string::npos; //searches for "true"
|
for (;;) {
|
||||||
switch (Index) {
|
Str >> Key >> std::ws >> Ignore >> std::ws;
|
||||||
case 1:
|
std::getline(Str, Value);
|
||||||
Application::Settings.DebugModeEnabled = FoundTrue; //checks and sets the Debug Value
|
if (Str.eof()) {
|
||||||
break;
|
break;
|
||||||
case 2:
|
}
|
||||||
Application::Settings.Private = FoundTrue; //checks and sets the Private Value
|
std::stringstream ValueStream(Value);
|
||||||
break;
|
ValueStream >> std::ws; // strip leading whitespace if any
|
||||||
case 3:
|
Value = ValueStream.str();
|
||||||
Application::Settings.Port = std::stoi(Data, &sz); //sets the Port
|
if (Key == "Debug") {
|
||||||
break;
|
Application::Settings.DebugModeEnabled = Value.find("true") != std::string::npos;
|
||||||
case 4:
|
} else if (Key == "Private") {
|
||||||
Application::Settings.MaxCars = std::stoi(Data, &sz); //sets the Max Car amount
|
Application::Settings.Private = Value.find("true") != std::string::npos;
|
||||||
break;
|
} else if (Key == "Port") {
|
||||||
case 5:
|
ValueStream >> Application::Settings.Port;
|
||||||
Application::Settings.MaxPlayers = std::stoi(Data, &sz); //sets the Max Amount of player
|
} else if (Key == "Cars") {
|
||||||
break;
|
ValueStream >> Application::Settings.MaxCars;
|
||||||
case 6:
|
} else if (Key == "MaxPlayers") {
|
||||||
Application::Settings.MapName = Data; //Map
|
ValueStream >> Application::Settings.MaxPlayers;
|
||||||
break;
|
} else if (Key == "Map") {
|
||||||
case 7:
|
Application::Settings.MapName = Value.substr(1, Value.size() - 3);
|
||||||
Application::Settings.ServerName = Data; //Name
|
} else if (Key == "Name") {
|
||||||
break;
|
Application::Settings.ServerName = Value.substr(1, Value.size() - 3);
|
||||||
case 8:
|
} else if (Key == "Desc") {
|
||||||
Application::Settings.ServerDesc = Data; //desc
|
Application::Settings.ServerDesc = Value.substr(1, Value.size() - 3);
|
||||||
break;
|
} else if (Key == "use") {
|
||||||
case 9:
|
Application::Settings.Resource = Value.substr(1, Value.size() - 3);
|
||||||
Application::Settings.Resource = Data; //File name
|
} else if (Key == "AuthKey") {
|
||||||
break;
|
Application::Settings.Key = Value.substr(1, Value.size() - 3);
|
||||||
case 10:
|
} else {
|
||||||
Application::Settings.Key = Data; //File name
|
warn("unknown key in old auth file (ignored): " + Key);
|
||||||
default:
|
}
|
||||||
break;
|
Str >> std::ws;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+55
-19
@@ -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");
|
SendError(lua->Engine(), lua->GetState(), R + " took too long to respond");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::any FutureWait(TLuaFile* lua, const std::string& R, std::shared_ptr<TLuaArg> arg, bool Wait) {
|
std::any FutureWait(TLuaFile* lua, const std::string& R, std::shared_ptr<TLuaArg> arg, bool Wait) {
|
||||||
Assert(lua);
|
Assert(lua);
|
||||||
std::packaged_task<std::any(std::shared_ptr<TLuaArg>)> task([lua, R](std::shared_ptr<TLuaArg> arg) { return Trigger(lua, R, arg); });
|
std::packaged_task<std::any(std::shared_ptr<TLuaArg>)> task([lua, R](std::shared_ptr<TLuaArg> arg) { return Trigger(lua, R, arg); });
|
||||||
@@ -70,6 +71,7 @@ std::any FutureWait(TLuaFile* lua, const std::string& R, std::shared_ptr<TLuaArg
|
|||||||
return f1.get();
|
return f1.get();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaFile* Caller, std::shared_ptr<TLuaArg> arg, bool Wait) {
|
std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaFile* Caller, std::shared_ptr<TLuaArg> arg, bool Wait) {
|
||||||
std::any R;
|
std::any R;
|
||||||
std::string Type;
|
std::string Type;
|
||||||
@@ -99,6 +101,7 @@ std::any TriggerLuaEvent(const std::string& Event, bool local, TLuaFile* Caller,
|
|||||||
}
|
}
|
||||||
return Ret;
|
return Ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConsoleCheck(lua_State* L, int r) {
|
bool ConsoleCheck(lua_State* L, int r) {
|
||||||
if (r != LUA_OK) {
|
if (r != LUA_OK) {
|
||||||
std::string msg = lua_tostring(L, -1);
|
std::string msg = lua_tostring(L, -1);
|
||||||
@@ -107,6 +110,7 @@ bool ConsoleCheck(lua_State* L, int r) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckLua(lua_State* L, int r) {
|
bool CheckLua(lua_State* L, int r) {
|
||||||
if (r != LUA_OK) {
|
if (r != LUA_OK) {
|
||||||
std::string msg = lua_tostring(L, -1);
|
std::string msg = lua_tostring(L, -1);
|
||||||
@@ -134,6 +138,7 @@ int lua_RegisterEvent(lua_State* L) {
|
|||||||
SendError(Engine(), L, "RegisterEvent invalid argument count expected 2 got " + std::to_string(Args));
|
SendError(Engine(), L, "RegisterEvent invalid argument count expected 2 got " + std::to_string(Args));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_TriggerEventL(lua_State* L) {
|
int lua_TriggerEventL(lua_State* L) {
|
||||||
int Args = lua_gettop(L);
|
int Args = lua_gettop(L);
|
||||||
auto MaybeScript = Engine().GetScript(L);
|
auto MaybeScript = Engine().GetScript(L);
|
||||||
@@ -197,6 +202,7 @@ int lua_StopThread(lua_State* L) {
|
|||||||
MaybeScript.value().get().SetStopThread(true);
|
MaybeScript.value().get().SetStopThread(true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_CreateThread(lua_State* L) {
|
int lua_CreateThread(lua_State* L) {
|
||||||
int Args = lua_gettop(L);
|
int Args = lua_gettop(L);
|
||||||
if (Args > 1) {
|
if (Args > 1) {
|
||||||
@@ -220,6 +226,7 @@ int lua_CreateThread(lua_State* L) {
|
|||||||
SendError(Engine(), L, ("CreateThread not enough arguments"));
|
SendError(Engine(), L, ("CreateThread not enough arguments"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_Sleep(lua_State* L) {
|
int lua_Sleep(lua_State* L) {
|
||||||
if (lua_isnumber(L, 1)) {
|
if (lua_isnumber(L, 1)) {
|
||||||
int t = int(lua_tonumber(L, 1));
|
int t = int(lua_tonumber(L, 1));
|
||||||
@@ -230,6 +237,7 @@ int lua_Sleep(lua_State* L) {
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::weak_ptr<TClient>> GetClient(TServer& Server, int ID) {
|
std::optional<std::weak_ptr<TClient>> GetClient(TServer& Server, int ID) {
|
||||||
std::optional<std::weak_ptr<TClient>> MaybeClient { std::nullopt };
|
std::optional<std::weak_ptr<TClient>> MaybeClient { std::nullopt };
|
||||||
Server.ForEachClient([&](std::weak_ptr<TClient> CPtr) -> bool {
|
Server.ForEachClient([&](std::weak_ptr<TClient> CPtr) -> bool {
|
||||||
@@ -245,7 +253,7 @@ std::optional<std::weak_ptr<TClient>> GetClient(TServer& Server, int ID) {
|
|||||||
});
|
});
|
||||||
return MaybeClient;
|
return MaybeClient;
|
||||||
}
|
}
|
||||||
// CONTINUE
|
|
||||||
int lua_isConnected(lua_State* L) {
|
int lua_isConnected(lua_State* L) {
|
||||||
if (lua_isnumber(L, 1)) {
|
if (lua_isnumber(L, 1)) {
|
||||||
int ID = int(lua_tonumber(L, 1));
|
int ID = int(lua_tonumber(L, 1));
|
||||||
@@ -260,6 +268,7 @@ int lua_isConnected(lua_State* L) {
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_GetPlayerName(lua_State* L) {
|
int lua_GetPlayerName(lua_State* L) {
|
||||||
if (lua_isnumber(L, 1)) {
|
if (lua_isnumber(L, 1)) {
|
||||||
int ID = int(lua_tonumber(L, 1));
|
int ID = int(lua_tonumber(L, 1));
|
||||||
@@ -274,10 +283,12 @@ int lua_GetPlayerName(lua_State* L) {
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_GetPlayerCount(lua_State* L) {
|
int lua_GetPlayerCount(lua_State* L) {
|
||||||
lua_pushinteger(L, Engine().Server().ClientCount());
|
lua_pushinteger(L, Engine().Server().ClientCount());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_GetGuest(lua_State* L) {
|
int lua_GetGuest(lua_State* L) {
|
||||||
if (lua_isnumber(L, 1)) {
|
if (lua_isnumber(L, 1)) {
|
||||||
int ID = int(lua_tonumber(L, 1));
|
int ID = int(lua_tonumber(L, 1));
|
||||||
@@ -292,6 +303,7 @@ int lua_GetGuest(lua_State* L) {
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_GetAllPlayers(lua_State* L) {
|
int lua_GetAllPlayers(lua_State* L) {
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
Engine().Server().ForEachClient([&](const std::weak_ptr<TClient>& ClientPtr) -> bool {
|
Engine().Server().ForEachClient([&](const std::weak_ptr<TClient>& ClientPtr) -> bool {
|
||||||
@@ -311,6 +323,7 @@ int lua_GetAllPlayers(lua_State* L) {
|
|||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_GetIdentifiers(lua_State* L) {
|
int lua_GetIdentifiers(lua_State* L) {
|
||||||
if (lua_isnumber(L, 1)) {
|
if (lua_isnumber(L, 1)) {
|
||||||
auto MaybeClient = GetClient(Engine().Server(), int(lua_tonumber(L, 1)));
|
auto MaybeClient = GetClient(Engine().Server(), int(lua_tonumber(L, 1)));
|
||||||
@@ -360,6 +373,7 @@ int lua_GetCars(lua_State* L) {
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_dropPlayer(lua_State* L) {
|
int lua_dropPlayer(lua_State* L) {
|
||||||
int Args = lua_gettop(L);
|
int Args = lua_gettop(L);
|
||||||
if (lua_isnumber(L, 1)) {
|
if (lua_isnumber(L, 1)) {
|
||||||
@@ -380,6 +394,7 @@ int lua_dropPlayer(lua_State* L) {
|
|||||||
SendError(Engine(), L, ("DropPlayer not enough arguments"));
|
SendError(Engine(), L, ("DropPlayer not enough arguments"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_sendChat(lua_State* L) {
|
int lua_sendChat(lua_State* L) {
|
||||||
if (lua_isinteger(L, 1) || lua_isnumber(L, 1)) {
|
if (lua_isinteger(L, 1) || lua_isnumber(L, 1)) {
|
||||||
if (lua_isstring(L, 2)) {
|
if (lua_isstring(L, 2)) {
|
||||||
@@ -404,6 +419,7 @@ int lua_sendChat(lua_State* L) {
|
|||||||
SendError(Engine(), L, ("SendChatMessage invalid argument [1] expected number"));
|
SendError(Engine(), L, ("SendChatMessage invalid argument [1] expected number"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_RemoveVehicle(lua_State* L) {
|
int lua_RemoveVehicle(lua_State* L) {
|
||||||
int Args = lua_gettop(L);
|
int Args = lua_gettop(L);
|
||||||
if (Args != 2) {
|
if (Args != 2) {
|
||||||
@@ -428,10 +444,12 @@ int lua_RemoveVehicle(lua_State* L) {
|
|||||||
SendError(Engine(), L, ("RemoveVehicle invalid argument expected number"));
|
SendError(Engine(), L, ("RemoveVehicle invalid argument expected number"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_HWID(lua_State* L) {
|
int lua_HWID(lua_State* L) {
|
||||||
lua_pushinteger(L, -1);
|
lua_pushinteger(L, -1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_RemoteEvent(lua_State* L) {
|
int lua_RemoteEvent(lua_State* L) {
|
||||||
int Args = lua_gettop(L);
|
int Args = lua_gettop(L);
|
||||||
if (Args != 3) {
|
if (Args != 3) {
|
||||||
@@ -465,14 +483,12 @@ int lua_RemoteEvent(lua_State* L) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int lua_ServerExit(lua_State* L) {
|
|
||||||
if (lua_gettop(L) > 0) {
|
int lua_ServerExit(lua_State*) {
|
||||||
if (lua_isnumber(L, 1)) {
|
Application::GracefullyShutdown();
|
||||||
_Exit(int(lua_tointeger(L, 1)));
|
return 0;
|
||||||
}
|
|
||||||
}
|
|
||||||
_Exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_Set(lua_State* L) {
|
int lua_Set(lua_State* L) {
|
||||||
int Args = lua_gettop(L);
|
int Args = lua_gettop(L);
|
||||||
if (Args != 2) {
|
if (Args != 2) {
|
||||||
@@ -548,6 +564,7 @@ int lua_Set(lua_State* L) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
int lua_Print(lua_State* L) {
|
int lua_Print(lua_State* L) {
|
||||||
int Arg = lua_gettop(L);
|
int Arg = lua_gettop(L);
|
||||||
@@ -619,11 +636,13 @@ void TLuaFile::Execute(const std::string& Command) {
|
|||||||
lua_settop(mLuaState, 0);
|
lua_settop(mLuaState, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TLuaFile::Reload() {
|
void TLuaFile::Reload() {
|
||||||
if (CheckLua(mLuaState, luaL_dofile(mLuaState, mFileName.c_str()))) {
|
if (CheckLua(mLuaState, luaL_dofile(mLuaState, mFileName.c_str()))) {
|
||||||
CallFunction(this, ("onInit"), nullptr);
|
CallFunction(this, ("onInit"), nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TLuaFile::GetOrigin() {
|
std::string TLuaFile::GetOrigin() {
|
||||||
return fs::path(GetFileName()).filename().string();
|
return fs::path(GetFileName()).filename().string();
|
||||||
}
|
}
|
||||||
@@ -641,9 +660,13 @@ std::any CallFunction(TLuaFile* lua, const std::string& FuncName, std::shared_pt
|
|||||||
int R = lua_pcall(luaState, Size, 1, 0);
|
int R = lua_pcall(luaState, Size, 1, 0);
|
||||||
if (CheckLua(luaState, R)) {
|
if (CheckLua(luaState, R)) {
|
||||||
if (lua_isnumber(luaState, -1)) {
|
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)) {
|
} 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 +714,7 @@ void TLuaFile::Load() {
|
|||||||
void TLuaFile::RegisterEvent(const std::string& Event, const std::string& FunctionName) {
|
void TLuaFile::RegisterEvent(const std::string& Event, const std::string& FunctionName) {
|
||||||
mRegisteredEvents.insert(std::make_pair(Event, FunctionName));
|
mRegisteredEvents.insert(std::make_pair(Event, FunctionName));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TLuaFile::UnRegisterEvent(const std::string& Event) {
|
void TLuaFile::UnRegisterEvent(const std::string& Event) {
|
||||||
for (const std::pair<std::string, std::string>& a : mRegisteredEvents) {
|
for (const std::pair<std::string, std::string>& a : mRegisteredEvents) {
|
||||||
if (a.first == Event) {
|
if (a.first == Event) {
|
||||||
@@ -699,6 +723,7 @@ void TLuaFile::UnRegisterEvent(const std::string& Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TLuaFile::IsRegistered(const std::string& Event) {
|
bool TLuaFile::IsRegistered(const std::string& Event) {
|
||||||
for (const std::pair<std::string, std::string>& a : mRegisteredEvents) {
|
for (const std::pair<std::string, std::string>& a : mRegisteredEvents) {
|
||||||
if (a.first == Event)
|
if (a.first == Event)
|
||||||
@@ -706,6 +731,7 @@ bool TLuaFile::IsRegistered(const std::string& Event) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TLuaFile::GetRegistered(const std::string& Event) const {
|
std::string TLuaFile::GetRegistered(const std::string& Event) const {
|
||||||
for (const std::pair<std::string, std::string>& a : mRegisteredEvents) {
|
for (const std::pair<std::string, std::string>& a : mRegisteredEvents) {
|
||||||
if (a.first == Event)
|
if (a.first == Event)
|
||||||
@@ -713,12 +739,15 @@ std::string TLuaFile::GetRegistered(const std::string& Event) const {
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TLuaFile::GetFileName() const {
|
std::string TLuaFile::GetFileName() const {
|
||||||
return mFileName;
|
return mFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TLuaFile::GetPluginName() const {
|
std::string TLuaFile::GetPluginName() const {
|
||||||
return mPluginName;
|
return mPluginName;
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_State* TLuaFile::GetState() {
|
lua_State* TLuaFile::GetState() {
|
||||||
return mLuaState;
|
return mLuaState;
|
||||||
}
|
}
|
||||||
@@ -751,6 +780,7 @@ void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) {
|
|||||||
}
|
}
|
||||||
warn(a + (" | Incorrect Call of ") + msg);
|
warn(a + (" | Incorrect Call of ") + msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lua_TempFix(lua_State* L) {
|
int lua_TempFix(lua_State* L) {
|
||||||
if (lua_isnumber(L, 1)) {
|
if (lua_isnumber(L, 1)) {
|
||||||
int ID = int(lua_tonumber(L, 1));
|
int ID = int(lua_tonumber(L, 1));
|
||||||
@@ -771,20 +801,26 @@ int lua_TempFix(lua_State* L) {
|
|||||||
|
|
||||||
void TLuaArg::PushArgs(lua_State* State) {
|
void TLuaArg::PushArgs(lua_State* State) {
|
||||||
for (std::any arg : args) {
|
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;
|
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));
|
lua_pushboolean(State, std::any_cast<bool>(arg));
|
||||||
}
|
} else if (Type == typeid(std::string)) {
|
||||||
if (Type.find("basic_string") != std::string::npos || Type.find("char") != std::string::npos) {
|
|
||||||
lua_pushstring(State, std::any_cast<std::string>(arg).c_str());
|
lua_pushstring(State, std::any_cast<std::string>(arg).c_str());
|
||||||
}
|
} else if (Type == typeid(const char*)) {
|
||||||
if (Type.find("int") != std::string::npos) {
|
lua_pushstring(State, std::any_cast<const char*>(arg));
|
||||||
|
} else if (Type == typeid(int)) {
|
||||||
lua_pushinteger(State, std::any_cast<int>(arg));
|
lua_pushinteger(State, std::any_cast<int>(arg));
|
||||||
}
|
} else if (Type == typeid(float)) {
|
||||||
if (Type.find("float") != std::string::npos) {
|
|
||||||
lua_pushnumber(State, std::any_cast<float>(arg));
|
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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-12
@@ -204,9 +204,7 @@ void TNetwork::TCPServerMain() {
|
|||||||
|
|
||||||
#undef GetObject //Fixes Windows
|
#undef GetObject //Fixes Windows
|
||||||
|
|
||||||
#include "rapidjson/document.h"
|
#include "Json.h"
|
||||||
#include "rapidjson/stringbuffer.h"
|
|
||||||
#include "rapidjson/writer.h"
|
|
||||||
namespace json = rapidjson;
|
namespace json = rapidjson;
|
||||||
|
|
||||||
void TNetwork::Identify(SOCKET TCPSock) {
|
void TNetwork::Identify(SOCKET TCPSock) {
|
||||||
@@ -390,8 +388,8 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Sent += Temp;
|
Sent += Temp;
|
||||||
|
c.UpdatePingTime();
|
||||||
} while (Sent < Size);
|
} while (Sent < Size);
|
||||||
c.UpdatePingTime();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,7 +484,12 @@ void TNetwork::ClientKick(TClient& c, const std::string& R) {
|
|||||||
// TODO handle
|
// TODO handle
|
||||||
}
|
}
|
||||||
c.SetStatus(-2);
|
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) {
|
void TNetwork::Looper(const std::weak_ptr<TClient>& c) {
|
||||||
while (!c.expired()) {
|
while (!c.expired()) {
|
||||||
@@ -757,7 +760,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
|
|||||||
if (Diff > Split) {
|
if (Diff > Split) {
|
||||||
f.seekg(Sent, std::ios_base::beg);
|
f.seekg(Sent, std::ios_base::beg);
|
||||||
f.read(Data, Split);
|
f.read(Data, Split);
|
||||||
if (!TCPSendRaw(TCPSock, Data, Split)) {
|
if (!TCPSendRaw(c, TCPSock, Data, Split)) {
|
||||||
if (c.GetStatus() > -1)
|
if (c.GetStatus() > -1)
|
||||||
c.SetStatus(-1);
|
c.SetStatus(-1);
|
||||||
break;
|
break;
|
||||||
@@ -766,7 +769,7 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
|
|||||||
} else {
|
} else {
|
||||||
f.seekg(Sent, std::ios_base::beg);
|
f.seekg(Sent, std::ios_base::beg);
|
||||||
f.read(Data, Diff);
|
f.read(Data, Diff);
|
||||||
if (!TCPSendRaw(TCPSock, Data, int32_t(Diff))) {
|
if (!TCPSendRaw(c, TCPSock, Data, int32_t(Diff))) {
|
||||||
if (c.GetStatus() > -1)
|
if (c.GetStatus() > -1)
|
||||||
c.SetStatus(-1);
|
c.SetStatus(-1);
|
||||||
break;
|
break;
|
||||||
@@ -778,16 +781,17 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
|
|||||||
f.close();
|
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;
|
intmax_t Sent = 0;
|
||||||
do {
|
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) {
|
if (Temp < 1) {
|
||||||
info("Socket Closed! " + std::to_string(C));
|
info("Socket Closed! " + std::to_string(socket));
|
||||||
CloseSocketProper(C);
|
CloseSocketProper(socket);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Sent += Temp;
|
Sent += Temp;
|
||||||
|
C.UpdatePingTime();
|
||||||
} while (Sent < Size);
|
} while (Sent < Size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -854,7 +858,6 @@ bool TNetwork::SyncClient(const std::weak_ptr<TClient>& c) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
res = Respond(*LockedClient, v.Data(), true, true);
|
res = Respond(*LockedClient, v.Data(), true, true);
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-6
@@ -36,17 +36,15 @@ void TPPSMonitor::operator()() {
|
|||||||
ReadLock Lock(mServer.GetClientMutex());
|
ReadLock Lock(mServer.GetClientMutex());
|
||||||
if (!ClientPtr.expired()) {
|
if (!ClientPtr.expired()) {
|
||||||
c = ClientPtr.lock();
|
c = ClientPtr.lock();
|
||||||
} else return true;
|
} else
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (c->GetCarCount() > 0) {
|
if (c->GetCarCount() > 0) {
|
||||||
C++;
|
C++;
|
||||||
V += c->GetCarCount();
|
V += c->GetCarCount();
|
||||||
}
|
}
|
||||||
if (!c->IsSynced() || c->IsSyncing()) {
|
|
||||||
c->UpdatePingTime();
|
|
||||||
}
|
|
||||||
// kick on "no ping"
|
// 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());
|
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);
|
||||||
}
|
}
|
||||||
@@ -54,7 +52,7 @@ void TPPSMonitor::operator()() {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
for (auto& ClientToKick : TimedOutClients) {
|
for (auto& ClientToKick : TimedOutClients) {
|
||||||
Network().ClientKick(*ClientToKick, "Timeout (no ping for >30 seconds)");
|
Network().ClientKick(*ClientToKick, "Timeout (no ping for >5 min)");
|
||||||
}
|
}
|
||||||
TimedOutClients.clear();
|
TimedOutClients.clear();
|
||||||
if (C == 0 || mInternalPPS == 0) {
|
if (C == 0 || mInternalPPS == 0) {
|
||||||
|
|||||||
+4
-3
@@ -9,9 +9,7 @@
|
|||||||
|
|
||||||
#undef GetObject //Fixes Windows
|
#undef GetObject //Fixes Windows
|
||||||
|
|
||||||
#include "rapidjson/document.h"
|
#include "Json.h"
|
||||||
#include "rapidjson/stringbuffer.h"
|
|
||||||
#include "rapidjson/writer.h"
|
|
||||||
|
|
||||||
namespace json = rapidjson;
|
namespace json = rapidjson;
|
||||||
|
|
||||||
@@ -138,6 +136,9 @@ void TServer::GlobalParser(const std::weak_ptr<TClient>& Client, std::string Pac
|
|||||||
#endif
|
#endif
|
||||||
HandleEvent(*LockedClient, Packet);
|
HandleEvent(*LockedClient, Packet);
|
||||||
return;
|
return;
|
||||||
|
case 'N':
|
||||||
|
debug("got 'N' packet (" + std::to_string(Packet.size()) + ")");
|
||||||
|
Network.SendToAll(LockedClient.get(), Packet, false, true);
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -50,7 +50,14 @@ int main(int argc, char** argv) {
|
|||||||
Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; });
|
Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; });
|
||||||
|
|
||||||
TServer Server(argc, argv);
|
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");
|
RegisterThread("Main");
|
||||||
TResourceManager ResourceManager;
|
TResourceManager ResourceManager;
|
||||||
TPPSMonitor PPSMonitor(Server);
|
TPPSMonitor PPSMonitor(Server);
|
||||||
|
|||||||
Reference in New Issue
Block a user