Initial work on client server within same process
This commit is contained in:
parent
b7f2a9614d
commit
c8ea01d264
@ -687,6 +687,7 @@ namespace GUIEngine
|
||||
#include "tips/tips_manager.hpp"
|
||||
#include "utils/debug.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "utils/stk_process.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
@ -755,7 +756,7 @@ namespace GUIEngine
|
||||
|
||||
std::vector<MenuMessage> gui_messages;
|
||||
|
||||
bool g_is_no_graphics;
|
||||
bool g_is_no_graphics[PT_COUNT];
|
||||
// ------------------------------------------------------------------------
|
||||
void showMessage(const core::stringw& message, const float time)
|
||||
{
|
||||
@ -1052,7 +1053,8 @@ namespace GUIEngine
|
||||
#ifdef ANDROID
|
||||
m_gui_functions.clear();
|
||||
#endif
|
||||
g_is_no_graphics = false;
|
||||
g_is_no_graphics[PT_MAIN] = false;
|
||||
g_is_no_graphics[PT_CHILD] = false;
|
||||
} // resetGlobalVariables
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
@ -1556,13 +1558,13 @@ namespace GUIEngine
|
||||
// -----------------------------------------------------------------------
|
||||
void disableGraphics()
|
||||
{
|
||||
g_is_no_graphics = true;
|
||||
g_is_no_graphics[STKProcess::getType()] = true;
|
||||
} // disableGraphics
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
bool isNoGraphics()
|
||||
{
|
||||
return g_is_no_graphics;
|
||||
return g_is_no_graphics[STKProcess::getType()];
|
||||
} // isNoGraphics
|
||||
#endif
|
||||
|
||||
|
@ -222,6 +222,9 @@
|
||||
#include "network/network.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_string.hpp"
|
||||
#include "network/protocols/connect_to_server.hpp"
|
||||
#include "network/protocols/client_lobby.hpp"
|
||||
#include "network/protocols/server_lobby.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
#include "network/rewind_queue.hpp"
|
||||
#include "network/server.hpp"
|
||||
@ -1731,6 +1734,9 @@ void clearGlobalVariables()
|
||||
// In android sometimes global variables is not reset when restart the app
|
||||
// we clear it here as much as possible
|
||||
STKProcess::reset();
|
||||
StateManager::clear();
|
||||
NetworkConfig::clear();
|
||||
STKHost::clear();
|
||||
race_manager = NULL;
|
||||
music_manager = NULL;
|
||||
irr_driver = NULL;
|
||||
|
140
src/network/child_loop.cpp
Normal file
140
src/network/child_loop.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2020 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "network/child_loop.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/protocols/server_lobby.hpp"
|
||||
#include "network/server_config.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/stk_process.hpp"
|
||||
#include "utils/time.hpp"
|
||||
#include "utils/vs.hpp"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
float ChildLoop::getLimitedDt()
|
||||
{
|
||||
m_prev_time = m_curr_time;
|
||||
|
||||
float dt = 0;
|
||||
while (1)
|
||||
{
|
||||
m_curr_time = StkTime::getMonoTimeMs();
|
||||
if (m_prev_time > m_curr_time)
|
||||
{
|
||||
m_prev_time = m_curr_time;
|
||||
}
|
||||
dt = (float)(m_curr_time - m_prev_time);
|
||||
while (dt == 0)
|
||||
{
|
||||
StkTime::sleep(1);
|
||||
m_curr_time = StkTime::getMonoTimeMs();
|
||||
if (m_prev_time > m_curr_time)
|
||||
{
|
||||
Log::error("MainLopp", "System clock keeps backwards!");
|
||||
m_prev_time = m_curr_time;
|
||||
}
|
||||
dt = (float)(m_curr_time - m_prev_time);
|
||||
}
|
||||
|
||||
const int current_fps = (int)(1000.0f / dt);
|
||||
const int max_fps = UserConfigParams::m_max_fps;
|
||||
if (current_fps <= max_fps)
|
||||
break;
|
||||
|
||||
int wait_time = 1000 / max_fps - 1000 / current_fps;
|
||||
if (wait_time < 1) wait_time = 1;
|
||||
|
||||
StkTime::sleep(wait_time);
|
||||
} // while(1)
|
||||
dt *= 0.001f;
|
||||
return dt;
|
||||
} // getLimitedDt
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void ChildLoop::run()
|
||||
{
|
||||
VS::setThreadName("ChildLoop");
|
||||
STKProcess::init(PT_CHILD);
|
||||
|
||||
GUIEngine::disableGraphics();
|
||||
NetworkConfig::get()->setIsServer(true);
|
||||
if (m_cl_config->m_lan_server)
|
||||
NetworkConfig::get()->setIsLAN();
|
||||
else
|
||||
{
|
||||
NetworkConfig::get()->setIPType(NetworkConfig::IP_V4);
|
||||
NetworkConfig::get()->detectIPType();
|
||||
NetworkConfig::get()->setIsWAN();
|
||||
NetworkConfig::get()->setIsPublicServer();
|
||||
}
|
||||
NetworkConfig::get()->setCurrentUserId(m_cl_config->m_login_id);
|
||||
NetworkConfig::get()->setCurrentUserToken(m_cl_config->m_token);
|
||||
NetworkConfig::get()->setNumFixedAI(m_cl_config->m_server_ai);
|
||||
// Unused afterwards
|
||||
delete m_cl_config;
|
||||
m_cl_config = NULL;
|
||||
|
||||
ServerConfig::loadServerLobbyFromConfig();
|
||||
StateManager::get()->enterMenuState();
|
||||
|
||||
m_curr_time = StkTime::getMonoTimeMs();
|
||||
float left_over_time = 0;
|
||||
while (!m_abort)
|
||||
{
|
||||
if ((STKHost::existHost() && STKHost::get()->requestedShutdown()) ||
|
||||
m_request_abort)
|
||||
{
|
||||
if (STKHost::existHost())
|
||||
STKHost::get()->shutdown();
|
||||
m_abort = true;
|
||||
}
|
||||
|
||||
// Tell the main process port and server id
|
||||
if (m_port == 0 && STKHost::existHost())
|
||||
{
|
||||
auto sl = LobbyProtocol::get<ServerLobby>();
|
||||
if (sl &&
|
||||
sl->getCurrentState() >= ServerLobby::WAITING_FOR_START_GAME)
|
||||
{
|
||||
m_port = STKHost::get()->getPrivatePort();
|
||||
m_server_online_id = sl->getServerIdOnline();
|
||||
}
|
||||
}
|
||||
|
||||
left_over_time += getLimitedDt();
|
||||
int num_steps = stk_config->time2Ticks(left_over_time);
|
||||
float dt = stk_config->ticks2Time(1);
|
||||
left_over_time -= num_steps * dt;
|
||||
|
||||
for (int i = 0; i < num_steps; i++)
|
||||
{
|
||||
if (auto pm = ProtocolManager::lock())
|
||||
pm->update(1);
|
||||
|
||||
if (m_abort || m_request_abort)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkConfig::destroy();
|
||||
StateManager::deallocate();
|
||||
} // run
|
67
src/network/child_loop.hpp
Normal file
67
src/network/child_loop.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2020 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_SERVER_LOOP_HPP
|
||||
#define HEADER_SERVER_LOOP_HPP
|
||||
|
||||
#include "utils/types.hpp"
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
|
||||
struct ChildLoopConfig
|
||||
{
|
||||
bool m_lan_server;
|
||||
uint32_t m_login_id;
|
||||
std::string m_token;
|
||||
unsigned m_server_ai;
|
||||
};
|
||||
|
||||
class ChildLoop
|
||||
{
|
||||
private:
|
||||
const ChildLoopConfig* m_cl_config;
|
||||
|
||||
std::atomic_bool m_abort;
|
||||
|
||||
std::atomic_bool m_request_abort;
|
||||
|
||||
std::atomic<uint16_t> m_port;
|
||||
|
||||
std::atomic<uint32_t> m_server_online_id;
|
||||
|
||||
uint64_t m_curr_time;
|
||||
uint64_t m_prev_time;
|
||||
float getLimitedDt();
|
||||
public:
|
||||
ChildLoop(const ChildLoopConfig& clc)
|
||||
: m_cl_config(new ChildLoopConfig(clc))
|
||||
{
|
||||
m_abort = false;
|
||||
m_request_abort = false;
|
||||
m_prev_time = m_curr_time = 0;
|
||||
m_port = 0;
|
||||
m_server_online_id = 0;
|
||||
}
|
||||
void run();
|
||||
/** Set the abort flag, causing the mainloop to be left. */
|
||||
void abort() { m_abort = true; }
|
||||
void requestAbort() { m_request_abort = true; }
|
||||
uint16_t getPort() const { return m_port; }
|
||||
uint32_t getServerOnlineId() const { return m_server_online_id; }
|
||||
}; // ChildLoop
|
||||
|
||||
#endif
|
@ -44,7 +44,7 @@
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
|
||||
NetworkConfig *NetworkConfig::m_network_config = NULL;
|
||||
NetworkConfig *NetworkConfig::m_network_config[PT_COUNT];
|
||||
|
||||
/** \class NetworkConfig
|
||||
* This class is the interface between STK and the online code, particularly
|
||||
|
@ -23,11 +23,13 @@
|
||||
#define HEADER_NETWORK_CONFIG
|
||||
|
||||
#include "race/race_manager.hpp"
|
||||
#include "utils/stk_process.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
#include "irrString.h"
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
@ -55,7 +57,7 @@ public:
|
||||
};
|
||||
private:
|
||||
/** The singleton instance. */
|
||||
static NetworkConfig *m_network_config;
|
||||
static NetworkConfig *m_network_config[PT_COUNT];
|
||||
|
||||
enum NetworkType
|
||||
{
|
||||
@ -122,18 +124,23 @@ public:
|
||||
/** Singleton get, which creates this object if necessary. */
|
||||
static NetworkConfig *get()
|
||||
{
|
||||
if (!m_network_config)
|
||||
m_network_config = new NetworkConfig();
|
||||
return m_network_config;
|
||||
ProcessType type = STKProcess::getType();
|
||||
if (!m_network_config[type])
|
||||
m_network_config[type] = new NetworkConfig();
|
||||
return m_network_config[type];
|
||||
} // get
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
static void destroy()
|
||||
{
|
||||
delete m_network_config; // It's ok to delete NULL
|
||||
m_network_config = NULL;
|
||||
ProcessType type = STKProcess::getType();
|
||||
delete m_network_config[type]; // It's ok to delete NULL
|
||||
m_network_config[type] = NULL;
|
||||
} // destroy
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
static void clear()
|
||||
{
|
||||
memset(m_network_config, 0, sizeof(m_network_config));
|
||||
} // clear
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets if this instance is a server or client. */
|
||||
void setIsServer(bool b)
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include <typeinfo>
|
||||
|
||||
// ============================================================================
|
||||
std::weak_ptr<ProtocolManager> ProtocolManager::m_protocol_manager;
|
||||
std::weak_ptr<ProtocolManager> ProtocolManager::m_protocol_manager[PT_COUNT];
|
||||
// ============================================================================
|
||||
std::shared_ptr<ProtocolManager> ProtocolManager::createInstance()
|
||||
{
|
||||
@ -47,10 +47,17 @@ std::shared_ptr<ProtocolManager> ProtocolManager::createInstance()
|
||||
"Create only 1 instance of ProtocolManager!");
|
||||
return NULL;
|
||||
}
|
||||
// This is called in STKHost creation, so its process type will be told
|
||||
// here
|
||||
ProcessType pt = STKProcess::getType();
|
||||
auto pm = std::make_shared<ProtocolManager>();
|
||||
pm->m_asynchronous_update_thread = std::thread([pm]()
|
||||
pm->m_asynchronous_update_thread = std::thread([pm, pt]()
|
||||
{
|
||||
VS::setThreadName("ProtocolManager");
|
||||
std::string thread_name = "PtlMgr";
|
||||
if (pt == PT_CHILD)
|
||||
thread_name += "_child";
|
||||
VS::setThreadName(thread_name.c_str());
|
||||
STKProcess::init(pt);
|
||||
while(!pm->m_exit.load())
|
||||
{
|
||||
pm->asynchronousUpdate();
|
||||
@ -61,9 +68,10 @@ std::shared_ptr<ProtocolManager> ProtocolManager::createInstance()
|
||||
});
|
||||
if (NetworkConfig::get()->isServer())
|
||||
{
|
||||
pm->m_game_protocol_thread = std::thread([pm]()
|
||||
pm->m_game_protocol_thread = std::thread([pm, pt]()
|
||||
{
|
||||
VS::setThreadName("CtrlEvents");
|
||||
STKProcess::init(pt);
|
||||
while (true)
|
||||
{
|
||||
std::unique_lock<std::mutex> ul(pm->m_game_protocol_mutex);
|
||||
@ -94,7 +102,7 @@ std::shared_ptr<ProtocolManager> ProtocolManager::createInstance()
|
||||
}
|
||||
});
|
||||
}
|
||||
m_protocol_manager = pm;
|
||||
m_protocol_manager[pt] = pm;
|
||||
return pm;
|
||||
} // createInstance
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "network/protocol.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
#include "utils/singleton.hpp"
|
||||
#include "utils/stk_process.hpp"
|
||||
#include "utils/synchronised.hpp"
|
||||
#include "utils/types.hpp"
|
||||
|
||||
@ -174,7 +175,7 @@ private:
|
||||
EventList m_controller_events_list;
|
||||
|
||||
/*! Single instance of protocol manager.*/
|
||||
static std::weak_ptr<ProtocolManager> m_protocol_manager;
|
||||
static std::weak_ptr<ProtocolManager> m_protocol_manager[PT_COUNT];
|
||||
|
||||
bool sendEvent(Event* event,
|
||||
std::array<OneProtocolType, PROTOCOL_MAX>& protocols);
|
||||
@ -205,12 +206,12 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
static bool emptyInstance()
|
||||
{
|
||||
return m_protocol_manager.expired();
|
||||
return m_protocol_manager[STKProcess::getType()].expired();
|
||||
} // emptyInstance
|
||||
// ------------------------------------------------------------------------
|
||||
static std::shared_ptr<ProtocolManager> lock()
|
||||
{
|
||||
return m_protocol_manager.lock();
|
||||
return m_protocol_manager[STKProcess::getType()].lock();
|
||||
} // lock
|
||||
|
||||
}; // class ProtocolManager
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/child_loop.hpp"
|
||||
#include "network/socket_address.hpp"
|
||||
#include "network/stk_ipv6.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
@ -113,42 +114,22 @@ void ConnectToServer::getClientServerInfo()
|
||||
{
|
||||
assert(m_server);
|
||||
// Allow up to 10 seconds for the separate process to fully start-up
|
||||
bool server_ipv6_socket = false;
|
||||
bool started = false;
|
||||
uint64_t timeout = StkTime::getMonoTimeMs() + 10000;
|
||||
const std::string& sid = NetworkConfig::get()->getServerIdFile();
|
||||
assert(!sid.empty());
|
||||
const std::string dir = StringUtils::getPath(sid);
|
||||
const std::string server_id_file = StringUtils::getBasename(sid);
|
||||
uint16_t port = 0;
|
||||
unsigned server_id = 0;
|
||||
ChildLoop* sl = STKHost::get()->getChildLoop();
|
||||
assert(sl);
|
||||
while (!ProtocolManager::lock()->isExiting() &&
|
||||
StkTime::getMonoTimeMs() < timeout)
|
||||
{
|
||||
std::set<std::string> files;
|
||||
file_manager->listFiles(files, dir);
|
||||
for (auto& f : files)
|
||||
{
|
||||
if (f.find(server_id_file) != std::string::npos)
|
||||
{
|
||||
auto split = StringUtils::split(f, '_');
|
||||
if (split.size() != 4)
|
||||
continue;
|
||||
if (!StringUtils::fromString(split[1], server_id))
|
||||
continue;
|
||||
if (!StringUtils::fromString(split[2], port))
|
||||
continue;
|
||||
server_ipv6_socket = split[3] == "v6";
|
||||
file_manager->removeFile(dir + "/" + f);
|
||||
started = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
port = sl->getPort();
|
||||
server_id = sl->getServerOnlineId();
|
||||
started = port != 0;
|
||||
if (started)
|
||||
break;
|
||||
StkTime::sleep(10);
|
||||
StkTime::sleep(1);
|
||||
}
|
||||
NetworkConfig::get()->setServerIdFile("");
|
||||
if (!started)
|
||||
{
|
||||
Log::error("ConnectToServer",
|
||||
@ -161,7 +142,8 @@ void ConnectToServer::getClientServerInfo()
|
||||
assert(port != 0);
|
||||
m_server->setAddress(SocketAddress("127.0.0.1", port));
|
||||
m_server->setPrivatePort(port);
|
||||
if (server_ipv6_socket)
|
||||
// The server will decide if to use IPv6 socket
|
||||
if (isIPv6Socket())
|
||||
{
|
||||
m_server->setIPV6Address(SocketAddress("::1", port));
|
||||
m_server->setIPV6Connection(true);
|
||||
@ -178,7 +160,7 @@ void ConnectToServer::getClientServerInfo()
|
||||
void ConnectToServer::asynchronousUpdate()
|
||||
{
|
||||
if (STKHost::get()->isClientServer() &&
|
||||
!NetworkConfig::get()->getServerIdFile().empty())
|
||||
m_server->getAddress().getPort() == 0)
|
||||
{
|
||||
getClientServerInfo();
|
||||
}
|
||||
|
@ -44,7 +44,7 @@
|
||||
#include "utils/time.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
std::weak_ptr<LobbyProtocol> LobbyProtocol::m_lobby;
|
||||
std::weak_ptr<LobbyProtocol> LobbyProtocol::m_lobby[PT_COUNT];
|
||||
|
||||
LobbyProtocol::LobbyProtocol()
|
||||
: Protocol(PROTOCOL_LOBBY_ROOM)
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define LOBBY_PROTOCOL_HPP
|
||||
|
||||
#include "network/protocol.hpp"
|
||||
#include "utils/stk_process.hpp"
|
||||
|
||||
class GameSetup;
|
||||
class NetworkPlayerProfile;
|
||||
@ -113,7 +114,7 @@ protected:
|
||||
|
||||
std::thread m_start_game_thread;
|
||||
|
||||
static std::weak_ptr<LobbyProtocol> m_lobby;
|
||||
static std::weak_ptr<LobbyProtocol> m_lobby[PT_COUNT];
|
||||
|
||||
/** Estimated current started game remaining time,
|
||||
* uint32_t max if not available. */
|
||||
@ -157,9 +158,10 @@ public:
|
||||
template<typename Singleton, typename... Types>
|
||||
static std::shared_ptr<Singleton> create(Types ...args)
|
||||
{
|
||||
assert(m_lobby.expired());
|
||||
ProcessType pt = STKProcess::getType();
|
||||
assert(m_lobby[pt].expired());
|
||||
auto ret = std::make_shared<Singleton>(args...);
|
||||
m_lobby = ret;
|
||||
m_lobby[pt] = ret;
|
||||
return std::dynamic_pointer_cast<Singleton>(ret);
|
||||
} // create
|
||||
|
||||
@ -167,7 +169,8 @@ public:
|
||||
/** Returns the singleton client or server lobby protocol. */
|
||||
template<class T> static std::shared_ptr<T> get()
|
||||
{
|
||||
if (std::shared_ptr<LobbyProtocol> lp = m_lobby.lock())
|
||||
ProcessType pt = STKProcess::getType();
|
||||
if (std::shared_ptr<LobbyProtocol> lp = m_lobby[pt].lock())
|
||||
{
|
||||
std::shared_ptr<T> new_type = std::dynamic_pointer_cast<T>(lp);
|
||||
if (new_type)
|
||||
|
@ -388,6 +388,7 @@ public:
|
||||
void initServerStatsTable();
|
||||
bool isAIProfile(const std::shared_ptr<NetworkPlayerProfile>& npp) const
|
||||
{ return m_ai_profiles.find(npp) != m_ai_profiles.end(); }
|
||||
uint32_t getServerIdOnline() const { return m_server_id_online; }
|
||||
}; // class ServerLobby
|
||||
|
||||
#endif // SERVER_LOBBY_HPP
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "network/protocols/server_lobby.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/server_config.hpp"
|
||||
#include "network/child_loop.hpp"
|
||||
#include "network/stk_ipv6.hpp"
|
||||
#include "network/stk_peer.hpp"
|
||||
#include "utils/log.hpp"
|
||||
@ -71,31 +72,37 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
STKHost *STKHost::m_stk_host = NULL;
|
||||
STKHost *STKHost::m_stk_host[PT_COUNT];
|
||||
bool STKHost::m_enable_console = false;
|
||||
|
||||
std::shared_ptr<LobbyProtocol> STKHost::create(SeparateProcess* p)
|
||||
std::shared_ptr<LobbyProtocol> STKHost::create(ChildLoop* cl)
|
||||
{
|
||||
assert(m_stk_host == NULL);
|
||||
ProcessType pt = STKProcess::getType();
|
||||
assert(m_stk_host[pt] == NULL);
|
||||
std::shared_ptr<LobbyProtocol> lp;
|
||||
if (NetworkConfig::get()->isServer())
|
||||
{
|
||||
std::shared_ptr<ServerLobby> sl =
|
||||
LobbyProtocol::create<ServerLobby>();
|
||||
m_stk_host = new STKHost(true/*server*/);
|
||||
m_stk_host[pt] = new STKHost(true/*server*/);
|
||||
sl->initServerStatsTable();
|
||||
lp = sl;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stk_host = new STKHost(false/*server*/);
|
||||
m_stk_host[pt] = new STKHost(false/*server*/);
|
||||
}
|
||||
// Separate process for client-server gui if exists
|
||||
m_stk_host->m_separate_process = p;
|
||||
if (!m_stk_host->m_network)
|
||||
m_stk_host[pt]->m_client_loop = cl;
|
||||
if (cl)
|
||||
{
|
||||
delete m_stk_host;
|
||||
m_stk_host = NULL;
|
||||
m_stk_host[pt]->m_client_loop_thread = std::thread(
|
||||
std::bind(&ChildLoop::run, cl));
|
||||
}
|
||||
if (!m_stk_host[pt]->m_network)
|
||||
{
|
||||
delete m_stk_host[pt];
|
||||
m_stk_host[pt] = NULL;
|
||||
}
|
||||
return lp;
|
||||
} // create
|
||||
@ -342,6 +349,11 @@ void STKHost::init()
|
||||
*/
|
||||
STKHost::~STKHost()
|
||||
{
|
||||
// Abort the server loop earlier so it can be stopped in background as
|
||||
// soon as possible
|
||||
if (m_client_loop)
|
||||
m_client_loop->requestAbort();
|
||||
|
||||
NetworkConfig::get()->clearActivePlayersForClient();
|
||||
requestShutdown();
|
||||
if (m_network_console.joinable())
|
||||
@ -362,7 +374,11 @@ STKHost::~STKHost()
|
||||
}
|
||||
delete m_network;
|
||||
enet_deinitialize();
|
||||
delete m_separate_process;
|
||||
if (m_client_loop)
|
||||
{
|
||||
m_client_loop_thread.join();
|
||||
delete m_client_loop;
|
||||
}
|
||||
} // ~STKHost
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -721,7 +737,8 @@ void STKHost::setErrorMessage(const irr::core::stringw &message)
|
||||
void STKHost::startListening()
|
||||
{
|
||||
m_exit_timeout.store(std::numeric_limits<uint64_t>::max());
|
||||
m_listening_thread = std::thread(std::bind(&STKHost::mainLoop, this));
|
||||
m_listening_thread = std::thread(std::bind(&STKHost::mainLoop, this,
|
||||
STKProcess::getType()));
|
||||
} // startListening
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -741,11 +758,16 @@ void STKHost::stopListening()
|
||||
* This function tries to get data from network low-level functions as
|
||||
* often as possible. When something is received, it generates an
|
||||
* event and passes it to the Network Manager.
|
||||
* \param self : used to pass the ENet host to the function.
|
||||
* \param pt : Used to register to different singleton.
|
||||
*/
|
||||
void STKHost::mainLoop()
|
||||
void STKHost::mainLoop(ProcessType pt)
|
||||
{
|
||||
VS::setThreadName("STKHost");
|
||||
std::string thread_name = "STKHost";
|
||||
if (pt == PT_CHILD)
|
||||
thread_name += "_child";
|
||||
VS::setThreadName(thread_name.c_str());
|
||||
|
||||
STKProcess::init(pt);
|
||||
Log::info("STKHost", "Listening has been started.");
|
||||
ENetEvent event;
|
||||
ENetHost* host = m_network->getENetHost();
|
||||
@ -1529,15 +1551,9 @@ void STKHost::updatePlayers(unsigned* ingame, unsigned* waiting,
|
||||
* creation screen. */
|
||||
bool STKHost::isClientServer() const
|
||||
{
|
||||
return NetworkConfig::get()->isClient() && m_separate_process != NULL;
|
||||
return m_client_loop != NULL;
|
||||
} // isClientServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool STKHost::hasServerAI() const
|
||||
{
|
||||
return NetworkConfig::get()->isServer() && m_separate_process != NULL;
|
||||
} // hasServerAI
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Return an valid public IPv4 or IPv6 address with port, empty if both are
|
||||
* unset, IPv6 will come first if both exists. */
|
||||
|
@ -22,6 +22,7 @@
|
||||
#ifndef STK_HOST_HPP
|
||||
#define STK_HOST_HPP
|
||||
|
||||
#include "utils/stk_process.hpp"
|
||||
#include "utils/synchronised.hpp"
|
||||
#include "utils/time.hpp"
|
||||
|
||||
@ -35,6 +36,7 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
@ -54,7 +56,7 @@ class NetworkString;
|
||||
class NetworkTimerSynchronizer;
|
||||
class Server;
|
||||
class ServerLobby;
|
||||
class SeparateProcess;
|
||||
class ChildLoop;
|
||||
class SocketAddress;
|
||||
class STKPeer;
|
||||
|
||||
@ -71,10 +73,12 @@ class STKHost
|
||||
{
|
||||
private:
|
||||
/** Singleton pointer to the instance. */
|
||||
static STKHost* m_stk_host;
|
||||
static STKHost* m_stk_host[PT_COUNT];
|
||||
|
||||
/** Separate process of server instance. */
|
||||
SeparateProcess* m_separate_process;
|
||||
ChildLoop* m_client_loop;
|
||||
|
||||
std::thread m_client_loop_thread;
|
||||
|
||||
/** ENet host interfacing sockets. */
|
||||
Network* m_network;
|
||||
@ -164,7 +168,7 @@ private:
|
||||
std::shared_ptr<ServerLobby> sl,
|
||||
std::map<std::string, uint64_t>& ctp);
|
||||
// ------------------------------------------------------------------------
|
||||
void mainLoop();
|
||||
void mainLoop(ProcessType pt);
|
||||
// ------------------------------------------------------------------------
|
||||
void getIPFromStun(int socket, const std::string& stun_address,
|
||||
short family, SocketAddress* result);
|
||||
@ -175,24 +179,29 @@ public:
|
||||
/** Creates the STKHost. It takes all confifguration parameters from
|
||||
* NetworkConfig. This STKHost can either be a client or a server.
|
||||
*/
|
||||
static std::shared_ptr<LobbyProtocol> create(SeparateProcess* p = NULL);
|
||||
static std::shared_ptr<LobbyProtocol> create(ChildLoop* cl = NULL);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the instance of STKHost. */
|
||||
static STKHost *get()
|
||||
{
|
||||
assert(m_stk_host != NULL);
|
||||
return m_stk_host;
|
||||
ProcessType pt = STKProcess::getType();
|
||||
assert(m_stk_host[pt] != NULL);
|
||||
return m_stk_host[pt];
|
||||
} // get
|
||||
// ------------------------------------------------------------------------
|
||||
static void destroy()
|
||||
{
|
||||
assert(m_stk_host != NULL);
|
||||
delete m_stk_host;
|
||||
m_stk_host = NULL;
|
||||
ProcessType pt = STKProcess::getType();
|
||||
assert(m_stk_host[pt] != NULL);
|
||||
delete m_stk_host[pt];
|
||||
m_stk_host[pt] = NULL;
|
||||
} // destroy
|
||||
// ------------------------------------------------------------------------
|
||||
/** Checks if the STKHost has been created. */
|
||||
static bool existHost() { return m_stk_host != NULL; }
|
||||
static bool existHost()
|
||||
{ return m_stk_host[STKProcess::getType()] != NULL; }
|
||||
// ------------------------------------------------------------------------
|
||||
static void clear() { memset(m_stk_host, 0, sizeof(m_stk_host)); }
|
||||
// ------------------------------------------------------------------------
|
||||
const SocketAddress& getPublicAddress() const
|
||||
{ return *m_public_address.get(); }
|
||||
@ -332,14 +341,6 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
bool isClientServer() const;
|
||||
// ------------------------------------------------------------------------
|
||||
bool hasServerAI() const;
|
||||
// ------------------------------------------------------------------------
|
||||
void setSeparateProcess(SeparateProcess* p)
|
||||
{
|
||||
assert(m_separate_process == NULL);
|
||||
m_separate_process = p;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
void initClientNetwork(ENetEvent& event, Network* new_network);
|
||||
// ------------------------------------------------------------------------
|
||||
std::map<uint32_t, uint32_t> getPeerPings()
|
||||
@ -387,6 +388,8 @@ public:
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
static BareNetworkString getStunRequest(uint8_t* stun_tansaction_id);
|
||||
// ------------------------------------------------------------------------
|
||||
ChildLoop* getChildLoop() const { return m_client_loop; }
|
||||
}; // class STKHost
|
||||
|
||||
#endif // STK_HOST_HPP
|
||||
|
@ -346,19 +346,20 @@ extern "C" void setIPv6Socket(int val)
|
||||
} // setIPV6
|
||||
|
||||
#else
|
||||
|
||||
#include <atomic>
|
||||
// ============================================================================
|
||||
int g_ipv6;
|
||||
// For client and server in same process using different thread
|
||||
std::atomic<int> g_ipv6(0);
|
||||
// ============================================================================
|
||||
extern "C" int isIPv6Socket()
|
||||
{
|
||||
return g_ipv6;
|
||||
return g_ipv6.load();
|
||||
} // isIPV6
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
extern "C" void setIPv6Socket(int val)
|
||||
{
|
||||
g_ipv6 = val;
|
||||
g_ipv6.store(val);
|
||||
} // setIPV6
|
||||
|
||||
#endif
|
||||
|
@ -24,12 +24,13 @@
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/server_config.hpp"
|
||||
#include "network/child_loop.hpp"
|
||||
#include "network/socket_address.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "online/online_profile.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "states_screens/online/networking_lobby.hpp"
|
||||
#include "utils/separate_process.hpp"
|
||||
#include "utils/stk_process.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
@ -294,10 +295,7 @@ void CreateServerScreen::createServer()
|
||||
|
||||
const bool private_server = !password.empty();
|
||||
ServerConfig::m_private_server_password = password;
|
||||
password = std::string(" --server-password=") + password;
|
||||
|
||||
SocketAddress server_address(0x7f000001,
|
||||
stk_config->m_server_discovery_port);
|
||||
SocketAddress server_address(0x7f000001, 0);
|
||||
|
||||
auto server = std::make_shared<Server>(0/*server_id*/, name,
|
||||
max_players, /*current_player*/0, (RaceManager::Difficulty)
|
||||
@ -333,43 +331,32 @@ void CreateServerScreen::createServer()
|
||||
#else
|
||||
|
||||
NetworkConfig::get()->setIsServer(false);
|
||||
std::ostringstream server_cfg;
|
||||
|
||||
const std::string server_name = StringUtils::xmlEncode(name);
|
||||
if (NetworkConfig::get()->isWAN())
|
||||
ServerConfig::m_server_name = StringUtils::xmlEncode(name);
|
||||
// Server always configurable if created with this screen
|
||||
ServerConfig::m_server_configurable = true;
|
||||
struct ChildLoopConfig clc;
|
||||
clc.m_lan_server = NetworkConfig::get()->isLAN();
|
||||
clc.m_login_id = NetworkConfig::get()->getCurrentUserId();
|
||||
clc.m_token = NetworkConfig::get()->getCurrentUserToken();
|
||||
clc.m_server_ai = 0;
|
||||
|
||||
switch (gamemode_widget->getSelection(PLAYER_ID_GAME_MASTER))
|
||||
{
|
||||
server_cfg << "--public-server --wan-server=" <<
|
||||
server_name << " --login-id=" <<
|
||||
NetworkConfig::get()->getCurrentUserId() << " --token=" <<
|
||||
NetworkConfig::get()->getCurrentUserToken();
|
||||
}
|
||||
else
|
||||
{
|
||||
server_cfg << "--lan-server=" << server_name;
|
||||
case 0:
|
||||
ServerConfig::m_server_mode = 3;
|
||||
break;
|
||||
case 1:
|
||||
ServerConfig::m_server_mode = 4;
|
||||
break;
|
||||
case 3:
|
||||
ServerConfig::m_server_mode = 6;
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear previous stk-server-id-file_*
|
||||
std::set<std::string> files;
|
||||
const std::string server_id_file = "stk-server-id-file_";
|
||||
file_manager->listFiles(files, file_manager->getUserConfigDir());
|
||||
for (auto& f : files)
|
||||
{
|
||||
if (f.find(server_id_file) != std::string::npos)
|
||||
{
|
||||
file_manager->removeFile(file_manager->getUserConfigDir() + "/" +
|
||||
f);
|
||||
}
|
||||
}
|
||||
NetworkConfig::get()->setServerIdFile(
|
||||
file_manager->getUserConfigFile(server_id_file));
|
||||
|
||||
server_cfg << " --stdout=server.log --mode=" <<
|
||||
gamemode_widget->getSelection(PLAYER_ID_GAME_MASTER) <<
|
||||
" --difficulty=" <<
|
||||
difficulty_widget->getSelection(PLAYER_ID_GAME_MASTER) <<
|
||||
" --max-players=" << max_players <<
|
||||
" --server-id-file=" << server_id_file <<
|
||||
" --log=1 --no-console-log";
|
||||
ServerConfig::m_server_difficulty =
|
||||
difficulty_widget->getSelection(PLAYER_ID_GAME_MASTER);
|
||||
ServerConfig::m_server_max_players = max_players;
|
||||
|
||||
if (m_more_options_spinner->isVisible())
|
||||
{
|
||||
@ -378,14 +365,17 @@ void CreateServerScreen::createServer()
|
||||
3/*is soccer*/)
|
||||
{
|
||||
if (esi == 0)
|
||||
server_cfg << " --soccer-timed";
|
||||
ServerConfig::m_soccer_goal_target = false;
|
||||
else
|
||||
server_cfg << " --soccer-goals";
|
||||
ServerConfig::m_soccer_goal_target = true;
|
||||
}
|
||||
else if (gamemode_widget->getSelection(PLAYER_ID_GAME_MASTER) ==
|
||||
2/*is battle*/)
|
||||
{
|
||||
server_cfg << " --battle-mode=" << esi;
|
||||
if (esi == 0)
|
||||
ServerConfig::m_server_mode = 7;
|
||||
else
|
||||
ServerConfig::m_server_mode = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -393,7 +383,7 @@ void CreateServerScreen::createServer()
|
||||
{
|
||||
if (esi > 0)
|
||||
{
|
||||
server_cfg << " --server-ai=" << esi;
|
||||
clc.m_server_ai = esi;
|
||||
NetworkAIController::setAIFrequency(10);
|
||||
}
|
||||
}
|
||||
@ -401,7 +391,13 @@ void CreateServerScreen::createServer()
|
||||
{
|
||||
// Grand prix track count
|
||||
if (esi > 0)
|
||||
server_cfg << " --network-gp=" << esi;
|
||||
{
|
||||
ServerConfig::m_gp_track_count = esi;
|
||||
if (ServerConfig::m_server_mode == 3)
|
||||
ServerConfig::m_server_mode = 0;
|
||||
else
|
||||
ServerConfig::m_server_mode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_prev_mode = gamemode_widget->getSelection(PLAYER_ID_GAME_MASTER);
|
||||
@ -412,10 +408,8 @@ void CreateServerScreen::createServer()
|
||||
m_prev_mode = m_prev_value = 0;
|
||||
}
|
||||
|
||||
SeparateProcess* sp =
|
||||
new SeparateProcess(SeparateProcess::getCurrentExecutableLocation(),
|
||||
server_cfg.str() + password);
|
||||
STKHost::create(sp);
|
||||
ChildLoop* cl = new ChildLoop(clc);
|
||||
STKHost::create(cl);
|
||||
NetworkingLobby::getInstance()->setJoinedServer(server);
|
||||
#endif
|
||||
} // createServer
|
||||
|
@ -32,24 +32,33 @@
|
||||
#include "modes/world.hpp"
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/stk_process.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace GUIEngine;
|
||||
|
||||
static StateManager* state_manager_singleton = NULL;
|
||||
static StateManager* state_manager_singleton[PT_COUNT];
|
||||
|
||||
StateManager* StateManager::get()
|
||||
{
|
||||
if (state_manager_singleton == NULL)
|
||||
state_manager_singleton = new StateManager();
|
||||
return state_manager_singleton;
|
||||
ProcessType type = STKProcess::getType();
|
||||
if (state_manager_singleton[type] == NULL)
|
||||
state_manager_singleton[type] = new StateManager();
|
||||
return state_manager_singleton[type];
|
||||
} // get
|
||||
|
||||
void StateManager::deallocate()
|
||||
{
|
||||
delete state_manager_singleton;
|
||||
state_manager_singleton = NULL;
|
||||
ProcessType type = STKProcess::getType();
|
||||
delete state_manager_singleton[type];
|
||||
state_manager_singleton[type] = NULL;
|
||||
} // deallocate
|
||||
|
||||
void StateManager::clear()
|
||||
{
|
||||
memset(state_manager_singleton, 0, sizeof(state_manager_singleton));
|
||||
} // clear
|
||||
|
||||
// ============================================================================
|
||||
|
||||
|
@ -210,6 +210,7 @@ public:
|
||||
// singleton
|
||||
static StateManager* get();
|
||||
static void deallocate();
|
||||
static void clear();
|
||||
void clearMenuStack() { m_menu_stack.clear(); }
|
||||
private:
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user