From c695923825c5825a9f78769bff51912db7f4fe41 Mon Sep 17 00:00:00 2001 From: Koncord Date: Mon, 15 Aug 2016 07:48:25 +0800 Subject: [PATCH] Added master server stuff --- apps/openmw-mp/CMakeLists.txt | 1 + apps/openmw-mp/MasterClient.cpp | 172 +++++++++++++++++++++++++ apps/openmw-mp/MasterClient.hpp | 46 +++++++ apps/openmw-mp/Networking.cpp | 5 + apps/openmw-mp/Networking.hpp | 2 + apps/openmw-mp/main.cpp | 34 ++++- files/tes3mp/tes3mp-server-default.cfg | 14 +- 7 files changed, 268 insertions(+), 6 deletions(-) create mode 100644 apps/openmw-mp/MasterClient.cpp create mode 100644 apps/openmw-mp/MasterClient.hpp diff --git a/apps/openmw-mp/CMakeLists.txt b/apps/openmw-mp/CMakeLists.txt index f5ed74de3..2f2a8d693 100644 --- a/apps/openmw-mp/CMakeLists.txt +++ b/apps/openmw-mp/CMakeLists.txt @@ -48,6 +48,7 @@ set(SERVER Networking.cpp Utils.cpp Log.cpp + MasterClient.cpp Script/Script.cpp Script/ScriptFunction.cpp Script/ScriptFunctions.cpp Script/Functions/Translocations.cpp Script/Functions/Stats.cpp Script/Functions/Items.cpp diff --git a/apps/openmw-mp/MasterClient.cpp b/apps/openmw-mp/MasterClient.cpp new file mode 100644 index 000000000..60ffb88a8 --- /dev/null +++ b/apps/openmw-mp/MasterClient.cpp @@ -0,0 +1,172 @@ +// +// Created by koncord on 14.08.16. +// + +#include +#include +#include +#include +#include +#include "MasterClient.hpp" +#include "Log.hpp" +#include "Networking.hpp" + +using namespace std; + +bool MasterClient::sRun = false; + +MasterClient::MasterClient(std::string queryAddr, unsigned short queryPort, std::string serverAddr, + unsigned short serverPort) : queryAddr(queryAddr), queryPort(queryPort), + serverAddr(serverAddr), serverPort(serverPort) +{ + httpConnection = RakNet::HTTPConnection2::GetInstance(); + tcpInterface.Start(0, 64); + tcpInterface.AttachPlugin(httpConnection); + players = 0; + maxPlayers = 0; + motd = ""; + timeout = 1000; // every 1 seconds +} + +void MasterClient::SetPlayers(unsigned pl) +{ + mutexData.lock(); + players = pl; + mutexData.unlock(); +} + +void MasterClient::SetMaxPlayers(unsigned pl) +{ + mutexData.lock(); + maxPlayers = pl; + mutexData.unlock(); +} + +void MasterClient::SetMOTD(std::string &motd) +{ + mutexData.lock(); + this->motd = motd.substr(0, 200); + mutexData.unlock(); +} + +RakNet::RakString MasterClient::Send(std::string motd, unsigned players, unsigned maxPlayers, bool update) +{ + /*static unsigned short oldServerPort, oldQueryPort; + static string oldMotd; + static unsigned oldPlayers, oldMaxPlayers;*/ + std::stringstream sstr; + mutexData.lock(); + sstr << "{"; + sstr << "\"port\": " << serverPort << ", "; + sstr << "\"query_port\": " << queryPort << ", "; + sstr << "\"motd\": \"" << motd << "\", "; + sstr << "\"players\": " << players << ", "; + sstr << "\"max_players\": " << maxPlayers; + sstr << "}"; + mutexData.unlock(); + + std::string contentType = "application/json"; + RakNet::RakString createRequest; + + if (update) + createRequest = RakNet::RakString::FormatForPUT( + string("/api/servers/" + serverAddr + ":" + to_string(serverPort)).c_str(), contentType.c_str(), + sstr.str().c_str()); + else + createRequest = RakNet::RakString::FormatForPOST("/api/servers", contentType.c_str(), + sstr.str().c_str()); + + httpConnection->TransmitRequest(createRequest.C_String(), queryAddr.c_str(), queryPort); + + RakNet::Packet *packet; + RakNet::SystemAddress sa; + + RakNet::RakString transmitted, hostTransmitted; + RakNet::RakString response; + RakNet::SystemAddress hostReceived; + int contentOffset; + + while (true) + { + + // This is kind of crappy, but for TCP plugins, always do HasCompletedConnectionAttempt, + // then Receive(), then HasFailedConnectionAttempt(),HasLostConnection() + sa = tcpInterface.HasCompletedConnectionAttempt(); + if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS) + LOG_MESSAGE_SIMPLE(Log::INFO, "Connected to master server: %s", sa.ToString()); + + sa = tcpInterface.HasFailedConnectionAttempt(); + if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS) + { + LOG_MESSAGE_SIMPLE(Log::WARNING, "Failed to connect to master server: %s", sa.ToString()); + return "FAIL_CONNECT"; + } + sa = tcpInterface.HasLostConnection(); + if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS) + { + LOG_MESSAGE_SIMPLE(Log::WARNING, "Lost connection to master server: %s", sa.ToString()); + return "LOST_CONNECTION"; + } + + for (packet = tcpInterface.Receive(); packet; tcpInterface.DeallocatePacket( + packet), packet = tcpInterface.Receive()); + + if (httpConnection->GetResponse(transmitted, hostTransmitted, response, hostReceived, contentOffset)) + { + if(contentOffset < 0) + return "NO_CONTENT"; // no content + tcpInterface.CloseConnection(sa); + return (response.C_String() + contentOffset); + } + RakSleep(30); + } + +} + +void MasterClient::Update() +{ + assert(!sRun); + RakNet::RakString response = Send(motd, players, maxPlayers, false); + bool update = true; + sRun = true; + while (sRun) + { + if (response == "Created") + LOG_MESSAGE_SIMPLE(Log::INFO, "Server registered on the master server.", ""); + else if (response == "Accepted") + LOG_MESSAGE_SIMPLE(Log::INFO, "Server updated information about himself on the master server.", ""); + else if (response == "bad request") + { + LOG_MESSAGE_SIMPLE(Log::WARNING, "Update rate is too low, and the master server has deleted information about" + " the server. Trying low rate...", ""); + SetUpdateRate(timeout - step_rate); + update = false; + } + else + { + /*cout << "Error: \""<< response << "\"" << endl; + cout << response.GetLength() << endl;*/ + } + + RakSleep(timeout); + ; + players = mwmp::Networking::Get().NumberOfConnections(); + response = Send(motd, players, maxPlayers, update); + update = true; + } + +} + +void MasterClient::Stop() +{ + sRun = false; +} + +void MasterClient::SetUpdateRate(unsigned int rate) +{ + if(timeout < min_rate) + timeout = min_rate; + else if (timeout > max_rate) + timeout = max_rate; + timeout = rate; +} diff --git a/apps/openmw-mp/MasterClient.hpp b/apps/openmw-mp/MasterClient.hpp new file mode 100644 index 000000000..62960c2ba --- /dev/null +++ b/apps/openmw-mp/MasterClient.hpp @@ -0,0 +1,46 @@ +// +// Created by koncord on 14.08.16. +// + +#ifndef OPENMW_MASTERCLIENT_HPP +#define OPENMW_MASTERCLIENT_HPP + +#include +#include +#include +#include + +class MasterClient +{ +public: + static const unsigned int step_rate = 1000; + static const unsigned int min_rate = 1000; + static const unsigned int max_rate = 30000; +public: + MasterClient(std::string queryAddr, unsigned short queryPort, std::string serverAddr, unsigned short serverPort); + void SetPlayers(unsigned pl); + void SetMaxPlayers(unsigned pl); + void SetMOTD(std::string &motd); + void Update(); + void Stop(); + void SetUpdateRate(unsigned int rate); + +private: + RakNet::RakString Send(std::string motd, unsigned players, unsigned maxPlayers, bool update = true); +private: + std::string queryAddr; + unsigned short queryPort; + std::string serverAddr; + unsigned short serverPort; + std::string motd; + unsigned players, maxPlayers; + RakNet::HTTPConnection2 *httpConnection; + RakNet::TCPInterface tcpInterface; + unsigned int timeout; + static bool sRun; + std::mutex mutexData; + +}; + + +#endif //OPENMW_MASTERCLIENT_HPP diff --git a/apps/openmw-mp/Networking.cpp b/apps/openmw-mp/Networking.cpp index 0981914c9..98a398d4d 100644 --- a/apps/openmw-mp/Networking.cpp +++ b/apps/openmw-mp/Networking.cpp @@ -402,3 +402,8 @@ void Networking::KickPlayer(RakNet::RakNetGUID guid) { peer->CloseConnection(guid, true); } + +unsigned short Networking::NumberOfConnections() const +{ + return peer->NumberOfConnections(); +} diff --git a/apps/openmw-mp/Networking.hpp b/apps/openmw-mp/Networking.hpp index 200ab2b0f..62fd77ea6 100644 --- a/apps/openmw-mp/Networking.hpp +++ b/apps/openmw-mp/Networking.hpp @@ -6,6 +6,7 @@ #define OPENMW_NETWORKING_HPP #include +#include "Player.hpp" namespace mwmp { @@ -19,6 +20,7 @@ namespace mwmp void DisconnectPlayer(RakNet::RakNetGUID guid); void KickPlayer(RakNet::RakNetGUID guid); void Update(RakNet::Packet *packet); + unsigned short NumberOfConnections() const; int MainLoop(); diff --git a/apps/openmw-mp/main.cpp b/apps/openmw-mp/main.cpp index 4e8cd378a..17c34fdf8 100644 --- a/apps/openmw-mp/main.cpp +++ b/apps/openmw-mp/main.cpp @@ -2,6 +2,7 @@ #include #include "Player.hpp" #include "Networking.hpp" +#include "MasterClient.hpp" #include "Log.hpp" #include #include @@ -10,6 +11,7 @@ #include #include #include +#include using namespace std; using namespace mwmp; @@ -64,6 +66,11 @@ std::string loadSettings (Settings::Manager & settings) return settingspath; } +void queryThread(MasterClient *mclient) +{ + mclient->Update(); +} + int main(int argc, char *argv[]) { Settings::Manager mgr; @@ -76,6 +83,7 @@ int main(int argc, char *argv[]) LOG_INIT(logLevel); int players = mgr.getInt("players", "General"); + string addr = mgr.getString("address", "General"); int port = mgr.getInt("port", "General"); string plugin_home = mgr.getString("home", "Plugins"); @@ -99,7 +107,7 @@ int main(int argc, char *argv[]) const char passw[8] = "1234567"; peer->SetIncomingPassword(passw, sizeof(passw)); - RakNet::SocketDescriptor sd((unsigned short)port, 0); + RakNet::SocketDescriptor sd((unsigned short)port, addr.c_str()); if (peer->Startup((unsigned)players, &sd, 1) != RakNet::RAKNET_STARTED) return 0; @@ -107,11 +115,33 @@ int main(int argc, char *argv[]) Networking networking(peer); + bool masterEnabled = mgr.getBool("enabled", "MasterServer"); + thread thrQuery; + MasterClient *mclient; + if(masterEnabled) + { + LOG_MESSAGE_SIMPLE(Log::INFO, "%s", "Sharing server query info to master enabled."); + string masterAddr = mgr.getString("address", "MasterServer"); + int masterPort = mgr.getInt("port", "MasterServer"); + mclient = new MasterClient(masterAddr, (unsigned short) masterPort, addr, (unsigned short) port); + mclient->SetMaxPlayers((unsigned)players); + string motd = mgr.getString("motd", "General"); + mclient->SetMOTD(motd); + thrQuery = thread(queryThread, mclient); + } + + int code = networking.MainLoop(); RakNet::RakPeerInterface::DestroyInstance(peer); + + if(thrQuery.joinable()) + { + mclient->Stop(); + thrQuery.join(); + } + if (code == 0) - printf("Quitting peacefully.\n"); LOG_MESSAGE_SIMPLE(Log::INFO, "%s", "Quitting peacefully."); LOG_QUIT(); diff --git a/files/tes3mp/tes3mp-server-default.cfg b/files/tes3mp/tes3mp-server-default.cfg index a6054fdfd..6c0ab52fc 100644 --- a/files/tes3mp/tes3mp-server-default.cfg +++ b/files/tes3mp/tes3mp-server-default.cfg @@ -1,12 +1,18 @@ [General] -;master = master.tes3mp.com:8088 +# from 3 to 0. 3 - only errors, 0 - all messages +loglevel = 0 +motd = My TES3MP server +address = server.tes3mp.com port = 25565 -;query = false #enable query server -;query-port = 25566 players = 4 [Plugins] -;home = ~/local/openmw/tes3mp +#home = ~/local/openmw/tes3mp home = ~/ClionProjects/PS-dev plugins = tes3mp.lua,chat_parser.lua +[MasterServer] +enabled = true +address = master.tes3mp.com +port = 8080 +rate = 1000 \ No newline at end of file