Merge remote-tracking branch 'origin/network_improvements' into game_protocol
This commit is contained in:
@@ -15,9 +15,9 @@
|
||||
|
||||
<div width="100%" height="fit" layout="horizontal-row" >
|
||||
<label proportion="1" text_align="left" I18N="In the server creation screen" text="Max. number of players"/>
|
||||
<gauge id="max_players" proportion="1" min_value="2" max_value="12"/>
|
||||
<gauge id="max_players" proportion="1" min_value="2"/>
|
||||
</div>
|
||||
|
||||
|
||||
<spacer height="20" width="20"/>
|
||||
|
||||
<div width="100%" height="fit" layout="horizontal-row" >
|
||||
|
||||
@@ -487,4 +487,11 @@
|
||||
-->
|
||||
<texture-compression quality="64"/>
|
||||
|
||||
<!-- List of default ports used, by default STK use random ports
|
||||
for client and server, disable it in user config to allow
|
||||
port forward. The server discovery port has to be the same
|
||||
across all clients and servers.
|
||||
-->
|
||||
<network server-discovery-port="2757" client-port="2758" server-port="2759"/>
|
||||
|
||||
</config>
|
||||
|
||||
@@ -48,9 +48,9 @@ CIrrDeviceStub::CIrrDeviceStub(const SIrrlichtCreationParameters& params)
|
||||
}
|
||||
else
|
||||
FileSystem = io::createFileSystem();
|
||||
core::stringc s = "Irrlicht Engine version ";
|
||||
s.append(getVersion());
|
||||
os::Printer::log(s.c_str(), ELL_INFORMATION);
|
||||
//core::stringc s = "Irrlicht Engine version ";
|
||||
//s.append(getVersion());
|
||||
//os::Printer::log(s.c_str(), ELL_INFORMATION);
|
||||
|
||||
checkVersion(params.SDK_version_do_not_use);
|
||||
}
|
||||
|
||||
@@ -129,10 +129,10 @@ void PlayerManager::onSTKQuit()
|
||||
* RequestManager.
|
||||
*/
|
||||
|
||||
Online::XMLRequest *PlayerManager::requestSignIn(const irr::core::stringw &username,
|
||||
const irr::core::stringw &password)
|
||||
void PlayerManager::requestSignIn(const irr::core::stringw &username,
|
||||
const irr::core::stringw &password)
|
||||
{
|
||||
return getCurrentPlayer()->requestSignIn(username, password);
|
||||
getCurrentPlayer()->requestSignIn(username, password);
|
||||
} // requestSignIn
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -111,8 +111,8 @@ public:
|
||||
static void resumeSavedSession();
|
||||
static void onSTKQuit();
|
||||
static void requestSignOut();
|
||||
static Online::XMLRequest *requestSignIn(const irr::core::stringw &username,
|
||||
const irr::core::stringw &password);
|
||||
static void requestSignIn(const irr::core::stringw &username,
|
||||
const irr::core::stringw &password);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the current player. */
|
||||
|
||||
@@ -138,8 +138,8 @@ public:
|
||||
virtual Online::OnlineProfile* getProfile() const = 0;
|
||||
virtual void requestPoll() const = 0;
|
||||
virtual void requestSavedSession() = 0;
|
||||
virtual Online::XMLRequest* requestSignIn(const irr::core::stringw &username,
|
||||
const irr::core::stringw &password) = 0;
|
||||
virtual void requestSignIn(const irr::core::stringw &username,
|
||||
const irr::core::stringw &password) = 0;
|
||||
virtual void signIn(bool success, const XMLNode * input) = 0;
|
||||
virtual void signOut(bool success, const XMLNode * input,
|
||||
const irr::core::stringw &info) = 0;
|
||||
|
||||
@@ -126,6 +126,12 @@ void STKConfig::load(const std::string &filename)
|
||||
Log::fatal("StkConfig", "No rotationalsmoothing defined in stk_config.");
|
||||
}
|
||||
|
||||
if (m_client_port == 0 || m_server_port == 0 || m_server_discovery_port == 0 ||
|
||||
m_client_port == m_server_port || m_client_port == m_server_discovery_port ||
|
||||
m_server_port == m_server_discovery_port)
|
||||
{
|
||||
Log::fatal("StkConfig", "Invalid default port values.");
|
||||
}
|
||||
CHECK_NEG(m_max_karts, "<karts max=..." );
|
||||
CHECK_NEG(m_item_switch_ticks, "item switch-time" );
|
||||
CHECK_NEG(m_bubblegum_counter, "bubblegum disappear counter");
|
||||
@@ -196,6 +202,9 @@ void STKConfig::init_defaults()
|
||||
m_cutscene_fov = 0.61f;
|
||||
m_max_skinning_bones = 1024;
|
||||
m_tc_quality = 16;
|
||||
m_server_discovery_port = 2757;
|
||||
m_client_port = 2758;
|
||||
m_server_port = 2759;
|
||||
|
||||
m_score_increase.clear();
|
||||
m_leader_intervals.clear();
|
||||
@@ -403,6 +412,19 @@ void STKConfig::getAllData(const XMLNode * root)
|
||||
tc->get("quality", &m_tc_quality);
|
||||
}
|
||||
|
||||
if (const XMLNode *tc = root->getNode("network"))
|
||||
{
|
||||
unsigned server_discovery_port = 0;
|
||||
unsigned client_port = 0;
|
||||
unsigned server_port = 0;
|
||||
tc->get("server-discovery-port", &server_discovery_port);
|
||||
tc->get("client-port", &client_port);
|
||||
tc->get("server-port", &server_port);
|
||||
m_server_discovery_port = (uint16_t)server_discovery_port;
|
||||
m_client_port = (uint16_t)client_port;
|
||||
m_server_port = (uint16_t)server_port;
|
||||
}
|
||||
|
||||
// Get the default KartProperties
|
||||
// ------------------------------
|
||||
const XMLNode *node = root -> getNode("general-kart-defaults");
|
||||
|
||||
@@ -170,6 +170,11 @@ public:
|
||||
|
||||
unsigned m_tc_quality;
|
||||
|
||||
/** Client and server port use random ports if enabled in user config. */
|
||||
uint16_t m_server_discovery_port;
|
||||
uint16_t m_client_port;
|
||||
uint16_t m_server_port;
|
||||
|
||||
/** Lists of TTF files used in STK. */
|
||||
std::vector<std::string> m_normal_ttf;
|
||||
std::vector<std::string> m_digit_ttf;
|
||||
|
||||
@@ -205,7 +205,7 @@ public:
|
||||
|
||||
irr::core::stringc toString() const;
|
||||
void revertToDefaults() { m_value = m_default_value; }
|
||||
|
||||
int getDefaultValue() { return m_default_value; }
|
||||
operator int() const { return m_value; }
|
||||
int& operator++(int dummy) { m_value++; return m_value; }
|
||||
int& operator=(const int& v) { m_value = v; return m_value; }
|
||||
@@ -713,37 +713,23 @@ namespace UserConfigParams
|
||||
// ---- Networking
|
||||
|
||||
PARAM_PREFIX IntUserConfigParam m_server_max_players
|
||||
PARAM_DEFAULT( IntUserConfigParam(16, "server_max_players",
|
||||
PARAM_DEFAULT( IntUserConfigParam(12, "server_max_players",
|
||||
"Maximum number of players on the server.") );
|
||||
|
||||
PARAM_PREFIX StringListUserConfigParam m_stun_servers
|
||||
PARAM_DEFAULT( StringListUserConfigParam("Stun_servers", "The stun servers"
|
||||
" that will be used to know the public address.",
|
||||
24,
|
||||
"provserver.televolution.net",
|
||||
"sip1.lakedestiny.cordiaip.com",
|
||||
"stun1.voiceeclipse.net",
|
||||
"stun01.sipphone.com",
|
||||
10,
|
||||
"stun.cope.es",
|
||||
"stun.12connect.com",
|
||||
"stun.callwithus.com",
|
||||
"stun.counterpath.net",
|
||||
"stun.endigovoip.com",
|
||||
"stun.ekiga.net",
|
||||
"stun.ideasip.com",
|
||||
"stun.internetcalls.com",
|
||||
"stun.ipns.com",
|
||||
"stun.noc.ams-ix.net",
|
||||
"stun.phonepower.com",
|
||||
"stun.phoneserve.com",
|
||||
"stun.rnktel.com",
|
||||
"stun.softjoys.com",
|
||||
"stunserver.org",
|
||||
"stun.sipgate.net",
|
||||
"stun.schlund.de",
|
||||
"stun.stunprotocol.org",
|
||||
"stun.voip.aebc.com",
|
||||
"stun.voipbuster.com",
|
||||
"stun.voxalot.com",
|
||||
"stun.voxgratia.org",
|
||||
"stun.xten.com") );
|
||||
"numb.viagenie.ca",
|
||||
"stun.ivao.aero") );
|
||||
|
||||
// ---- Gamemode setup
|
||||
PARAM_PREFIX IntToIntUserConfigParam m_num_karts_per_gamemode
|
||||
@@ -753,9 +739,15 @@ namespace UserConfigParams
|
||||
std::make_pair(1100, 4)
|
||||
));
|
||||
|
||||
// ---- Network
|
||||
PARAM_PREFIX GroupUserConfigParam m_network_group
|
||||
PARAM_DEFAULT(GroupUserConfigParam("Network", "Network Settings"));
|
||||
PARAM_PREFIX BoolUserConfigParam m_log_packets
|
||||
PARAM_DEFAULT( BoolUserConfigParam(false, "log-network-packets",
|
||||
"If all network packets should be logged") );
|
||||
PARAM_DEFAULT(BoolUserConfigParam(false, "log-network-packets",
|
||||
&m_network_group, "If all network packets should be logged"));
|
||||
PARAM_PREFIX BoolUserConfigParam m_random_ports
|
||||
PARAM_DEFAULT(BoolUserConfigParam(true, "randrom-ports",
|
||||
&m_network_group, "Use random ports for client and server connection"));
|
||||
|
||||
// ---- Graphic Quality
|
||||
PARAM_PREFIX GroupUserConfigParam m_graphics_quality
|
||||
@@ -837,17 +829,6 @@ namespace UserConfigParams
|
||||
PARAM_PREFIX BoolUserConfigParam m_crashed
|
||||
PARAM_DEFAULT( BoolUserConfigParam(false, "crashed") );
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__)
|
||||
// No console on windows
|
||||
# define CONSOLE_DEFAULT false
|
||||
#else
|
||||
# define CONSOLE_DEFAULT true
|
||||
#endif
|
||||
// No console on windows
|
||||
PARAM_PREFIX BoolUserConfigParam m_log_errors_to_console
|
||||
PARAM_DEFAULT( BoolUserConfigParam(
|
||||
CONSOLE_DEFAULT, "log_errors", "Enable logging to console.") );
|
||||
|
||||
// ---- Camera
|
||||
PARAM_PREFIX GroupUserConfigParam m_camera
|
||||
PARAM_DEFAULT( GroupUserConfigParam("camera",
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "graphics/stk_tex_manager.hpp"
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "guiengine/skin.hpp"
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
#include <array>
|
||||
@@ -208,7 +209,7 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi)
|
||||
|
||||
const unsigned int cur_tex = m_spritebank->getTextureCount() -1;
|
||||
#ifndef SERVER_ONLY
|
||||
if (bits->buffer != NULL)
|
||||
if (bits->buffer != NULL && !ProfileWorld::isNoGraphics())
|
||||
{
|
||||
video::ITexture* tex = m_spritebank->getTexture(cur_tex);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->getOpenGLTextureName());
|
||||
|
||||
@@ -303,7 +303,6 @@ core::recti IrrDriver::getSplitscreenWindow(int WindowNum)
|
||||
|
||||
const int x_grid_Position = WindowNum % cols;
|
||||
const int y_grid_Position = int(floor((WindowNum) / cols));
|
||||
int wid = (int)irr_driver->getActualScreenSize().Width;
|
||||
|
||||
//To prevent the viewport going over the right side, we use std::min to ensure the right corners are never larger than the total width
|
||||
return core::recti(
|
||||
@@ -715,8 +714,8 @@ void IrrDriver::initDevice()
|
||||
// set cursor visible by default (what's the default is not too clearly documented,
|
||||
// so let's decide ourselves...)
|
||||
m_device->getCursorControl()->setVisible(true);
|
||||
m_pointer_shown = true;
|
||||
#endif
|
||||
m_pointer_shown = true;
|
||||
} // initDevice
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -786,16 +785,19 @@ void IrrDriver::getOpenGLData(std::string *vendor, std::string *renderer,
|
||||
//-----------------------------------------------------------------------------
|
||||
void IrrDriver::showPointer()
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
if (!m_pointer_shown)
|
||||
{
|
||||
m_pointer_shown = true;
|
||||
this->getDevice()->getCursorControl()->setVisible(true);
|
||||
}
|
||||
#endif
|
||||
} // showPointer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void IrrDriver::hidePointer()
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
// always visible in artist debug mode, to be able to use the context menu
|
||||
if (UserConfigParams::m_artist_debug_mode)
|
||||
{
|
||||
@@ -808,6 +810,7 @@ void IrrDriver::hidePointer()
|
||||
m_pointer_shown = false;
|
||||
this->getDevice()->getCursorControl()->setVisible(false);
|
||||
}
|
||||
#endif
|
||||
} // hidePointer
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -79,7 +79,7 @@ STKTexture::STKTexture(video::IImage* img, const std::string& name)
|
||||
STKTexture::~STKTexture()
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
if (m_texture_name != 0)
|
||||
if (m_texture_name != 0 && !ProfileWorld::isNoGraphics())
|
||||
{
|
||||
glDeleteTextures(1, &m_texture_name);
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ namespace GUIEngine
|
||||
* it visible implicitely calls setActive(true). If you mix visiblity and (de)activated calls,
|
||||
* undefined behavior may ensue (like invisible but clickable buttons).
|
||||
*/
|
||||
void setVisible(bool visible);
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
/** Returns if the element is visible. */
|
||||
bool isVisible() const;
|
||||
|
||||
@@ -416,3 +416,13 @@ void IconButtonWidget::setLabelFont()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void IconButtonWidget::setVisible(bool visible)
|
||||
{
|
||||
Widget::setVisible(visible);
|
||||
|
||||
if (m_label != NULL)
|
||||
m_label->setVisible(visible);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace irr
|
||||
|
||||
#include "guiengine/widget.hpp"
|
||||
#include "utils/leak_check.hpp"
|
||||
#include "utils/cpp2011.hpp"
|
||||
|
||||
namespace GUIEngine
|
||||
{
|
||||
@@ -161,6 +162,14 @@ namespace GUIEngine
|
||||
// --------------------------------------------------------------------
|
||||
/** Returns the texture of this button. */
|
||||
const video::ITexture* getTexture();
|
||||
// --------------------------------------------------------------------
|
||||
virtual void setVisible(bool visible) OVERRIDE;
|
||||
// --------------------------------------------------------------------
|
||||
virtual void elementRemoved() OVERRIDE
|
||||
{
|
||||
Widget::elementRemoved();
|
||||
m_label = NULL;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
223
src/main.cpp
223
src/main.cpp
@@ -157,6 +157,7 @@
|
||||
# include <direct.h>
|
||||
# endif
|
||||
#else
|
||||
# include <signal.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <stdexcept>
|
||||
@@ -213,6 +214,7 @@
|
||||
#include "network/network_string.hpp"
|
||||
#include "network/rewind_manager.hpp"
|
||||
#include "network/rewind_queue.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "online/profile_manager.hpp"
|
||||
@@ -541,8 +543,8 @@ void cmdLineHelp()
|
||||
" and the music.\n"
|
||||
" -t, --track=NAME Start track NAME.\n"
|
||||
" --gp=NAME Start the specified Grand Prix.\n"
|
||||
" --add-gp-dir=DIR Load Grand Prix files in DIR. Setting will be saved "
|
||||
"in config.xml under additional_gp_directory. Use "
|
||||
" --add-gp-dir=DIR Load Grand Prix files in DIR. Setting will be saved\n"
|
||||
"in config.xml under additional_gp_directory. Use\n"
|
||||
"--add-gp-dir=\"\" to unset.\n"
|
||||
" --stk-config=FILE use ./data/FILE instead of "
|
||||
"./data/stk_config.xml\n"
|
||||
@@ -568,7 +570,7 @@ void cmdLineHelp()
|
||||
" --no-graphics Do not display the actual race.\n"
|
||||
" --demo-mode=t Enables demo mode after t seconds of idle time in "
|
||||
"main menu.\n"
|
||||
" --demo-tracks=t1,t2 List of tracks to be used in demo mode. No"
|
||||
" --demo-tracks=t1,t2 List of tracks to be used in demo mode. No\n"
|
||||
" spaces are allowed in the track names.\n"
|
||||
" --demo-laps=n Number of laps to use in a demo.\n"
|
||||
" --demo-karts=n Number of karts to use in a demo.\n"
|
||||
@@ -576,21 +578,22 @@ void cmdLineHelp()
|
||||
// " --test-ai=n Use the test-ai for every n-th AI kart.\n"
|
||||
// " (so n=1 means all Ais will be the test ai)\n"
|
||||
// "
|
||||
" --network-console Enable network console.\n"
|
||||
" --wan-server=name Start a Wan server (not a playing client).\n"
|
||||
" --public-server Allow direct connection to the server (without stk server)\n"
|
||||
" --lan-server=name Start a LAN server (not a playing client).\n"
|
||||
" --server-password= Sets a password for a server (both client&server).\n"
|
||||
" --connect-now=ip Connect to a server with IP known now (in format x.x.x.x:xxx(port)).\n"
|
||||
" --connect-now=ip Connect to a server with IP known now\n"
|
||||
" (in format x.x.x.x:xxx(port)), the port should be its\n"
|
||||
" private port.\n"
|
||||
" --login=s Automatically log in (set the login).\n"
|
||||
" --password=s Automatically log in (set the password).\n"
|
||||
" --port=n Port number to use.\n"
|
||||
" --my-address=1.1.1.1:1 Own IP address (can replace stun protocol)\n"
|
||||
" --disable-lan Disable LAN detection (connect using WAN).\n"
|
||||
" --auto-connect Automatically connect to fist server and start race\n"
|
||||
" --max-players=n Maximum number of clients (server only).\n"
|
||||
" --no-console Does not write messages in the console but to\n"
|
||||
" --no-console-log Does not write messages in the console but to\n"
|
||||
" stdout.log.\n"
|
||||
" --console Write messages in the console and files\n"
|
||||
" -h, --help Show this help.\n"
|
||||
" --log=N Set the verbosity to a value between\n"
|
||||
" 0 (Debug) and 5 (Only Fatal messages)\n"
|
||||
@@ -674,12 +677,8 @@ int handleCmdLineOutputModifier()
|
||||
Log::disableColor();
|
||||
Log::verbose("main", "Colours disabled.");
|
||||
}
|
||||
|
||||
if(CommandLine::has("--console"))
|
||||
UserConfigParams::m_log_errors_to_console=true;
|
||||
if(CommandLine::has("--no-console"))
|
||||
UserConfigParams::m_log_errors_to_console=false;
|
||||
|
||||
if(CommandLine::has("--no-console-log"))
|
||||
Log::toggleConsoleLog(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -732,7 +731,6 @@ int handleCmdLinePreliminary()
|
||||
if(CommandLine::has("--no-graphics") || CommandLine::has("-l"))
|
||||
{
|
||||
ProfileWorld::disableGraphics();
|
||||
UserConfigParams::m_log_errors_to_console=true;
|
||||
}
|
||||
|
||||
if(CommandLine::has("--screensize", &s) || CommandLine::has("-s", &s))
|
||||
@@ -891,7 +889,6 @@ int handleCmdLine()
|
||||
int n;
|
||||
std::string s;
|
||||
|
||||
bool try_login = false;
|
||||
irr::core::stringw login, password;
|
||||
|
||||
if (CommandLine::has("--unit-testing"))
|
||||
@@ -984,10 +981,82 @@ int handleCmdLine()
|
||||
UserConfigParams::m_check_debug=true;
|
||||
}
|
||||
|
||||
if (CommandLine::has( "--difficulty", &s))
|
||||
{
|
||||
int n = atoi(s.c_str());
|
||||
if(n<0 || n>RaceManager::DIFFICULTY_LAST)
|
||||
Log::warn("main", "Invalid difficulty '%s' - ignored.\n",
|
||||
s.c_str());
|
||||
else
|
||||
race_manager->setDifficulty(RaceManager::Difficulty(n));
|
||||
} // --mode
|
||||
|
||||
if (CommandLine::has("--type", &n))
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
// The order here makes server creation screen easier
|
||||
case 0: race_manager->setMinorMode(RaceManager::MINOR_MODE_NORMAL_RACE);
|
||||
break;
|
||||
case 1: race_manager->setMinorMode(RaceManager::MINOR_MODE_TIME_TRIAL);
|
||||
break;
|
||||
case 2: race_manager->setMinorMode(RaceManager::MINOR_MODE_3_STRIKES);
|
||||
break;
|
||||
case 3: race_manager->setMinorMode(RaceManager::MINOR_MODE_SOCCER);
|
||||
break;
|
||||
case 4: race_manager->setMinorMode(RaceManager::MINOR_MODE_FOLLOW_LEADER);
|
||||
break;
|
||||
default:
|
||||
Log::warn("main", "Invalid race type '%d' - ignored.", n);
|
||||
}
|
||||
} // --type
|
||||
|
||||
|
||||
if (CommandLine::has("--login", &s))
|
||||
login = s.c_str();
|
||||
if (CommandLine::has("--password", &s))
|
||||
password = s.c_str();
|
||||
|
||||
bool can_wan = false;
|
||||
if (!login.empty() && !password.empty())
|
||||
{
|
||||
irr::core::stringw s;
|
||||
PlayerManager::requestSignIn(login, password);
|
||||
while (PlayerManager::getCurrentOnlineState() != PlayerProfile::OS_SIGNED_IN)
|
||||
{
|
||||
Online::RequestManager::get()->update(0.0f);
|
||||
StkTime::sleep(1);
|
||||
}
|
||||
Log::info("Main", "Logged in from command-line.");
|
||||
can_wan = true;
|
||||
}
|
||||
|
||||
if (!can_wan && CommandLine::has("--login-id", &n) &&
|
||||
CommandLine::has("--token", &s))
|
||||
{
|
||||
NetworkConfig::get()->setCurrentUserId(n);
|
||||
NetworkConfig::get()->setCurrentUserToken(s);
|
||||
can_wan = true;
|
||||
}
|
||||
|
||||
// Networking command lines
|
||||
if(CommandLine::has("--start-console"))
|
||||
if(CommandLine::has("--network-console"))
|
||||
STKHost::m_enable_console = true;
|
||||
|
||||
if (CommandLine::has("--server-password", &s))
|
||||
{
|
||||
core::stringw pw = StringUtils::xmlDecode(s);
|
||||
NetworkConfig::get()->setPassword(StringUtils::wideToUtf8(pw));
|
||||
}
|
||||
|
||||
if (CommandLine::has("--server-id-file", &s))
|
||||
{
|
||||
NetworkConfig::get()->setServerIdFile(
|
||||
file_manager->getUserConfigFile(s));
|
||||
}
|
||||
|
||||
if(CommandLine::has("--max-players", &n))
|
||||
UserConfigParams::m_server_max_players=n;
|
||||
NetworkConfig::get()->
|
||||
setMaxPlayers(UserConfigParams::m_server_max_players);
|
||||
if (CommandLine::has("--port", &n))
|
||||
@@ -1009,65 +1078,55 @@ int handleCmdLine()
|
||||
Log::info("main", "Try to connect to server '%s'.",
|
||||
ip.toString().c_str() );
|
||||
irr::core::stringw name = StringUtils::utf8ToWide(ip.toString());
|
||||
ServersManager::get()->addServer(new Server(name, /*lan*/true,
|
||||
16, 0, ip));
|
||||
ServersManager::get()->setJoinedServer(0);
|
||||
STKHost::create();
|
||||
auto server = std::make_shared<Server>(0, name,
|
||||
NetworkConfig::get()->getMaxPlayers(), 0,
|
||||
race_manager->getDifficulty(),
|
||||
NetworkConfig::get()->getServerGameMode(race_manager->getMinorMode(),
|
||||
race_manager->getMajorMode()), ip);
|
||||
NetworkingLobby::getInstance()->setJoinedServer(server);
|
||||
STKHost::create(server);
|
||||
}
|
||||
|
||||
if (CommandLine::has("--wan-server", &s))
|
||||
{
|
||||
// Try to use saved user token if exists
|
||||
PlayerProfile* player = PlayerManager::getCurrentPlayer();
|
||||
if (player && player->wasOnlineLastTime() && player->wasOnlineLastTime() &&
|
||||
player->hasSavedSession())
|
||||
if (!can_wan && player && player->wasOnlineLastTime() &&
|
||||
player->wasOnlineLastTime() && player->hasSavedSession())
|
||||
{
|
||||
while (true)
|
||||
while (PlayerManager::getCurrentOnlineState() != PlayerProfile::OS_SIGNED_IN)
|
||||
{
|
||||
Online::RequestManager::get()->update(0.0f);
|
||||
StkTime::sleep(1);
|
||||
if (PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_SIGNED_IN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
NetworkConfig::get()->setServerName(core::stringw(s.c_str()));
|
||||
NetworkConfig::get()->setIsServer(true);
|
||||
NetworkConfig::get()->setIsWAN();
|
||||
STKHost::create();
|
||||
Log::info("main", "Creating a WAN server '%s'.", s.c_str());
|
||||
can_wan = true;
|
||||
}
|
||||
else
|
||||
else if (!can_wan)
|
||||
{
|
||||
Log::warn("main", "No saved online player session to create a wan server");
|
||||
}
|
||||
if (can_wan)
|
||||
{
|
||||
NetworkConfig::get()->setServerName(StringUtils::xmlDecode(s));
|
||||
NetworkConfig::get()->setIsServer(true);
|
||||
NetworkConfig::get()->setIsWAN();
|
||||
NetworkConfig::get()->setIsPublicServer();
|
||||
STKHost::create();
|
||||
Log::info("main", "Creating a WAN server '%s'.", s.c_str());
|
||||
}
|
||||
}
|
||||
else if (CommandLine::has("--lan-server", &s))
|
||||
{
|
||||
NetworkConfig::get()->setServerName(core::stringw(s.c_str()));
|
||||
NetworkConfig::get()->setServerName(StringUtils::xmlDecode(s));
|
||||
NetworkConfig::get()->setIsServer(true);
|
||||
NetworkConfig::get()->setIsLAN();
|
||||
STKHost::create();
|
||||
Log::info("main", "Creating a LAN server '%s'.", s.c_str());
|
||||
}
|
||||
if (CommandLine::has("--server-password", &s))
|
||||
{
|
||||
NetworkConfig::get()->setPassword(s);
|
||||
}
|
||||
if (CommandLine::has("--auto-connect"))
|
||||
{
|
||||
NetworkConfig::get()->setAutoConnect(true);
|
||||
}
|
||||
if(CommandLine::has("--max-players", &n))
|
||||
UserConfigParams::m_server_max_players=n;
|
||||
|
||||
if(CommandLine::has("--login", &s) )
|
||||
{
|
||||
login = s.c_str();
|
||||
try_login = true;
|
||||
} // --login
|
||||
|
||||
if(CommandLine::has("--password", &s))
|
||||
password = s.c_str();
|
||||
|
||||
/** Disable detection of LAN connection when connecting via WAN. This is
|
||||
* mostly a debugging feature to force using WAN connection. */
|
||||
@@ -1126,31 +1185,6 @@ int handleCmdLine()
|
||||
race_manager->setNumKarts((int)l.size()+1);
|
||||
} // --ai
|
||||
|
||||
if(CommandLine::has( "--mode", &s) || CommandLine::has( "--difficulty", &s))
|
||||
{
|
||||
int n = atoi(s.c_str());
|
||||
if(n<0 || n>RaceManager::DIFFICULTY_LAST)
|
||||
Log::warn("main", "Invalid difficulty '%s' - ignored.\n",
|
||||
s.c_str());
|
||||
else
|
||||
race_manager->setDifficulty(RaceManager::Difficulty(n));
|
||||
} // --mode
|
||||
|
||||
if(CommandLine::has("--type", &n))
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 0: race_manager->setMinorMode(RaceManager::MINOR_MODE_NORMAL_RACE);
|
||||
break;
|
||||
case 1: race_manager->setMinorMode(RaceManager::MINOR_MODE_TIME_TRIAL);
|
||||
break;
|
||||
case 2: race_manager->setMinorMode(RaceManager::MINOR_MODE_FOLLOW_LEADER);
|
||||
break;
|
||||
default:
|
||||
Log::warn("main", "Invalid race type '%d' - ignored.", n);
|
||||
}
|
||||
} // --type
|
||||
|
||||
if(CommandLine::has("--track", &s) || CommandLine::has("-t", &s))
|
||||
{
|
||||
race_manager->setTrack(s);
|
||||
@@ -1331,24 +1365,12 @@ int handleCmdLine()
|
||||
|
||||
CommandLine::reportInvalidParameters();
|
||||
|
||||
if(ProfileWorld::isProfileMode())
|
||||
if (ProfileWorld::isProfileMode() || ProfileWorld::isNoGraphics())
|
||||
{
|
||||
UserConfigParams::m_sfx = false; // Disable sound effects
|
||||
UserConfigParams::m_music = false;// and music when profiling
|
||||
}
|
||||
|
||||
if (try_login)
|
||||
{
|
||||
irr::core::stringw s;
|
||||
Online::XMLRequest* request =
|
||||
PlayerManager::requestSignIn(login, password);
|
||||
|
||||
if (request->isSuccess())
|
||||
{
|
||||
Log::info("Main", "Logged in from command-line.");
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
} // handleCmdLine
|
||||
|
||||
@@ -1541,7 +1563,13 @@ int main(int argc, char *argv[] )
|
||||
CommandLine::init(argc, argv);
|
||||
|
||||
CrashReporting::installHandlers();
|
||||
|
||||
#ifndef WIN32
|
||||
signal(SIGTERM, [](int signum)
|
||||
{
|
||||
if (main_loop)
|
||||
main_loop->abort();
|
||||
});
|
||||
#endif
|
||||
srand(( unsigned ) time( 0 ));
|
||||
|
||||
try
|
||||
@@ -1572,7 +1600,11 @@ int main(int argc, char *argv[] )
|
||||
|
||||
// Get into menu mode initially.
|
||||
input_manager->setMode(InputManager::MENU);
|
||||
main_loop = new MainLoop();
|
||||
int parent_pid;
|
||||
if (CommandLine::has("--parent-process", &parent_pid))
|
||||
main_loop = new MainLoop(parent_pid);
|
||||
else
|
||||
main_loop = new MainLoop(0/*parent_pid*/);
|
||||
material_manager->loadMaterial();
|
||||
|
||||
// Preload the explosion effects (explode.png)
|
||||
@@ -1735,9 +1767,7 @@ int main(int argc, char *argv[] )
|
||||
HardwareStats::reportHardwareStats();
|
||||
}
|
||||
|
||||
// This can only be the case if --connect-now was used, which adds
|
||||
// a server to the server list.
|
||||
if (ServersManager::get()->getNumServers()==1)
|
||||
if (STKHost::existHost())
|
||||
{
|
||||
NetworkingLobby::getInstance()->push();
|
||||
}
|
||||
@@ -1857,8 +1887,8 @@ int main(int argc, char *argv[] )
|
||||
StateManager::get()->resetActivePlayers();
|
||||
if(input_manager) delete input_manager; // if early crash avoid delete NULL
|
||||
|
||||
if(NetworkConfig::get()->isNetworking() && STKHost::existHost())
|
||||
STKHost::get()->abort();
|
||||
if (STKHost::existHost())
|
||||
STKHost::get()->shutdown();
|
||||
|
||||
cleanSuperTuxKart();
|
||||
|
||||
@@ -1967,12 +1997,7 @@ static void cleanSuperTuxKart()
|
||||
// in the request manager, so it can not be deleted earlier.
|
||||
if(addons_manager) delete addons_manager;
|
||||
|
||||
// FIXME: do we need to wait for threads there, can they be
|
||||
// moved further up?
|
||||
ServersManager::deallocate();
|
||||
if(NetworkConfig::get()->isNetworking() && STKHost::existHost())
|
||||
STKHost::destroy();
|
||||
|
||||
cleanUserConfig();
|
||||
|
||||
StateManager::deallocate();
|
||||
|
||||
@@ -58,9 +58,6 @@ void override_default_params()
|
||||
|
||||
// Create default user istead of showing login screen to make life easier
|
||||
UserConfigParams::m_enforce_current_player = true;
|
||||
|
||||
// Just for debugging
|
||||
UserConfigParams::m_log_errors_to_console = true;
|
||||
}
|
||||
|
||||
void android_main(struct android_app* app)
|
||||
|
||||
@@ -45,14 +45,38 @@
|
||||
|
||||
MainLoop* main_loop = 0;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
MainLoop::MainLoop() :
|
||||
m_abort(false)
|
||||
MainLoop::MainLoop(unsigned parent_pid)
|
||||
: m_abort(false), m_parent_pid(parent_pid)
|
||||
{
|
||||
m_curr_time = 0;
|
||||
m_prev_time = 0;
|
||||
m_throttle_fps = true;
|
||||
m_is_last_substep = false;
|
||||
#ifdef WIN32
|
||||
if (parent_pid != 0)
|
||||
{
|
||||
std::string class_name = "separate_process";
|
||||
class_name += StringUtils::toString(GetCurrentProcessId());
|
||||
WNDCLASSEX wx = {};
|
||||
wx.cbSize = sizeof(WNDCLASSEX);
|
||||
wx.lpfnWndProc = [](HWND h, UINT m, WPARAM w, LPARAM l)->LRESULT
|
||||
{
|
||||
if (m == WM_DESTROY)
|
||||
{
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProc(h, m, w, l);
|
||||
};
|
||||
wx.hInstance = GetModuleHandle(0);
|
||||
wx.lpszClassName = &class_name[0];
|
||||
if (RegisterClassEx(&wx))
|
||||
{
|
||||
CreateWindowEx(0, &class_name[0], "stk_server_only",
|
||||
0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} // MainLoop
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -259,8 +283,38 @@ void MainLoop::run()
|
||||
// DT keeps track of the leftover time, since the race update
|
||||
// happens in fixed timesteps
|
||||
float left_over_time = 0;
|
||||
|
||||
#ifdef WIN32
|
||||
HANDLE parent = 0;
|
||||
if (m_parent_pid != 0)
|
||||
{
|
||||
parent = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_parent_pid);
|
||||
if (parent == 0 || parent == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
Log::warn("MainLoop", "Cannot open parent handle, this child "
|
||||
"may not be auto destroyed when parent is terminated");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
while(!m_abort)
|
||||
{
|
||||
#ifdef WIN32
|
||||
if (parent != 0 && parent != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
if (msg.message == WM_QUIT)
|
||||
m_abort = true;
|
||||
}
|
||||
// If parent is killed, abort the child main loop too
|
||||
if (WaitForSingleObject(parent, 0) != WAIT_TIMEOUT)
|
||||
m_abort = true;
|
||||
}
|
||||
#endif
|
||||
m_is_last_substep = false;
|
||||
PROFILER_PUSH_CPU_MARKER("Main loop", 0xFF, 0x00, 0xF7);
|
||||
|
||||
@@ -357,6 +411,11 @@ void MainLoop::run()
|
||||
PROFILER_SYNC_FRAME();
|
||||
} // while !m_abort
|
||||
|
||||
#ifdef WIN32
|
||||
if (parent != 0 && parent != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(parent);
|
||||
#endif
|
||||
|
||||
} // run
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -40,10 +40,11 @@ private:
|
||||
bool m_is_last_substep;
|
||||
Uint32 m_curr_time;
|
||||
Uint32 m_prev_time;
|
||||
unsigned m_parent_pid;
|
||||
float getLimitedDt();
|
||||
void updateRace(int ticks);
|
||||
public:
|
||||
MainLoop();
|
||||
MainLoop(unsigned parent_pid);
|
||||
~MainLoop();
|
||||
void run();
|
||||
void abort();
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "network/stk_host.hpp"
|
||||
#include "network/stk_peer.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/time.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@@ -65,11 +65,7 @@ Network::Network(int peer_count, int channel_limit,
|
||||
// Any port
|
||||
new_addr.port = 0;
|
||||
m_host = enet_host_create(&new_addr, peer_count, channel_limit, 0, 0);
|
||||
if (m_host)
|
||||
return;
|
||||
}
|
||||
Log::fatal("Network", "An error occurred while trying to create an ENet "
|
||||
"client host, maybe you started multiple instance of STK server?");
|
||||
} // Network
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "network/network_config.hpp"
|
||||
#include "config/stk_config.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "online/xml_request.hpp"
|
||||
|
||||
NetworkConfig *NetworkConfig::m_network_config = NULL;
|
||||
bool NetworkConfig::m_disable_lan = false;
|
||||
@@ -40,15 +43,24 @@ NetworkConfig::NetworkConfig()
|
||||
m_is_server = false;
|
||||
m_is_public_server = false;
|
||||
m_max_players = 4;
|
||||
m_is_registered = false;
|
||||
m_cur_user_id = 0;
|
||||
m_cur_user_token = "";
|
||||
m_server_name = "";
|
||||
m_password = "";
|
||||
m_server_discovery_port = 2757;
|
||||
m_server_port = 2758;
|
||||
m_client_port = 2759;
|
||||
m_server_discovery_port = stk_config->m_server_discovery_port;
|
||||
if (UserConfigParams::m_random_ports)
|
||||
{
|
||||
m_client_port = 0;
|
||||
m_server_port = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_client_port = stk_config->m_client_port;
|
||||
m_server_port = stk_config->m_server_port;
|
||||
}
|
||||
} // NetworkConfig
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets if this instance is a server or client. It also assigns the
|
||||
* private port depending if this is a server or client.
|
||||
*/
|
||||
@@ -56,3 +68,80 @@ void NetworkConfig::setIsServer(bool b)
|
||||
{
|
||||
m_is_server = b;
|
||||
} // setIsServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
unsigned NetworkConfig::getServerGameMode(RaceManager::MinorRaceModeType minor,
|
||||
RaceManager::MajorRaceModeType major)
|
||||
{
|
||||
if (major == RaceManager::MAJOR_MODE_GRAND_PRIX)
|
||||
{
|
||||
if (minor == RaceManager::MINOR_MODE_NORMAL_RACE)
|
||||
return 0;
|
||||
else if (minor == RaceManager::MINOR_MODE_TIME_TRIAL)
|
||||
return 1;
|
||||
else if (minor == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (minor == RaceManager::MINOR_MODE_NORMAL_RACE)
|
||||
return 3;
|
||||
else if (minor == RaceManager::MINOR_MODE_TIME_TRIAL)
|
||||
return 4;
|
||||
else if (minor == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
||||
return 5;
|
||||
else if (minor == RaceManager::MINOR_MODE_3_STRIKES)
|
||||
return 6;
|
||||
else if (minor == RaceManager::MINOR_MODE_SOCCER)
|
||||
return 7;
|
||||
}
|
||||
return 0;
|
||||
} // getServerGameMode
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
std::pair<RaceManager::MinorRaceModeType, RaceManager::MajorRaceModeType>
|
||||
NetworkConfig::getLocalGameMode(unsigned id)
|
||||
{
|
||||
switch(id)
|
||||
{
|
||||
case 0:
|
||||
return { RaceManager::MINOR_MODE_NORMAL_RACE,
|
||||
RaceManager::MAJOR_MODE_GRAND_PRIX };
|
||||
case 1:
|
||||
return { RaceManager::MINOR_MODE_TIME_TRIAL,
|
||||
RaceManager::MAJOR_MODE_GRAND_PRIX };
|
||||
case 2:
|
||||
return { RaceManager::MINOR_MODE_FOLLOW_LEADER,
|
||||
RaceManager::MAJOR_MODE_GRAND_PRIX };
|
||||
case 3:
|
||||
return { RaceManager::MINOR_MODE_NORMAL_RACE,
|
||||
RaceManager::MAJOR_MODE_SINGLE };
|
||||
case 4:
|
||||
return { RaceManager::MINOR_MODE_TIME_TRIAL,
|
||||
RaceManager::MAJOR_MODE_SINGLE };
|
||||
case 5:
|
||||
return { RaceManager::MINOR_MODE_FOLLOW_LEADER,
|
||||
RaceManager::MAJOR_MODE_SINGLE };
|
||||
case 6:
|
||||
return { RaceManager::MINOR_MODE_3_STRIKES,
|
||||
RaceManager::MAJOR_MODE_SINGLE };
|
||||
case 7:
|
||||
return { RaceManager::MINOR_MODE_SOCCER,
|
||||
RaceManager::MAJOR_MODE_SINGLE };
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return { RaceManager::MINOR_MODE_NORMAL_RACE,
|
||||
RaceManager::MAJOR_MODE_SINGLE };
|
||||
|
||||
} // getLocalGameMode
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkConfig::setUserDetails(Online::XMLRequest* r,
|
||||
const std::string& name)
|
||||
{
|
||||
assert(!m_cur_user_token.empty());
|
||||
r->setApiURL(Online::API::SERVER_PATH, name);
|
||||
r->addParameter("userid", m_cur_user_id);
|
||||
r->addParameter("token", m_cur_user_token);
|
||||
} // setUserDetails
|
||||
|
||||
@@ -23,10 +23,15 @@
|
||||
#define HEADER_NETWORK_CONFIG
|
||||
|
||||
#include "network/transport_address.hpp"
|
||||
#include "utils/synchronised.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
|
||||
#include "irrString.h"
|
||||
|
||||
namespace Online
|
||||
{
|
||||
class XMLRequest;
|
||||
}
|
||||
|
||||
class NetworkConfig
|
||||
{
|
||||
private:
|
||||
@@ -43,7 +48,9 @@ private:
|
||||
|
||||
/** If set it allows clients to connect directly to this server without
|
||||
* using the stk server in between. It requires obviously that this
|
||||
* server is accessible (through the firewall) from the outside. */
|
||||
* server is accessible (through the firewall) from the outside,
|
||||
* then you can use the \ref m_server_discovery_port and ip address for
|
||||
* direct connection. */
|
||||
bool m_is_public_server;
|
||||
|
||||
/** True if this host is a server, false otherwise. */
|
||||
@@ -52,7 +59,8 @@ private:
|
||||
/** The password for a server (or to authenticate to a server). */
|
||||
std::string m_password;
|
||||
|
||||
/** The port number to which the server listens to detect LAN requests. */
|
||||
/** The port number to which the server listens to detect direct socket
|
||||
* requests. */
|
||||
uint16_t m_server_discovery_port;
|
||||
|
||||
/** The port on which the server listens for connection requests from LAN. */
|
||||
@@ -64,10 +72,6 @@ private:
|
||||
/** Maximum number of players on the server. */
|
||||
int m_max_players;
|
||||
|
||||
/** If this is a server, it indicates if this server is registered
|
||||
* with the stk server. */
|
||||
bool m_is_registered;
|
||||
|
||||
/** True if a client should connect to the first server it finds and
|
||||
* immediately start a race. */
|
||||
bool m_auto_connect;
|
||||
@@ -75,6 +79,13 @@ private:
|
||||
/** If this is a server, the server name. */
|
||||
irr::core::stringw m_server_name;
|
||||
|
||||
/** Used by wan server. */
|
||||
uint32_t m_cur_user_id;
|
||||
std::string m_cur_user_token;
|
||||
|
||||
/** Used by client server to determine if the child server is created. */
|
||||
std::string m_server_id_file;
|
||||
|
||||
NetworkConfig();
|
||||
|
||||
public:
|
||||
@@ -154,35 +165,57 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the maximum number of players for this server. */
|
||||
void setMaxPlayers(int n) { m_max_players = n; }
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum number of players for this server. */
|
||||
int getMaxPlayers() const { return m_max_players; }
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if this instance is a server. */
|
||||
bool isServer() const { return m_is_server; }
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if this instance is a client. */
|
||||
bool isClient() const { return !m_is_server; }
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the name of this server. */
|
||||
void setServerName(const irr::core::stringw &name)
|
||||
{
|
||||
m_server_name = name;
|
||||
} // setServerName
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the server name. */
|
||||
const irr::core::stringw& getServerName() const
|
||||
{
|
||||
assert(isServer());
|
||||
return m_server_name;
|
||||
} // getServerName
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets if a client should immediately connect to the first server. */
|
||||
void setAutoConnect(bool b) { m_auto_connect = b; }
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns if an immediate connection to the first server was
|
||||
* requested. */
|
||||
bool isAutoConnect() const { return m_auto_connect; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the game mode id for server database. */
|
||||
unsigned getServerGameMode(RaceManager::MinorRaceModeType mode,
|
||||
RaceManager::MajorRaceModeType);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the minor and majar game mode from server database id. */
|
||||
std::pair<RaceManager::MinorRaceModeType, RaceManager::MajorRaceModeType>
|
||||
getLocalGameMode(unsigned);
|
||||
// ------------------------------------------------------------------------
|
||||
void setCurrentUserId(uint32_t id) { m_cur_user_id = id ; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setCurrentUserToken(const std::string& t) { m_cur_user_token = t; }
|
||||
// ------------------------------------------------------------------------
|
||||
uint32_t getCurrentUserId() const { return m_cur_user_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
const std::string& getCurrentUserToken() const { return m_cur_user_token; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setUserDetails(Online::XMLRequest* r, const std::string& name);
|
||||
// ------------------------------------------------------------------------
|
||||
void setServerIdFile(const std::string& id) { m_server_id_file = id; }
|
||||
// ------------------------------------------------------------------------
|
||||
const std::string& getServerIdFile() const { return m_server_id_file; }
|
||||
|
||||
}; // class NetworkConfig
|
||||
|
||||
|
||||
@@ -210,7 +210,6 @@ void ClientLobby::leave()
|
||||
m_server->disconnect();
|
||||
STKHost::get()->removePeer(m_server);
|
||||
m_server_address.clear();
|
||||
ServersManager::get()->unsetJoinedServer();
|
||||
} // leave
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include "network/protocols/connect_to_server.hpp"
|
||||
|
||||
#include "config/player_manager.hpp"
|
||||
#include "network/event.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/protocols/get_peer_address.hpp"
|
||||
@@ -27,37 +26,21 @@
|
||||
#include "network/protocols/client_lobby.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "network/stk_peer.hpp"
|
||||
#include "states_screens/networking_lobby.hpp"
|
||||
#include "utils/time.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Connects to a server. This is the quick connect constructor, which
|
||||
* will pick a server randomly.
|
||||
*/
|
||||
ConnectToServer::ConnectToServer() : Protocol(PROTOCOL_CONNECTION)
|
||||
{
|
||||
m_server_id = 0;
|
||||
m_host_id = 0;
|
||||
m_quick_join = true;
|
||||
m_server_address.clear();
|
||||
setHandleConnections(true);
|
||||
} // ConnectToServer()
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Specify server to connect to.
|
||||
* \param server_id Id of server to connect to.
|
||||
* \param host_id Id of host.
|
||||
* \param server Server to connect to (if nullptr than we use quick play).
|
||||
*/
|
||||
ConnectToServer::ConnectToServer(uint32_t server_id, uint32_t host_id)
|
||||
ConnectToServer::ConnectToServer(std::shared_ptr<Server> server)
|
||||
: Protocol(PROTOCOL_CONNECTION)
|
||||
{
|
||||
m_server_id = server_id;
|
||||
m_host_id = host_id;
|
||||
m_quick_join = false;
|
||||
m_server = ServersManager::get()->getServerByID(m_server_id);
|
||||
m_server_address.copy(m_server->getAddress());
|
||||
m_server = server;
|
||||
setHandleConnections(true);
|
||||
} // ConnectToServer(server, host)
|
||||
|
||||
@@ -75,10 +58,11 @@ void ConnectToServer::setup()
|
||||
{
|
||||
Log::info("ConnectToServer", "SETUP");
|
||||
m_current_protocol.reset();
|
||||
// In case of LAN we already have the server's and our ip address,
|
||||
// so we can immediately start requesting a connection.
|
||||
m_state = NetworkConfig::get()->isLAN() ? GOT_SERVER_ADDRESS :
|
||||
SET_PUBLIC_ADDRESS;
|
||||
// In case of LAN or client-server we already have the server's
|
||||
// and our ip address, so we can immediately start requesting a connection.
|
||||
m_state = (NetworkConfig::get()->isLAN() ||
|
||||
STKHost::get()->isClientServer()) ?
|
||||
GOT_SERVER_ADDRESS : SET_PUBLIC_ADDRESS;
|
||||
} // setup
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -88,6 +72,34 @@ void ConnectToServer::asynchronousUpdate()
|
||||
{
|
||||
case SET_PUBLIC_ADDRESS:
|
||||
{
|
||||
if (!m_server)
|
||||
{
|
||||
while (!ServersManager::get()->refresh())
|
||||
StkTime::sleep(1);
|
||||
while (!ServersManager::get()->listUpdated())
|
||||
StkTime::sleep(1);
|
||||
if (!ServersManager::get()->getServers().empty())
|
||||
{
|
||||
// For quick play we choose the server with the least player
|
||||
ServersManager::get()->sortServers([]
|
||||
(const std::shared_ptr<Server> a,
|
||||
const std::shared_ptr<Server> b)->bool
|
||||
{
|
||||
return a->getCurrentPlayers() < b->getCurrentPlayers();
|
||||
});
|
||||
m_server = ServersManager::get()->getServers()[0];
|
||||
ServersManager::get()->cleanUpServers();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shutdown STKHost (go back to online menu too)
|
||||
STKHost::get()->setErrorMessage(
|
||||
_("No quick play server available."));
|
||||
STKHost::get()->requestShutdown();
|
||||
m_state = EXITING;
|
||||
return;
|
||||
}
|
||||
}
|
||||
STKHost::get()->setPublicAddress();
|
||||
// Set to DONE will stop STKHost is not connected
|
||||
m_state = STKHost::get()->getPublicAddress().isUnset() ?
|
||||
@@ -97,26 +109,17 @@ void ConnectToServer::asynchronousUpdate()
|
||||
case REGISTER_SELF_ADDRESS:
|
||||
{
|
||||
registerWithSTKServer(); // Register us with STK server
|
||||
if (m_quick_join)
|
||||
{
|
||||
handleQuickConnect();
|
||||
// Quick connect will give us the server details,
|
||||
// so we can immediately try to connect to the server
|
||||
m_state = REQUESTING_CONNECTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state = GOT_SERVER_ADDRESS;
|
||||
}
|
||||
m_state = GOT_SERVER_ADDRESS;
|
||||
}
|
||||
break;
|
||||
case GOT_SERVER_ADDRESS:
|
||||
{
|
||||
assert(!m_quick_join);
|
||||
assert(m_server);
|
||||
m_server_address.copy(m_server->getAddress());
|
||||
Log::info("ConnectToServer", "Server's address known");
|
||||
m_state = REQUESTING_CONNECTION;
|
||||
auto request_connection =
|
||||
std::make_shared<RequestConnection>(m_server_id);
|
||||
std::make_shared<RequestConnection>(m_server);
|
||||
request_connection->requestStart();
|
||||
m_current_protocol = request_connection;
|
||||
// Reset timer for next usage
|
||||
@@ -124,6 +127,7 @@ void ConnectToServer::asynchronousUpdate()
|
||||
break;
|
||||
}
|
||||
case REQUESTING_CONNECTION:
|
||||
{
|
||||
if (!m_current_protocol.expired())
|
||||
{
|
||||
return;
|
||||
@@ -148,10 +152,11 @@ void ConnectToServer::asynchronousUpdate()
|
||||
m_state = NetworkConfig::get()->isWAN() ?
|
||||
HIDING_ADDRESS : DONE;
|
||||
}
|
||||
if ((!NetworkConfig::m_disable_lan &&
|
||||
if ((!NetworkConfig::m_disable_lan &&
|
||||
m_server_address.getIP() ==
|
||||
STKHost::get()->getPublicAddress().getIP()) ||
|
||||
NetworkConfig::get()->isLAN())
|
||||
(NetworkConfig::get()->isLAN() ||
|
||||
STKHost::get()->isClientServer()))
|
||||
{
|
||||
// We're in the same lan (same public ip address).
|
||||
// The state will change to CONNECTING
|
||||
@@ -171,6 +176,7 @@ void ConnectToServer::asynchronousUpdate()
|
||||
waitingAloha(true/*is_wan*/);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONNECTING: // waiting the server to answer our connection
|
||||
{
|
||||
// Every 5 seconds
|
||||
@@ -194,7 +200,8 @@ void ConnectToServer::asynchronousUpdate()
|
||||
{
|
||||
Log::info("ConnectToServer", "Connected");
|
||||
// LAN networking does not use the stk server tables.
|
||||
if (NetworkConfig::get()->isWAN())
|
||||
if (NetworkConfig::get()->isWAN() &&
|
||||
!STKHost::get()->isClientServer())
|
||||
{
|
||||
auto hide_address = std::make_shared<HidePublicAddress>();
|
||||
hide_address->requestStart();
|
||||
@@ -222,6 +229,12 @@ void ConnectToServer::update(int ticks)
|
||||
{
|
||||
switch(m_state.load())
|
||||
{
|
||||
case REQUESTING_CONNECTION:
|
||||
{
|
||||
assert(m_server);
|
||||
NetworkingLobby::getInstance()->setJoinedServer(m_server);
|
||||
break;
|
||||
}
|
||||
case DONE:
|
||||
{
|
||||
// lobby room protocol if we're connected only
|
||||
@@ -239,7 +252,7 @@ void ConnectToServer::update(int ticks)
|
||||
{
|
||||
// Shutdown STKHost (go back to online menu too)
|
||||
STKHost::get()->setErrorMessage(
|
||||
_("Cannot connect to server %s.", m_server->getName()));
|
||||
_("Cannot connect to server %s.", m_server->getName()));
|
||||
STKHost::get()->requestShutdown();
|
||||
}
|
||||
requestTerminate();
|
||||
@@ -260,8 +273,7 @@ void ConnectToServer::registerWithSTKServer()
|
||||
// STK server.
|
||||
const TransportAddress& addr = STKHost::get()->getPublicAddress();
|
||||
Online::XMLRequest *request = new Online::XMLRequest();
|
||||
PlayerManager::setUserDetails(request, "set",
|
||||
Online::API::SERVER_PATH);
|
||||
NetworkConfig::get()->setUserDetails(request, "set");
|
||||
request->addParameter("address", addr.getIP());
|
||||
request->addParameter("port", addr.getPort());
|
||||
request->addParameter("private_port", STKHost::get()->getPrivatePort());
|
||||
@@ -292,46 +304,6 @@ void ConnectToServer::registerWithSTKServer()
|
||||
|
||||
} // registerWithSTKServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called to request a quick connect from the STK server.
|
||||
*/
|
||||
void ConnectToServer::handleQuickConnect()
|
||||
{
|
||||
Online::XMLRequest *request = new Online::XMLRequest();
|
||||
PlayerManager::setUserDetails(request, "quick-join",
|
||||
Online::API::SERVER_PATH);
|
||||
request->executeNow();
|
||||
|
||||
const XMLNode * result = request->getXMLData();
|
||||
std::string success;
|
||||
|
||||
if(result->get("success", &success) && success=="yes")
|
||||
{
|
||||
uint32_t ip;
|
||||
result->get("ip", &ip);
|
||||
m_server_address.setIP(ip);
|
||||
|
||||
uint16_t port;
|
||||
// If we are using a LAN connection, we need the private (local) port
|
||||
if (m_server_address.getIP() ==
|
||||
STKHost::get()->getPublicAddress().getIP())
|
||||
{
|
||||
result->get("private_port", &port);
|
||||
}
|
||||
else
|
||||
result->get("port", &port);
|
||||
|
||||
m_server_address.setPort(port);
|
||||
|
||||
Log::debug("GetPeerAddress", "Address gotten successfully.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("GetPeerAddress", "Failed to get address.");
|
||||
}
|
||||
delete request;
|
||||
} // handleQuickConnect
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called when the server is on the same LAN. It uses broadcast to
|
||||
* find and conntect to the server. For WAN game, it makes sure server recieve
|
||||
@@ -369,7 +341,7 @@ void ConnectToServer::waitingAloha(bool is_wan)
|
||||
sender.toString().c_str());
|
||||
if (!is_wan)
|
||||
{
|
||||
if (sender.isPublicAddressLAN())
|
||||
if (sender.isPublicAddressLocalhost())
|
||||
sender.setIP(0x7f000001); // 127.0.0.1
|
||||
}
|
||||
m_server_address.copy(sender);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "network/transport_address.hpp"
|
||||
#include "utils/cpp2011.hpp"
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class Server;
|
||||
@@ -32,14 +33,11 @@ class ConnectToServer : public Protocol
|
||||
private:
|
||||
double m_timer = 0.0;
|
||||
TransportAddress m_server_address;
|
||||
uint32_t m_server_id;
|
||||
uint32_t m_host_id;
|
||||
std::shared_ptr<Server> m_server;
|
||||
unsigned m_tried_connection = 0;
|
||||
|
||||
const Server* m_server = NULL;
|
||||
/** Protocol currently being monitored. */
|
||||
std::weak_ptr<Protocol> m_current_protocol;
|
||||
bool m_quick_join;
|
||||
|
||||
/** State for finite state machine. */
|
||||
enum ConnectState : unsigned int
|
||||
@@ -57,12 +55,10 @@ private:
|
||||
std::atomic<ConnectState> m_state;
|
||||
|
||||
void registerWithSTKServer();
|
||||
void handleQuickConnect();
|
||||
void waitingAloha(bool is_wan);
|
||||
|
||||
public:
|
||||
ConnectToServer();
|
||||
ConnectToServer(uint32_t server_id, uint32_t host_id);
|
||||
ConnectToServer(std::shared_ptr<Server> server);
|
||||
virtual ~ConnectToServer();
|
||||
|
||||
virtual bool notifyEventAsynchronous(Event* event) OVERRIDE;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "network/stk_host.hpp"
|
||||
#include "network/stk_peer.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/time.hpp"
|
||||
|
||||
// ============================================================================
|
||||
std::weak_ptr<GameProtocol> GameProtocol::m_game_protocol;
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
#include "network/protocols/get_peer_address.hpp"
|
||||
|
||||
#include "config/player_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "online/request_manager.hpp"
|
||||
#include "online/xml_request.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
GetPeerAddress::GetPeerAddress(uint32_t peer_id)
|
||||
@@ -41,8 +41,7 @@ void GetPeerAddress::setup()
|
||||
{
|
||||
m_address.clear();
|
||||
m_request = new Online::XMLRequest();
|
||||
PlayerManager::setUserDetails(m_request, "get",
|
||||
Online::API::SERVER_PATH);
|
||||
NetworkConfig::get()->setUserDetails(m_request, "get");
|
||||
m_request->addParameter("peer_id", m_peer_id);
|
||||
|
||||
Online::RequestManager::get()->addRequest(m_request);
|
||||
@@ -63,11 +62,7 @@ void GetPeerAddress::asynchronousUpdate()
|
||||
m_address.setIP(ip);
|
||||
|
||||
uint16_t port;
|
||||
uint32_t my_ip = STKHost::get()->getPublicAddress().getIP();
|
||||
if (m_address.getIP() == my_ip && !NetworkConfig::m_disable_lan)
|
||||
result->get("private_port", &port);
|
||||
else
|
||||
result->get("port", &port);
|
||||
result->get("port", &port);
|
||||
m_address.setPort(port);
|
||||
|
||||
Log::debug("GetPeerAddress", "Peer address retrieved.");
|
||||
|
||||
@@ -18,10 +18,9 @@
|
||||
|
||||
#include "network/protocols/hide_public_address.hpp"
|
||||
|
||||
#include "config/player_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "online/request_manager.hpp"
|
||||
#include "online/xml_request.hpp"
|
||||
#include "utils/log.hpp"
|
||||
|
||||
HidePublicAddress::HidePublicAddress() : Protocol(PROTOCOL_SILENT)
|
||||
@@ -42,8 +41,7 @@ void HidePublicAddress::asynchronousUpdate()
|
||||
if (m_state == NONE)
|
||||
{
|
||||
m_request = new Online::XMLRequest();
|
||||
PlayerManager::setUserDetails(m_request, "unset", Online::API::SERVER_PATH);
|
||||
|
||||
NetworkConfig::get()->setUserDetails(m_request, "unset");
|
||||
Online::RequestManager::get()->addRequest(m_request);
|
||||
m_state = REQUEST_PENDING;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ LatencyProtocol::LatencyProtocol()
|
||||
m_total_diff.resize(size, 0);
|
||||
m_average_ping.resize(size, 0);
|
||||
m_pings_count = 0;
|
||||
m_last_time = 0.0;
|
||||
} // LatencyProtocol
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -18,24 +18,25 @@
|
||||
|
||||
#include "network/protocols/request_connection.hpp"
|
||||
|
||||
#include "config/player_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "network/network.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "online/xml_request.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
using namespace Online;
|
||||
|
||||
/** Constructor. Stores the server id.
|
||||
* \param server_id Id of the server.
|
||||
* \param server Server to be joined.
|
||||
*/
|
||||
RequestConnection::RequestConnection(uint32_t server_id)
|
||||
RequestConnection::RequestConnection(std::shared_ptr<Server> server)
|
||||
: Protocol(PROTOCOL_SILENT)
|
||||
{
|
||||
m_server_id = server_id;
|
||||
m_request = NULL;
|
||||
m_server = server;
|
||||
m_request = NULL;
|
||||
} // RequestConnection
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -51,20 +52,6 @@ void RequestConnection::setup()
|
||||
m_state = NONE;
|
||||
} // setup
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** The callback for the server join request. It informs the server manager
|
||||
* of a successful join request.
|
||||
*/
|
||||
void RequestConnection::ServerJoinRequest::callback()
|
||||
{
|
||||
if (isSuccess())
|
||||
{
|
||||
uint32_t server_id;
|
||||
getXMLData()->get("serverid", &server_id);
|
||||
ServersManager::get()->setJoinedServer(server_id);
|
||||
}
|
||||
} // ServerJoinRequest::callback
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This implements a finite state machine to monitor the server join
|
||||
* request asynchronously.
|
||||
@@ -75,21 +62,66 @@ void RequestConnection::asynchronousUpdate()
|
||||
{
|
||||
case NONE:
|
||||
{
|
||||
if(NetworkConfig::get()->isLAN())
|
||||
if ((!NetworkConfig::m_disable_lan &&
|
||||
m_server->getAddress().getIP() ==
|
||||
STKHost::get()->getPublicAddress().getIP()) ||
|
||||
(NetworkConfig::get()->isLAN() ||
|
||||
STKHost::get()->isClientServer()))
|
||||
{
|
||||
const Server *server =
|
||||
ServersManager::get()->getServerByID(m_server_id);
|
||||
BareNetworkString message(std::string("connection-request"));
|
||||
STKHost::get()->sendRawPacket(message, server->getAddress());
|
||||
if (NetworkConfig::get()->isWAN())
|
||||
{
|
||||
Log::info("RequestConnection",
|
||||
"LAN connection to WAN server will be used.");
|
||||
}
|
||||
if (STKHost::get()->isClientServer())
|
||||
{
|
||||
// Allow up to 10 seconds for the separate process to
|
||||
// fully start-up
|
||||
double timeout = StkTime::getRealTime() + 10.;
|
||||
while (StkTime::getRealTime() < timeout)
|
||||
{
|
||||
const std::string& sid = NetworkConfig::get()
|
||||
->getServerIdFile();
|
||||
assert(!sid.empty());
|
||||
if (file_manager->fileExists(sid))
|
||||
{
|
||||
file_manager->removeFile(sid);
|
||||
break;
|
||||
}
|
||||
StkTime::sleep(10);
|
||||
}
|
||||
NetworkConfig::get()->setServerIdFile("");
|
||||
}
|
||||
std::string str_msg("connection-request");
|
||||
BareNetworkString message(str_msg +
|
||||
(STKHost::get()->isClientServer() ? "-localhost" :
|
||||
StringUtils::toString(m_server->getPrivatePort())));
|
||||
|
||||
TransportAddress server_addr;
|
||||
if (!NetworkConfig::m_disable_lan &&
|
||||
m_server->getAddress().getIP() ==
|
||||
STKHost::get()->getPublicAddress().getIP() &&
|
||||
!STKHost::get()->isClientServer())
|
||||
{
|
||||
// If use lan connection in wan server, send a broadcast
|
||||
server_addr.setIP(0xffffffff);
|
||||
}
|
||||
else
|
||||
{
|
||||
server_addr.setIP(m_server->getAddress().getIP());
|
||||
}
|
||||
// Direct socket always listens on server discovery port
|
||||
server_addr.setPort(NetworkConfig::get()
|
||||
->getServerDiscoveryPort());
|
||||
STKHost::get()->sendRawPacket(message, server_addr);
|
||||
m_state = DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_request = new ServerJoinRequest();
|
||||
PlayerManager::setUserDetails(m_request, "request-connection",
|
||||
Online::API::SERVER_PATH);
|
||||
|
||||
m_request->addParameter("server_id", m_server_id);
|
||||
m_request = new Online::XMLRequest();
|
||||
NetworkConfig::get()->setUserDetails(m_request,
|
||||
"request-connection");
|
||||
m_request->addParameter("server_id", m_server->getServerId());
|
||||
m_request->queue();
|
||||
m_state = REQUEST_PENDING;
|
||||
}
|
||||
@@ -114,7 +146,7 @@ void RequestConnection::asynchronousUpdate()
|
||||
{
|
||||
Log::error("RequestConnection",
|
||||
"Fail to make a request to connecto to server %d",
|
||||
m_server_id);
|
||||
m_server->getServerId());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
#include "network/protocol.hpp"
|
||||
#include "online/xml_request.hpp"
|
||||
|
||||
#include <memory>
|
||||
class Server;
|
||||
|
||||
class RequestConnection : public Protocol
|
||||
{
|
||||
protected:
|
||||
/** Id of the server to join. */
|
||||
uint32_t m_server_id;
|
||||
std::shared_ptr<Server> m_server;
|
||||
|
||||
/** The request to join a server. */
|
||||
Online::XMLRequest *m_request;
|
||||
@@ -24,19 +27,8 @@ protected:
|
||||
STATE m_state;
|
||||
|
||||
public:
|
||||
// --------------------------------------------------------------------
|
||||
/** A simple request class to ask to join a server.
|
||||
*/
|
||||
class ServerJoinRequest : public Online::XMLRequest
|
||||
{
|
||||
virtual void callback();
|
||||
public:
|
||||
ServerJoinRequest() : Online::XMLRequest() {}
|
||||
}; // ServerJoinRequest
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
RequestConnection(uint32_t server_id);
|
||||
// ------------------------------------------------------------------------
|
||||
RequestConnection(std::shared_ptr<Server> server);
|
||||
virtual ~RequestConnection();
|
||||
virtual void setup() OVERRIDE;
|
||||
virtual void asynchronousUpdate() OVERRIDE;
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include "network/protocols/server_lobby.hpp"
|
||||
|
||||
#include "config/player_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
@@ -33,6 +32,7 @@
|
||||
#include "network/stk_peer.hpp"
|
||||
#include "online/online_profile.hpp"
|
||||
#include "online/request_manager.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "states_screens/networking_lobby.hpp"
|
||||
#include "states_screens/race_result_gui.hpp"
|
||||
#include "states_screens/waiting_for_others.hpp"
|
||||
@@ -41,6 +41,8 @@
|
||||
#include "utils/random_generator.hpp"
|
||||
#include "utils/time.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
/** This is the central game setup protocol running in the server. It is
|
||||
* mostly a finite state machine. Note that all nodes in ellipses and light
|
||||
* grey background are actual states; nodes in boxes and white background
|
||||
@@ -101,7 +103,7 @@ ServerLobby::ServerLobby() : LobbyProtocol(NULL)
|
||||
*/
|
||||
ServerLobby::~ServerLobby()
|
||||
{
|
||||
if (m_server_registered)
|
||||
if (m_server_registered && NetworkConfig::get()->isWAN())
|
||||
{
|
||||
unregisterServer();
|
||||
}
|
||||
@@ -190,6 +192,20 @@ bool ServerLobby::notifyEventAsynchronous(Event* event)
|
||||
return true;
|
||||
} // notifyEventAsynchronous
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Create the server id file to let the graphics server client connect. */
|
||||
void ServerLobby::createServerIdFile()
|
||||
{
|
||||
const std::string& sid = NetworkConfig::get()->getServerIdFile();
|
||||
if (!sid.empty())
|
||||
{
|
||||
std::fstream fs;
|
||||
fs.open(sid, std::ios::out);
|
||||
fs.close();
|
||||
NetworkConfig::get()->setServerIdFile("");
|
||||
}
|
||||
} // createServerIdFile
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Find out the public IP server or poll STK server asynchronously. */
|
||||
void ServerLobby::asynchronousUpdate()
|
||||
@@ -204,6 +220,7 @@ void ServerLobby::asynchronousUpdate()
|
||||
{
|
||||
m_state = ACCEPTING_CLIENTS;
|
||||
STKHost::get()->startListening();
|
||||
createServerIdFile();
|
||||
return;
|
||||
}
|
||||
STKHost::get()->setPublicAddress();
|
||||
@@ -224,7 +241,11 @@ void ServerLobby::asynchronousUpdate()
|
||||
// this thread, but there is no need for the protocol manager
|
||||
// to react to any requests before the server is registered.
|
||||
registerServer();
|
||||
m_state = ACCEPTING_CLIENTS;
|
||||
if (m_server_registered)
|
||||
{
|
||||
m_state = ACCEPTING_CLIENTS;
|
||||
createServerIdFile();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ACCEPTING_CLIENTS:
|
||||
@@ -349,16 +370,20 @@ void ServerLobby::registerServer()
|
||||
{
|
||||
Online::XMLRequest *request = new Online::XMLRequest();
|
||||
const TransportAddress& addr = STKHost::get()->getPublicAddress();
|
||||
PlayerManager::setUserDetails(request, "create", Online::API::SERVER_PATH);
|
||||
NetworkConfig::get()->setUserDetails(request, "create");
|
||||
request->addParameter("address", addr.getIP() );
|
||||
request->addParameter("port", addr.getPort() );
|
||||
request->addParameter("private_port",
|
||||
STKHost::get()->getPrivatePort() );
|
||||
request->addParameter("name", NetworkConfig::get()->getServerName() );
|
||||
request->addParameter("max_players",
|
||||
UserConfigParams::m_server_max_players );
|
||||
request->addParameter("max_players",
|
||||
NetworkConfig::get()->getMaxPlayers());
|
||||
request->addParameter("difficulty", race_manager->getDifficulty());
|
||||
request->addParameter("game_mode",
|
||||
NetworkConfig::get()->getServerGameMode(race_manager->getMinorMode(),
|
||||
race_manager->getMajorMode()));
|
||||
Log::info("ServerLobby", "Public server addr %s", addr.toString().c_str());
|
||||
|
||||
|
||||
request->executeNow();
|
||||
|
||||
const XMLNode * result = request->getXMLData();
|
||||
@@ -386,7 +411,7 @@ void ServerLobby::unregisterServer()
|
||||
{
|
||||
const TransportAddress &addr = STKHost::get()->getPublicAddress();
|
||||
Online::XMLRequest* request = new Online::XMLRequest();
|
||||
PlayerManager::setUserDetails(request, "stop", Online::API::SERVER_PATH);
|
||||
NetworkConfig::get()->setUserDetails(request, "stop");
|
||||
|
||||
request->addParameter("address", addr.getIP());
|
||||
request->addParameter("port", addr.getPort());
|
||||
@@ -439,9 +464,9 @@ void ServerLobby::signalRaceStartToClients()
|
||||
*/
|
||||
void ServerLobby::startSelection(const Event *event)
|
||||
{
|
||||
//assert(m_server_registered);
|
||||
if (m_server_registered)
|
||||
if (NetworkConfig::get()->isWAN())
|
||||
{
|
||||
assert(m_server_registered);
|
||||
unregisterServer();
|
||||
m_server_registered = false;
|
||||
}
|
||||
@@ -514,12 +539,12 @@ void ServerLobby::checkIncomingConnectionRequests()
|
||||
// Now poll the stk server
|
||||
last_poll_time = StkTime::getRealTime();
|
||||
Online::XMLRequest* request = new Online::XMLRequest();
|
||||
PlayerManager::setUserDetails(request, "poll-connection-requests",
|
||||
Online::API::SERVER_PATH);
|
||||
NetworkConfig::get()->setUserDetails(request, "poll-connection-requests");
|
||||
|
||||
const TransportAddress &addr = STKHost::get()->getPublicAddress();
|
||||
request->addParameter("address", addr.getIP() );
|
||||
request->addParameter("port", addr.getPort());
|
||||
request->addParameter("current_players", STKHost::get()->getPeerCount());
|
||||
|
||||
request->executeNow();
|
||||
assert(request->isDone());
|
||||
|
||||
@@ -83,6 +83,7 @@ private:
|
||||
void finishedLoadingWorldClient(Event *event);
|
||||
void startedRaceOnClient(Event *event);
|
||||
void unregisterServer();
|
||||
void createServerIdFile();
|
||||
public:
|
||||
ServerLobby();
|
||||
virtual ~ServerLobby();
|
||||
|
||||
@@ -16,19 +16,16 @@
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "network/server.hpp"
|
||||
|
||||
#include "network/network_config.hpp"
|
||||
#include "io/xml_node.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
Server::SortOrder Server::m_sort_order = Server::SO_NAME;
|
||||
|
||||
/** Constructor based on XML data received from the stk server.
|
||||
* \param xml The data for one server as received as part of the
|
||||
* get-all stk-server request.
|
||||
* \param is_lan If this is a lan only server.
|
||||
*/
|
||||
Server::Server(const XMLNode & xml, bool is_lan)
|
||||
Server::Server(const XMLNode& xml)
|
||||
{
|
||||
assert(xml.getName() == "server");
|
||||
|
||||
@@ -37,9 +34,12 @@ Server::Server(const XMLNode & xml, bool is_lan)
|
||||
m_server_id = 0;
|
||||
m_current_players = 0;
|
||||
m_max_players = 0;
|
||||
m_is_lan = is_lan;
|
||||
m_minor_mode = RaceManager::MINOR_MODE_NORMAL_RACE;
|
||||
m_difficulty = RaceManager::DIFFICULTY_HARD;
|
||||
unsigned server_data = 0;
|
||||
xml.get("game_mode", &server_data);
|
||||
m_minor_mode = NetworkConfig::get()->getLocalGameMode(server_data).first;
|
||||
m_major_mode = NetworkConfig::get()->getLocalGameMode(server_data).second;
|
||||
xml.get("difficulty", &server_data);
|
||||
m_difficulty = (RaceManager::Difficulty)server_data;
|
||||
|
||||
xml.get("name", &m_lower_case_name);
|
||||
m_name = StringUtils::xmlDecode(m_lower_case_name);
|
||||
@@ -60,29 +60,34 @@ Server::Server(const XMLNode & xml, bool is_lan)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Manual server creation, based on data received from a LAN server discovery
|
||||
* (see ServersManager::getLANRefresh). This constructor is only used for
|
||||
* LAN servers.
|
||||
* (see ServersManager::getLANRefresh) or local graphics server creation
|
||||
* where the server info is known already.
|
||||
* \param server_id ID of server.
|
||||
* \param name Name of the server.
|
||||
* \param is_lan If this is a lan-only server.
|
||||
* \param max_players Maximum number of players allowed on this server.
|
||||
* \param current_players The currently connected number of players.
|
||||
* \param difficulty The difficulty of server.
|
||||
* \param server_mode The game modes of server (including minor and major).
|
||||
* \param address IP and port of the server.
|
||||
*/
|
||||
Server::Server(const core::stringw &name, bool is_lan, int max_players,
|
||||
int current_players, const TransportAddress &address)
|
||||
Server::Server(unsigned server_id, const core::stringw &name, int max_players,
|
||||
int current_players, unsigned difficulty, unsigned server_mode,
|
||||
const TransportAddress &address)
|
||||
{
|
||||
m_name = name;
|
||||
m_lower_case_name = StringUtils::toLowerCase(StringUtils::wideToUtf8(name));
|
||||
m_satisfaction_score = 0;
|
||||
m_server_id = 0;
|
||||
m_server_id = server_id;
|
||||
m_host_id = 0;
|
||||
m_current_players = current_players;
|
||||
m_max_players = max_players;
|
||||
m_is_lan = is_lan;
|
||||
m_address.copy(address);
|
||||
// In case of LAN server, public and private port are the same.
|
||||
m_private_port = m_address.getPort();
|
||||
m_minor_mode = RaceManager::MINOR_MODE_NORMAL_RACE;
|
||||
m_difficulty = RaceManager::DIFFICULTY_HARD;
|
||||
|
||||
} // server(name, ...)
|
||||
m_difficulty = (RaceManager::Difficulty)difficulty;
|
||||
m_minor_mode = NetworkConfig::get()->getLocalGameMode(server_mode).first;
|
||||
m_major_mode = NetworkConfig::get()->getLocalGameMode(server_mode).second;
|
||||
} // server(server_id, ...)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** \brief Filter the add-on with a list of words.
|
||||
|
||||
@@ -41,14 +41,6 @@ class Server
|
||||
{
|
||||
public:
|
||||
|
||||
/** Set the sort order used in the comparison function. */
|
||||
enum SortOrder
|
||||
{
|
||||
SO_SCORE = 1, // Sorted on satisfaction score
|
||||
SO_NAME = 2, // Sorted alphabetically by name
|
||||
SO_PLAYERS = 4
|
||||
};
|
||||
|
||||
protected:
|
||||
/** The server name to be displayed. */
|
||||
irr::core::stringw m_name;
|
||||
@@ -68,39 +60,34 @@ protected:
|
||||
/** The score/rating given */
|
||||
float m_satisfaction_score;
|
||||
|
||||
/** True if this server is on the LAN, false otherwise. */
|
||||
bool m_is_lan;
|
||||
|
||||
/** The public ip address and port of this server. */
|
||||
TransportAddress m_address;
|
||||
|
||||
/** This is the private port of the server. This is used if a WAN game
|
||||
* is started, but one client is discovered on the same LAN, so a direct
|
||||
* connection using the private port is possible. */
|
||||
* connection using the private port with a broadcast is possible. */
|
||||
uint16_t m_private_port;
|
||||
|
||||
RaceManager::MinorRaceModeType m_minor_mode;
|
||||
|
||||
RaceManager::Difficulty m_difficulty;
|
||||
RaceManager::MajorRaceModeType m_major_mode;
|
||||
|
||||
/** The sort order to be used in the comparison. */
|
||||
static SortOrder m_sort_order;
|
||||
RaceManager::Difficulty m_difficulty;
|
||||
|
||||
public:
|
||||
|
||||
/** Initialises the object from an XML node. */
|
||||
Server(const XMLNode &xml, bool is_lan);
|
||||
Server(const irr::core::stringw &name, bool is_lan, int max_players,
|
||||
int current_players, const TransportAddress &address);
|
||||
Server(const XMLNode &xml);
|
||||
Server(unsigned server_id, const irr::core::stringw &name,
|
||||
int max_players, int current_players, unsigned difficulty,
|
||||
unsigned server_mode, const TransportAddress &address);
|
||||
bool filterByWords(const irr::core::stringw words) const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns ip address and port of this server. */
|
||||
const TransportAddress& getAddress() const { return m_address; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the sort order used in the comparison function. It is static, so
|
||||
* that each instance can access the sort order. */
|
||||
static void setSortOrder(SortOrder so) { m_sort_order = so; }
|
||||
|
||||
/** Returns the lower case name of the server. */
|
||||
const std::string& getLowerCaseName() const { return m_lower_case_name; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the name of the server. */
|
||||
const irr::core::stringw& getName() const { return m_name; }
|
||||
@@ -108,44 +95,26 @@ public:
|
||||
/** Returns the ID of this server. */
|
||||
const uint32_t getServerId() const { return m_server_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the unique host id of this server. */
|
||||
/** Returns the unique host id of this server (wan game only), which is
|
||||
* the user id in STK addon server of the server owner. */
|
||||
const uint32_t getHostId() const { return m_host_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
uint16_t getPrivatePort() const { return m_private_port; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the maximum number of players allowed on this server. */
|
||||
const int getMaxPlayers() const { return m_max_players; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of currently connected players. */
|
||||
const int getCurrentPlayers() const { return m_current_players; }
|
||||
// ------------------------------------------------------------------------
|
||||
RaceManager::MinorRaceModeType getRaceMinorMode() const { return m_minor_mode; }
|
||||
RaceManager::MinorRaceModeType getRaceMinorMode() const
|
||||
{ return m_minor_mode; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setRaceMinorMode(RaceManager::MinorRaceModeType m) { m_minor_mode = m; }
|
||||
RaceManager::MajorRaceModeType getRaceMajorMode() const
|
||||
{ return m_major_mode; }
|
||||
// ------------------------------------------------------------------------
|
||||
RaceManager::Difficulty getDifficulty() const { return m_difficulty; }
|
||||
// ------------------------------------------------------------------------
|
||||
void setDifficulty(RaceManager::Difficulty d) { m_difficulty = d; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Compares two servers according to the sort order currently defined.
|
||||
* \param a The addon to compare this addon to.
|
||||
*/
|
||||
bool operator<(const Server &server) const
|
||||
{
|
||||
switch (m_sort_order)
|
||||
{
|
||||
case SO_SCORE:
|
||||
return m_satisfaction_score < server.m_satisfaction_score;
|
||||
break;
|
||||
case SO_NAME:
|
||||
// m_id is the lower case name
|
||||
return m_lower_case_name < server.m_lower_case_name;
|
||||
break;
|
||||
case SO_PLAYERS:
|
||||
return m_current_players < server.m_current_players;
|
||||
break;
|
||||
} // switch
|
||||
RaceManager::Difficulty getDifficulty() const { return m_difficulty; }
|
||||
|
||||
return true;
|
||||
} // operator<
|
||||
|
||||
}; // Server
|
||||
#endif // HEADER_SERVER_HPP
|
||||
|
||||
@@ -22,8 +22,10 @@
|
||||
#include "network/network.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_string.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "online/xml_request.hpp"
|
||||
#include "online/request_manager.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
#include "utils/time.hpp"
|
||||
|
||||
@@ -33,59 +35,36 @@
|
||||
|
||||
#define SERVER_REFRESH_INTERVAL 5.0f
|
||||
|
||||
static ServersManager* manager_singleton(NULL);
|
||||
static ServersManager* g_manager_singleton(NULL);
|
||||
|
||||
// ============================================================================
|
||||
ServersManager* ServersManager::get()
|
||||
{
|
||||
if (manager_singleton == NULL)
|
||||
manager_singleton = new ServersManager();
|
||||
if (g_manager_singleton == NULL)
|
||||
g_manager_singleton = new ServersManager();
|
||||
|
||||
return manager_singleton;
|
||||
return g_manager_singleton;
|
||||
} // get
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// ============================================================================
|
||||
void ServersManager::deallocate()
|
||||
{
|
||||
delete manager_singleton;
|
||||
manager_singleton = NULL;
|
||||
delete g_manager_singleton;
|
||||
g_manager_singleton = NULL;
|
||||
} // deallocate
|
||||
|
||||
// ===========================================================-=============
|
||||
// ----------------------------------------------------------------------------
|
||||
ServersManager::ServersManager()
|
||||
{
|
||||
m_last_load_time.setAtomic(0.0f);
|
||||
m_joined_server.setAtomic(NULL);
|
||||
m_last_load_time.store(0.0f);
|
||||
m_list_updated = false;
|
||||
} // ServersManager
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------
|
||||
ServersManager::~ServersManager()
|
||||
{
|
||||
cleanUpServers();
|
||||
} // ~ServersManager
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Removes all stored server information. After this call the list of
|
||||
* servers can be refreshed.
|
||||
*/
|
||||
void ServersManager::cleanUpServers()
|
||||
{
|
||||
if(m_joined_server.getAtomic()!=NULL)
|
||||
{
|
||||
// m_joinsed_server is a pointer into the m_server structure,
|
||||
// we can not modify this data structure while this pointer exists.
|
||||
Log::warn("ServersManager", "Server cleanUp while being already "
|
||||
"connected to a server.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_sorted_servers.lock();
|
||||
m_sorted_servers.getData().clearAndDeleteAll();
|
||||
m_sorted_servers.unlock();
|
||||
m_mapped_servers.lock();
|
||||
m_mapped_servers.getData().clear();
|
||||
m_mapped_servers.unlock();
|
||||
} // cleanUpServers
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns a WAN update-list-of-servers request. It queries the
|
||||
* STK server for an up-to-date list of servers.
|
||||
@@ -98,12 +77,13 @@ Online::XMLRequest* ServersManager::getWANRefreshRequest() const
|
||||
class WANRefreshRequest : public Online::XMLRequest
|
||||
{
|
||||
public:
|
||||
WANRefreshRequest() : Online::XMLRequest(/*manage_memory*/false,
|
||||
WANRefreshRequest() : Online::XMLRequest(/*manage_memory*/true,
|
||||
/*priority*/100) {}
|
||||
// --------------------------------------------------------------------
|
||||
virtual void callback()
|
||||
virtual void afterOperation() OVERRIDE
|
||||
{
|
||||
ServersManager::get()->refresh(isSuccess(), getXMLData());
|
||||
Online::XMLRequest::afterOperation();
|
||||
ServersManager::get()->setWanServers(isSuccess(), getXMLData());
|
||||
} // callback
|
||||
// --------------------------------------------------------------------
|
||||
}; // RefreshRequest
|
||||
@@ -132,7 +112,7 @@ Online::XMLRequest* ServersManager::getLANRefreshRequest() const
|
||||
public:
|
||||
|
||||
/** High priority for this request. */
|
||||
LANRefreshRequest() : XMLRequest(false, 100) {m_success = false;}
|
||||
LANRefreshRequest() : XMLRequest(true, 100) {m_success = false;}
|
||||
// --------------------------------------------------------------------
|
||||
virtual ~LANRefreshRequest() {}
|
||||
// --------------------------------------------------------------------
|
||||
@@ -169,34 +149,34 @@ Online::XMLRequest* ServersManager::getLANRefreshRequest() const
|
||||
// any local servers.
|
||||
double start_time = StkTime::getRealTime();
|
||||
const double DURATION = 1.0;
|
||||
while(StkTime::getRealTime() - start_time < DURATION)
|
||||
const auto& servers = ServersManager::get()->getServers();
|
||||
int cur_server_id = servers.size();
|
||||
assert(cur_server_id == 0);
|
||||
std::vector<std::shared_ptr<Server> > servers_now;
|
||||
while (StkTime::getRealTime() - start_time < DURATION)
|
||||
{
|
||||
TransportAddress sender;
|
||||
int len = broadcast->receiveRawPacket(buffer, LEN, &sender, 1);
|
||||
if(len>0)
|
||||
if (len > 0)
|
||||
{
|
||||
BareNetworkString s(buffer, len);
|
||||
irr::core::stringw name;
|
||||
// bytes_read is the number of bytes read
|
||||
uint8_t bytes_read = s.decodeStringW(&name);
|
||||
s.decodeStringW(&name);
|
||||
uint8_t max_players = s.getUInt8();
|
||||
uint8_t players = s.getUInt8();
|
||||
uint32_t my_ip = s.getUInt32();
|
||||
uint16_t my_port = s.getUInt16();
|
||||
uint16_t mode = s.getUInt16();
|
||||
uint16_t port = s.getUInt16();
|
||||
uint8_t difficulty = s.getUInt8();
|
||||
Server* server = new Server(name, /*lan*/true,
|
||||
max_players, players, sender);
|
||||
server->setDifficulty((RaceManager::Difficulty)difficulty);
|
||||
server->setRaceMinorMode((RaceManager::MinorRaceModeType)mode);
|
||||
ServersManager::get()->addServer(server);
|
||||
m_success = true;
|
||||
uint8_t mode = s.getUInt8();
|
||||
sender.setPort(port);
|
||||
servers_now.emplace_back(std::make_shared<Server>
|
||||
(cur_server_id++, name, max_players, players,
|
||||
difficulty, mode, sender));
|
||||
} // if received_data
|
||||
} // while still waiting
|
||||
|
||||
m_success = true;
|
||||
ServersManager::get()->setLanServers(servers_now);
|
||||
delete broadcast;
|
||||
if (!m_success)
|
||||
m_info = _("No LAN server detected");
|
||||
} // operation
|
||||
// --------------------------------------------------------------------
|
||||
/** This function is necessary, otherwise the XML- and HTTP-Request
|
||||
@@ -212,133 +192,46 @@ Online::XMLRequest* ServersManager::getLANRefreshRequest() const
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Factory function to create either a LAN or a WAN update-of-server
|
||||
* requests. The current list of servers is also cleared/
|
||||
* requests. The current list of servers is also cleared.
|
||||
*/
|
||||
Online::XMLRequest* ServersManager::getRefreshRequest(bool request_now)
|
||||
bool ServersManager::refresh()
|
||||
{
|
||||
if (StkTime::getRealTime() - m_last_load_time.getAtomic()
|
||||
if (StkTime::getRealTime() - m_last_load_time.load()
|
||||
< SERVER_REFRESH_INTERVAL)
|
||||
{
|
||||
// Avoid too frequent refreshing
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(m_joined_server.getAtomic()!=NULL)
|
||||
{
|
||||
// m_joinsed_server is a pointer into the m_server structure,
|
||||
// we can not modify this data structure while this pointer exists.
|
||||
Log::warn("ServersManager", "Server refresh while being already "
|
||||
"connected to a server.");
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
cleanUpServers();
|
||||
Online::XMLRequest *request =
|
||||
NetworkConfig::get()->isWAN() ? getWANRefreshRequest()
|
||||
: getLANRefreshRequest();
|
||||
|
||||
if (request_now)
|
||||
Online::RequestManager::get()->addRequest(request);
|
||||
|
||||
return request;
|
||||
} // getRefreshRequest
|
||||
m_list_updated = false;
|
||||
if (NetworkConfig::get()->isWAN())
|
||||
Online::RequestManager::get()->addRequest(getWANRefreshRequest());
|
||||
else
|
||||
Online::RequestManager::get()->addRequest(getLANRefreshRequest());
|
||||
return true;
|
||||
} // refresh
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Callback from the refresh request.
|
||||
/** Callback from the refresh request for wan servers.
|
||||
* \param success If the refresh was successful.
|
||||
* \param input The XML data describing the server.
|
||||
*/
|
||||
void ServersManager::refresh(bool success, const XMLNode *input)
|
||||
void ServersManager::setWanServers(bool success, const XMLNode* input)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
Log::error("Server Manager", "Could not refresh server list");
|
||||
m_list_updated = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const XMLNode *servers_xml = input->getNode("servers");
|
||||
for (unsigned int i = 0; i < servers_xml->getNumNodes(); i++)
|
||||
{
|
||||
addServer(new Server(*servers_xml->getNode(i), /*is_lan*/false));
|
||||
m_servers.emplace_back(
|
||||
std::make_shared<Server>(*servers_xml->getNode(i)));
|
||||
}
|
||||
m_last_load_time.setAtomic((float)StkTime::getRealTime());
|
||||
m_last_load_time.store((float)StkTime::getRealTime());
|
||||
m_list_updated = true;
|
||||
} // refresh
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
const Server* ServersManager::getQuickPlay() const
|
||||
{
|
||||
if (m_sorted_servers.getData().size() > 0)
|
||||
return getServerBySort(0);
|
||||
|
||||
return NULL;
|
||||
} // getQuickPlay
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets a pointer to the server to which this client is connected. From now
|
||||
* on the list of servers must not be modified (else this pointer might
|
||||
* become invalid).
|
||||
*/
|
||||
void ServersManager::setJoinedServer(uint32_t id)
|
||||
{
|
||||
MutexLocker(m_mapped_servers);
|
||||
m_joined_server.getData() = m_mapped_servers.getData().at(id);
|
||||
} // setJoinedServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Unsets the server to which this client is connected.
|
||||
*/
|
||||
void ServersManager::unsetJoinedServer()
|
||||
{
|
||||
MutexLocker(m_joined_server);
|
||||
m_joined_server.getData() = NULL;
|
||||
} // unsetJoinedServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Adds a server to the list of known servers.
|
||||
* \param server The server to add.
|
||||
*/
|
||||
void ServersManager::addServer(Server *server)
|
||||
{
|
||||
m_sorted_servers.lock();
|
||||
m_sorted_servers.getData().push_back(server);
|
||||
m_sorted_servers.unlock();
|
||||
|
||||
m_mapped_servers.lock();
|
||||
m_mapped_servers.getData()[server->getServerId()] = server;
|
||||
m_mapped_servers.unlock();
|
||||
} // addServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
int ServersManager::getNumServers() const
|
||||
{
|
||||
MutexLocker(m_sorted_servers);
|
||||
return m_sorted_servers.getData().size();
|
||||
} // getNumServers
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
const Server* ServersManager::getServerBySort(int index) const
|
||||
{
|
||||
MutexLocker(m_sorted_servers);
|
||||
return m_sorted_servers.getData().get(index);
|
||||
} // getServerBySort
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
const Server* ServersManager::getServerByID(uint32_t id) const
|
||||
{
|
||||
MutexLocker(m_mapped_servers);
|
||||
return m_mapped_servers.getData().at(id);
|
||||
} // getServerByID
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
Server* ServersManager::getJoinedServer() const
|
||||
{
|
||||
return m_joined_server.getAtomic();
|
||||
} // getJoinedServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void ServersManager::sort(bool sort_desc)
|
||||
{
|
||||
MutexLocker(m_sorted_servers);
|
||||
m_sorted_servers.getData().insertionSort(0, sort_desc);
|
||||
} // sort
|
||||
|
||||
|
||||
@@ -19,13 +19,17 @@
|
||||
#ifndef HEADER_SERVERS_MANAGER_HPP
|
||||
#define HEADER_SERVERS_MANAGER_HPP
|
||||
|
||||
#include "online/request_manager.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "utils/ptr_vector.hpp"
|
||||
#include "utils/synchronised.hpp"
|
||||
#include "utils/types.hpp"
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Online { class XMLRequest; }
|
||||
class Server;
|
||||
class XMLNode;
|
||||
|
||||
/**
|
||||
* \brief
|
||||
@@ -34,41 +38,51 @@ namespace Online { class XMLRequest; }
|
||||
class ServersManager
|
||||
{
|
||||
private:
|
||||
/** List of servers */
|
||||
std::vector<std::shared_ptr<Server> > m_servers;
|
||||
|
||||
std::atomic<float> m_last_load_time;
|
||||
|
||||
std::atomic_bool m_list_updated;
|
||||
// ------------------------------------------------------------------------
|
||||
ServersManager();
|
||||
// ------------------------------------------------------------------------
|
||||
~ServersManager();
|
||||
|
||||
/** Sorted vector of servers */
|
||||
Synchronised<PtrVector<Server> > m_sorted_servers;
|
||||
|
||||
/** Maps server id's to the same servers*/
|
||||
Synchronised<std::map<uint32_t, Server*> > m_mapped_servers;
|
||||
|
||||
/** This is a pointer to a copy of the server, the moment it got joined */
|
||||
Synchronised<Server *> m_joined_server;
|
||||
|
||||
Synchronised<float> m_last_load_time;
|
||||
void refresh(bool success, const XMLNode * input);
|
||||
void cleanUpServers();
|
||||
Online::XMLRequest * getWANRefreshRequest() const;
|
||||
Online::XMLRequest * getLANRefreshRequest() const;
|
||||
// ------------------------------------------------------------------------
|
||||
void setWanServers(bool success, const XMLNode* input);
|
||||
// ------------------------------------------------------------------------
|
||||
void setLanServers(std::vector<std::shared_ptr<Server> >& servers)
|
||||
{
|
||||
m_servers = std::move(servers);
|
||||
m_list_updated = true;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
Online::XMLRequest* getWANRefreshRequest() const;
|
||||
// ------------------------------------------------------------------------
|
||||
Online::XMLRequest* getLANRefreshRequest() const;
|
||||
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
// Singleton
|
||||
static ServersManager* get();
|
||||
static void deallocate();
|
||||
|
||||
Online::XMLRequest * getRefreshRequest(bool request_now = true);
|
||||
void setJoinedServer(uint32_t server_id);
|
||||
void unsetJoinedServer();
|
||||
void addServer(Server * server);
|
||||
int getNumServers() const;
|
||||
const Server * getServerByID(uint32_t server_id) const;
|
||||
const Server * getServerBySort(int index) const;
|
||||
void sort(bool sort_desc);
|
||||
Server * getJoinedServer() const;
|
||||
|
||||
// Returns the best server to join
|
||||
const Server * getQuickPlay() const;
|
||||
static ServersManager* get();
|
||||
// ------------------------------------------------------------------------
|
||||
static void deallocate();
|
||||
// ------------------------------------------------------------------------
|
||||
void cleanUpServers() { m_servers.clear(); }
|
||||
// ------------------------------------------------------------------------
|
||||
void sortServers(std::function<bool(const std::shared_ptr<Server> a,
|
||||
const std::shared_ptr<Server> b)> sorting_function)
|
||||
{
|
||||
assert(m_list_updated);
|
||||
std::sort(m_servers.begin(), m_servers.end(), sorting_function);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
bool refresh();
|
||||
// ------------------------------------------------------------------------
|
||||
const std::vector<std::shared_ptr<Server> >& getServers() const
|
||||
{ return m_servers; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool listUpdated() const { return m_list_updated; }
|
||||
|
||||
}; // class ServersManager
|
||||
#endif // HEADER_SERVERS_MANAGER_HPP
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
#include "network/protocols/connect_to_server.hpp"
|
||||
#include "network/protocols/server_lobby.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "network/stk_peer.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/separate_process.hpp"
|
||||
#include "utils/time.hpp"
|
||||
#include "utils/vs.hpp"
|
||||
|
||||
@@ -65,16 +65,16 @@
|
||||
STKHost *STKHost::m_stk_host = NULL;
|
||||
bool STKHost::m_enable_console = false;
|
||||
|
||||
void STKHost::create()
|
||||
void STKHost::create(std::shared_ptr<Server> server, SeparateProcess* p)
|
||||
{
|
||||
assert(m_stk_host == NULL);
|
||||
if (NetworkConfig::get()->isServer())
|
||||
m_stk_host = new STKHost(NetworkConfig::get()->getServerName());
|
||||
else
|
||||
{
|
||||
Server *server = ServersManager::get()->getJoinedServer();
|
||||
m_stk_host = new STKHost(server->getServerId(), 0);
|
||||
m_stk_host = new STKHost(server);
|
||||
}
|
||||
m_stk_host->m_separate_process = p;
|
||||
if (!m_stk_host->m_network)
|
||||
{
|
||||
delete m_stk_host;
|
||||
@@ -254,7 +254,7 @@ void STKHost::create()
|
||||
// ============================================================================
|
||||
/** Constructor for a client
|
||||
*/
|
||||
STKHost::STKHost(uint32_t server_id, uint32_t host_id)
|
||||
STKHost::STKHost(std::shared_ptr<Server> server)
|
||||
{
|
||||
m_next_unique_host_id = -1;
|
||||
// Will be overwritten with the correct value once a connection with the
|
||||
@@ -264,7 +264,7 @@ STKHost::STKHost(uint32_t server_id, uint32_t host_id)
|
||||
|
||||
ENetAddress ea;
|
||||
ea.host = STKHost::HOST_ANY;
|
||||
ea.port = NetworkConfig::get()->getClientPort();
|
||||
ea.port = NetworkConfig::get()->getClientPort();
|
||||
|
||||
m_network = new Network(/*peer_count*/1, /*channel_limit*/2,
|
||||
/*max_in_bandwidth*/0, /*max_out_bandwidth*/0,
|
||||
@@ -276,7 +276,7 @@ STKHost::STKHost(uint32_t server_id, uint32_t host_id)
|
||||
}
|
||||
|
||||
setPrivatePort();
|
||||
std::make_shared<ConnectToServer>(server_id, host_id)->requestStart();
|
||||
std::make_shared<ConnectToServer>(server)->requestStart();
|
||||
} // STKHost
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -371,6 +371,17 @@ STKHost::~STKHost()
|
||||
|
||||
delete m_network;
|
||||
enet_deinitialize();
|
||||
delete m_separate_process;
|
||||
// Always clean up server id file in case client failed to connect
|
||||
const std::string& sid = NetworkConfig::get()->getServerIdFile();
|
||||
if (!sid.empty())
|
||||
{
|
||||
if (file_manager->fileExists(sid))
|
||||
{
|
||||
file_manager->removeFile(sid);
|
||||
}
|
||||
NetworkConfig::get()->setServerIdFile("");
|
||||
}
|
||||
} // ~STKHost
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -379,7 +390,6 @@ STKHost::~STKHost()
|
||||
*/
|
||||
void STKHost::shutdown()
|
||||
{
|
||||
ServersManager::get()->unsetJoinedServer();
|
||||
ProtocolManager::lock()->abort();
|
||||
deleteAllPeers();
|
||||
destroy();
|
||||
@@ -503,12 +513,11 @@ void STKHost::setPublicAddress()
|
||||
|
||||
// The stun message is valid, so we parse it now:
|
||||
// Those are the port and the address to be detected
|
||||
bool found = false;
|
||||
TransportAddress non_xor_addr, xor_addr;
|
||||
while (true)
|
||||
{
|
||||
if (response.size() < 4)
|
||||
{
|
||||
Log::error("STKHost", "STUN response is invalid.");
|
||||
break;
|
||||
}
|
||||
unsigned type = response.getUInt16();
|
||||
@@ -555,11 +564,14 @@ void STKHost::setPublicAddress()
|
||||
// Obfuscation is described in Section 15.2 of RFC 5389.
|
||||
port ^= magic_cookie >> 16;
|
||||
ip ^= magic_cookie;
|
||||
xor_addr.setPort(port);
|
||||
xor_addr.setIP(ip);
|
||||
}
|
||||
else
|
||||
{
|
||||
non_xor_addr.setPort(port);
|
||||
non_xor_addr.setIP(ip);
|
||||
}
|
||||
m_public_address.setPort(port);
|
||||
m_public_address.setIP(ip);
|
||||
found = true;
|
||||
break;
|
||||
} // type == mapped_address || type == xor_mapped_address
|
||||
else
|
||||
{
|
||||
@@ -570,8 +582,23 @@ void STKHost::setPublicAddress()
|
||||
}
|
||||
} // while true
|
||||
// Found public address and port
|
||||
if (found)
|
||||
if (!xor_addr.isUnset() || !non_xor_addr.isUnset())
|
||||
{
|
||||
// Use XOR mapped address when possible to avoid translation of
|
||||
// the packet content by application layer gateways (ALGs) that
|
||||
// perform deep packet inspection in an attempt to perform
|
||||
// alternate NAT traversal methods.
|
||||
if (!xor_addr.isUnset())
|
||||
{
|
||||
m_public_address.copy(xor_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::warn("STKHost", "Only non xor-mapped address returned.");
|
||||
m_public_address.copy(non_xor_addr);
|
||||
}
|
||||
untried_server.clear();
|
||||
}
|
||||
}
|
||||
} // setPublicAddress
|
||||
|
||||
@@ -716,21 +743,29 @@ void STKHost::mainLoop()
|
||||
ENetHost* host = m_network->getENetHost();
|
||||
|
||||
// A separate network connection (socket) to handle LAN requests.
|
||||
Network* lan_network = NULL;
|
||||
if (NetworkConfig::get()->isLAN() && NetworkConfig::get()->isServer())
|
||||
Network* direct_socket = NULL;
|
||||
if ((NetworkConfig::get()->isLAN() && NetworkConfig::get()->isServer()) ||
|
||||
NetworkConfig::get()->isPublicServer())
|
||||
{
|
||||
TransportAddress address(0,
|
||||
NetworkConfig::get()->getServerDiscoveryPort());
|
||||
ENetAddress eaddr = address.toEnetAddress();
|
||||
lan_network = new Network(1, 1, 0, 0, &eaddr);
|
||||
direct_socket = new Network(1, 1, 0, 0, &eaddr);
|
||||
if (direct_socket->getENetHost() == NULL)
|
||||
{
|
||||
Log::warn("STKHost", "No direct socket available, this "
|
||||
"server may not be connected by lan network");
|
||||
delete direct_socket;
|
||||
direct_socket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
while (m_exit_flag.test_and_set())
|
||||
{
|
||||
auto sl = LobbyProtocol::get<ServerLobby>();
|
||||
if (lan_network && sl && sl->waitingForPlayers())
|
||||
if (direct_socket && sl && sl->waitingForPlayers())
|
||||
{
|
||||
handleDirectSocketRequest(lan_network);
|
||||
handleDirectSocketRequest(direct_socket);
|
||||
} // if discovery host
|
||||
|
||||
while (enet_host_service(host, &event, 20) != 0)
|
||||
@@ -780,7 +815,7 @@ void STKHost::mainLoop()
|
||||
|
||||
} // while enet_host_service
|
||||
} // while m_exit_flag.test_and_set()
|
||||
delete lan_network;
|
||||
delete direct_socket;
|
||||
Log::info("STKHost", "Listening has been stopped");
|
||||
} // mainLoop
|
||||
|
||||
@@ -793,17 +828,20 @@ void STKHost::mainLoop()
|
||||
* message is received, will answer with a message containing server details
|
||||
* (and sender IP address and port).
|
||||
*/
|
||||
void STKHost::handleDirectSocketRequest(Network* lan_network)
|
||||
void STKHost::handleDirectSocketRequest(Network* direct_socket)
|
||||
{
|
||||
const int LEN=2048;
|
||||
char buffer[LEN];
|
||||
|
||||
TransportAddress sender;
|
||||
int len = lan_network->receiveRawPacket(buffer, LEN, &sender, 1);
|
||||
int len = direct_socket->receiveRawPacket(buffer, LEN, &sender, 1);
|
||||
if(len<=0) return;
|
||||
BareNetworkString message(buffer, len);
|
||||
std::string command;
|
||||
message.decodeString(&command);
|
||||
const std::string connection_cmd = std::string("connection-request") +
|
||||
StringUtils::toString(m_private_port);
|
||||
const std::string connection_cmd_localhost("connection-request-localhost");
|
||||
|
||||
if (command == "stk-server")
|
||||
{
|
||||
@@ -822,17 +860,19 @@ void STKHost::handleDirectSocketRequest(Network* lan_network)
|
||||
s.encodeString(name);
|
||||
s.addUInt8(NetworkConfig::get()->getMaxPlayers());
|
||||
s.addUInt8(0); // FIXME: current number of connected players
|
||||
s.addUInt32(sender.getIP());
|
||||
s.addUInt16(sender.getPort());
|
||||
s.addUInt16((uint16_t)race_manager->getMinorMode());
|
||||
s.addUInt16(m_private_port);
|
||||
s.addUInt8((uint8_t)race_manager->getDifficulty());
|
||||
lan_network->sendRawPacket(s, sender);
|
||||
s.addUInt8((uint8_t)
|
||||
NetworkConfig::get()->getServerGameMode(race_manager->getMinorMode(),
|
||||
race_manager->getMajorMode()));
|
||||
direct_socket->sendRawPacket(s, sender);
|
||||
} // if message is server-requested
|
||||
else if (command == "connection-request")
|
||||
else if (command == connection_cmd)
|
||||
{
|
||||
// In case of a LAN connection, we only allow connections from
|
||||
// a LAN address (192.168*, ..., and 127.*).
|
||||
if (!sender.isLAN() && !sender.isPublicAddressLAN())
|
||||
if (!sender.isLAN() && !sender.isPublicAddressLocalhost() &&
|
||||
!NetworkConfig::get()->isPublicServer())
|
||||
{
|
||||
Log::error("STKHost", "Client trying to connect from '%s'",
|
||||
sender.toString().c_str());
|
||||
@@ -841,6 +881,19 @@ void STKHost::handleDirectSocketRequest(Network* lan_network)
|
||||
}
|
||||
std::make_shared<ConnectToPeer>(sender)->requestStart();
|
||||
}
|
||||
else if (command == connection_cmd_localhost)
|
||||
{
|
||||
if (sender.getIP() == 0x7f000001)
|
||||
{
|
||||
std::make_shared<ConnectToPeer>(sender)->requestStart();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("STKHost", "Client trying to connect from '%s'",
|
||||
sender.toString().c_str());
|
||||
Log::error("STKHost", "which is not localhost - rejected.");
|
||||
}
|
||||
}
|
||||
else
|
||||
Log::info("STKHost", "Received unknown command '%s'",
|
||||
std::string(buffer, len).c_str());
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "network/network.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/network_string.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "network/stk_peer.hpp"
|
||||
#include "network/transport_address.hpp"
|
||||
#include "utils/synchronised.hpp"
|
||||
@@ -39,9 +38,12 @@
|
||||
#include <enet/enet.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
class GameSetup;
|
||||
class Server;
|
||||
class SeparateProcess;
|
||||
|
||||
class STKHost
|
||||
{
|
||||
@@ -63,6 +65,9 @@ private:
|
||||
/** Singleton pointer to the instance. */
|
||||
static STKHost* m_stk_host;
|
||||
|
||||
/** Separate process of server instance. */
|
||||
SeparateProcess* m_separate_process;
|
||||
|
||||
/** ENet host interfacing sockets. */
|
||||
Network* m_network;
|
||||
|
||||
@@ -110,11 +115,11 @@ private:
|
||||
/** An error message, which is set by a protocol to be displayed
|
||||
* in the GUI. */
|
||||
|
||||
STKHost(uint32_t server_id, uint32_t host_id);
|
||||
STKHost(std::shared_ptr<Server> server);
|
||||
STKHost(const irr::core::stringw &server_name);
|
||||
virtual ~STKHost();
|
||||
void init();
|
||||
void handleDirectSocketRequest(Network* lan_network);
|
||||
void handleDirectSocketRequest(Network* direct_socket);
|
||||
// ------------------------------------------------------------------------
|
||||
void mainLoop();
|
||||
|
||||
@@ -127,7 +132,8 @@ public:
|
||||
/** Creates the STKHost. It takes all confifguration parameters from
|
||||
* NetworkConfig. This STKHost can either be a client or a server.
|
||||
*/
|
||||
static void create();
|
||||
static void create(std::shared_ptr<Server> server = nullptr,
|
||||
SeparateProcess* p = NULL);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the instance of STKHost. */
|
||||
@@ -197,57 +203,61 @@ public:
|
||||
void setErrorMessage(const irr::core::stringw &message);
|
||||
bool isAuthorisedToControl() const;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the last error (or "" if no error has happened). */
|
||||
const irr::core::stringw& getErrorMessage() const
|
||||
{ return m_error_message; }
|
||||
// --------------------------------------------------------------------
|
||||
{ return m_error_message; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns true if a shutdown of the network infrastructure was
|
||||
* requested. */
|
||||
bool requestedShutdown() const { return m_shutdown.load(); }
|
||||
// --------------------------------------------------------------------
|
||||
bool requestedShutdown() const { return m_shutdown.load(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the current game setup. */
|
||||
GameSetup* getGameSetup() { return m_game_setup; }
|
||||
// --------------------------------------------------------------------
|
||||
GameSetup* getGameSetup() { return m_game_setup; }
|
||||
// ------------------------------------------------------------------------
|
||||
int receiveRawPacket(char *buffer, int buffer_len,
|
||||
TransportAddress* sender, int max_tries = -1)
|
||||
{
|
||||
return m_network->receiveRawPacket(buffer, buffer_len, sender,
|
||||
max_tries);
|
||||
} // receiveRawPacket
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
void sendRawPacket(const BareNetworkString &buffer,
|
||||
const TransportAddress& dst)
|
||||
{
|
||||
m_network->sendRawPacket(buffer, dst);
|
||||
} // sendRawPacket
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a const reference to the list of peers. */
|
||||
const std::vector<STKPeer*> &getPeers() { return m_peers; }
|
||||
// --------------------------------------------------------------------
|
||||
const std::vector<STKPeer*> &getPeers() { return m_peers; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the next (unique) host id. */
|
||||
unsigned int getNextHostId() const
|
||||
{
|
||||
assert(m_next_unique_host_id >= 0);
|
||||
return m_next_unique_host_id;
|
||||
}
|
||||
// --------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of currently connected peers. */
|
||||
unsigned int getPeerCount() { return (int)m_peers.size(); }
|
||||
// --------------------------------------------------------------------
|
||||
unsigned int getPeerCount() { return (int)m_peers.size(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the global host id of this host. */
|
||||
void setMyHostId(uint8_t my_host_id) { m_host_id = my_host_id; }
|
||||
// --------------------------------------------------------------------
|
||||
void setMyHostId(uint8_t my_host_id) { m_host_id = my_host_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the host id of this host. */
|
||||
uint8_t getMyHostId() const { return m_host_id; }
|
||||
// --------------------------------------------------------------------
|
||||
uint8_t getMyHostId() const { return m_host_id; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sends a message from a client to the server. */
|
||||
void sendToServer(NetworkString *data, bool reliable = true)
|
||||
{
|
||||
assert(NetworkConfig::get()->isClient());
|
||||
m_peers[0]->sendPacket(data, reliable);
|
||||
} // sendToServer
|
||||
// ------------------------------------------------------------------------
|
||||
/** True if this is a client and server in graphics mode made by server
|
||||
* creation screen. */
|
||||
bool isClientServer() const { return m_separate_process != NULL; }
|
||||
|
||||
}; // class STKHost
|
||||
|
||||
#endif // STK_HOST_HPP
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "network/stk_host.hpp"
|
||||
#include "network/transport_address.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/time.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@@ -21,7 +21,10 @@
|
||||
#ifdef WIN32
|
||||
# include <iphlpapi.h>
|
||||
#else
|
||||
#include <ifaddrs.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <net/if.h>
|
||||
# include <string.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -45,23 +48,53 @@ bool TransportAddress::isLAN() const
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns this IP address is localhost (127.0.0.1).
|
||||
*/
|
||||
bool TransportAddress::isPublicAddressLAN() const
|
||||
bool TransportAddress::isPublicAddressLocalhost() const
|
||||
{
|
||||
#ifndef WIN32
|
||||
struct ifaddrs *ifap, *ifa;
|
||||
struct sockaddr_in *sa;
|
||||
getifaddrs(&ifap); // get the info
|
||||
for (ifa = ifap; ifa; ifa = ifa->ifa_next)
|
||||
char buffer[2048] = {};
|
||||
struct ifconf ifc;
|
||||
ifc.ifc_len = sizeof(buffer);
|
||||
ifc.ifc_buf = (caddr_t)buffer;
|
||||
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (ifa->ifa_addr->sa_family == AF_INET)
|
||||
Log::error("TransportAddress","create socket failed, errno "
|
||||
"= %s (%d)\n", strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
|
||||
{
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
Log::error("TransportAddress", "ioctl SIOCGIFCONF failed, "
|
||||
"errno = %s (%d)\n", strerror(errno), errno);
|
||||
return false;
|
||||
}
|
||||
bool is_local_host = false;
|
||||
for (int i = 0; i < ifc.ifc_len; i += sizeof(struct ifreq))
|
||||
{
|
||||
struct ifreq *ifr = (struct ifreq*)(buffer + i);
|
||||
if (ifr->ifr_addr.sa_family != AF_INET)
|
||||
{
|
||||
sa = (struct sockaddr_in *) ifa->ifa_addr;
|
||||
// This interface is ours
|
||||
if (ntohl(sa->sin_addr.s_addr) == getIP())
|
||||
return true;
|
||||
// only support IPv4
|
||||
continue;
|
||||
}
|
||||
struct sockaddr_in *addr = (struct sockaddr_in*)&ifr->ifr_addr;
|
||||
if (ntohl(addr->sin_addr.s_addr) == getIP())
|
||||
{
|
||||
is_local_host = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
if (fd >= 0 && close(fd) != 0)
|
||||
{
|
||||
Log::error("TransportAddress", "close fd %d failed, errno "
|
||||
"= %s (%d)\n", strerror(errno), errno);
|
||||
}
|
||||
return is_local_host;
|
||||
|
||||
#else
|
||||
// Query the list of all IP addresses on the local host. First call to
|
||||
// GetIpAddrTable with 0 bytes buffer will return insufficient buffer
|
||||
@@ -92,9 +125,9 @@ bool TransportAddress::isPublicAddressLAN() const
|
||||
}
|
||||
}
|
||||
delete[] table;
|
||||
#endif
|
||||
return false;
|
||||
} // isLAN
|
||||
#endif
|
||||
} // isPublicAddressLocalhost
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Unit testing. Test various LAN patterns to verify that isLAN() works as
|
||||
|
||||
@@ -89,7 +89,7 @@ private:
|
||||
} // TransportAddress(const TransportAddress&)
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
bool isPublicAddressLAN() const;
|
||||
bool isPublicAddressLocalhost() const;
|
||||
// ------------------------------------------------------------------------
|
||||
bool isLAN() const;
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "config/user_config.hpp"
|
||||
#include "guiengine/message_queue.hpp"
|
||||
#include "guiengine/screen.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "online/online_profile.hpp"
|
||||
#include "online/profile_manager.hpp"
|
||||
#include "states_screens/main_menu_screen.hpp"
|
||||
@@ -110,15 +111,14 @@ namespace Online
|
||||
* \param username Name of user.
|
||||
* \param password Password.
|
||||
*/
|
||||
OnlinePlayerProfile::SignInRequest*
|
||||
OnlinePlayerProfile::requestSignIn(const core::stringw &username,
|
||||
void OnlinePlayerProfile::requestSignIn(const core::stringw &username,
|
||||
const core::stringw &password)
|
||||
{
|
||||
// If the player changes the online account, there can be a
|
||||
// logout stil happening.
|
||||
assert(m_online_state == OS_SIGNED_OUT ||
|
||||
m_online_state == OS_SIGNING_OUT);
|
||||
SignInRequest * request = new SignInRequest(false);
|
||||
SignInRequest * request = new SignInRequest(true);
|
||||
|
||||
// We can't use setUserDetail here, since there is no token yet
|
||||
request->setApiURL(API::USER_PATH, "connect");
|
||||
@@ -129,8 +129,6 @@ namespace Online
|
||||
: "false");
|
||||
request->queue();
|
||||
m_online_state = OS_SIGNING_IN;
|
||||
|
||||
return request;
|
||||
} // requestSignIn
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -208,9 +206,21 @@ namespace Online
|
||||
core::stringw username("");
|
||||
uint32_t userid(0);
|
||||
|
||||
#ifdef DEBUG
|
||||
int token_fetched = input->get("token", &m_token);
|
||||
int username_fetched = input->get("username", &username);
|
||||
int userid_fetched = input->get("userid", &userid);
|
||||
assert(token_fetched && username_fetched && userid_fetched);
|
||||
#else
|
||||
input->get("token", &m_token);
|
||||
input->get("username", &username);
|
||||
input->get("userid", &userid);
|
||||
#endif
|
||||
if (NetworkConfig::get()->getServerIdFile().empty())
|
||||
{
|
||||
NetworkConfig::get()->setCurrentUserId(userid);
|
||||
NetworkConfig::get()->setCurrentUserToken(m_token);
|
||||
}
|
||||
setLastOnlineName(username);
|
||||
|
||||
OnlineProfile* profile = new OnlineProfile(userid, username, true);
|
||||
@@ -218,7 +228,6 @@ namespace Online
|
||||
// existing profile, and then delete profile. Only the returned
|
||||
// pointer is save to use.
|
||||
m_profile = ProfileManager::get()->addPersistent(profile);
|
||||
assert(token_fetched && username_fetched && userid_fetched);
|
||||
m_online_state = OS_SIGNED_IN;
|
||||
if(rememberPassword())
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace Online
|
||||
{
|
||||
virtual void callback ();
|
||||
public:
|
||||
SignInRequest(bool manage_memory = false)
|
||||
SignInRequest(bool manage_memory)
|
||||
: XMLRequest(manage_memory, /*priority*/10) {}
|
||||
}; // SignInRequest
|
||||
|
||||
@@ -105,8 +105,8 @@ namespace Online
|
||||
const std::string& getToken() const { return m_token; }
|
||||
virtual void requestSavedSession();
|
||||
virtual void requestSignOut();
|
||||
virtual SignInRequest *requestSignIn(const irr::core::stringw &username,
|
||||
const irr::core::stringw &password);
|
||||
virtual void requestSignIn(const irr::core::stringw &username,
|
||||
const irr::core::stringw &password);
|
||||
|
||||
public:
|
||||
OnlinePlayerProfile(const XMLNode *player);
|
||||
|
||||
@@ -227,7 +227,7 @@ public:
|
||||
#undef BATTLE_ARENA
|
||||
|
||||
/** Game difficulty. */
|
||||
enum Difficulty { DIFFICULTY_EASY,
|
||||
enum Difficulty { DIFFICULTY_EASY = 0,
|
||||
DIFFICULTY_FIRST = DIFFICULTY_EASY,
|
||||
DIFFICULTY_MEDIUM,
|
||||
DIFFICULTY_HARD,
|
||||
|
||||
@@ -26,12 +26,13 @@
|
||||
#include "modes/demo_world.hpp"
|
||||
#include "network/protocols/lobby_protocol.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "states_screens/dialogs/message_dialog.hpp"
|
||||
#include "states_screens/networking_lobby.hpp"
|
||||
#include "states_screens/dialogs/server_info_dialog.hpp"
|
||||
#include "utils/separate_process.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
#include <irrString.h>
|
||||
@@ -59,7 +60,13 @@ void CreateServerScreen::loadedFromFile()
|
||||
|
||||
m_max_players_widget = getWidget<SpinnerWidget>("max_players");
|
||||
assert(m_max_players_widget != NULL);
|
||||
m_max_players_widget->setValue(8);
|
||||
int max = UserConfigParams::m_server_max_players.getDefaultValue();
|
||||
m_max_players_widget->setMax(max);
|
||||
|
||||
if (UserConfigParams::m_server_max_players > max)
|
||||
UserConfigParams::m_server_max_players = max;
|
||||
|
||||
m_max_players_widget->setValue(UserConfigParams::m_server_max_players);
|
||||
|
||||
m_info_widget = getWidget<LabelWidget>("info");
|
||||
assert(m_info_widget != NULL);
|
||||
@@ -162,25 +169,28 @@ void CreateServerScreen::createServer()
|
||||
SFXManager::get()->quickSound("anvil");
|
||||
return;
|
||||
}
|
||||
else if (max_players < 2 || max_players > 12)
|
||||
{
|
||||
m_info_widget->setText(
|
||||
_("The maxinum number of players has to be between 2 and 12."),
|
||||
false);
|
||||
SFXManager::get()->quickSound("anvil");
|
||||
return;
|
||||
}
|
||||
assert(max_players > 1 &&
|
||||
max_players <= UserConfigParams::m_server_max_players.getDefaultValue());
|
||||
|
||||
// In case of a LAN game, we can create the new server object now
|
||||
if (NetworkConfig::get()->isLAN())
|
||||
{
|
||||
// FIXME Is this actually necessary?? Only in case of WAN, or LAN and WAN?
|
||||
TransportAddress address(0x7f000001,0); // 127.0.0.1
|
||||
Server *server = new Server(name, /*lan*/true, max_players,
|
||||
/*current_player*/1, address);
|
||||
ServersManager::get()->addServer(server);
|
||||
}
|
||||
UserConfigParams::m_server_max_players = max_players;
|
||||
core::stringw password_w = getWidget<TextBoxWidget>("password")->getText();
|
||||
std::string password = StringUtils::xmlEncode(password_w);
|
||||
NetworkConfig::get()->setPassword(StringUtils::wideToUtf8(password_w));
|
||||
if (!password.empty())
|
||||
password = std::string(" --server-password=") + password;
|
||||
|
||||
TransportAddress server_address(0x7f000001,
|
||||
NetworkConfig::get()->getServerDiscoveryPort());
|
||||
|
||||
auto server = std::make_shared<Server>(0/*server_id*/, name,
|
||||
max_players, /*current_player*/0, (RaceManager::Difficulty)
|
||||
difficulty_widget->getSelection(PLAYER_ID_GAME_MASTER),
|
||||
NetworkConfig::get()->getServerGameMode(race_manager->getMinorMode(),
|
||||
race_manager->getMajorMode()), server_address);
|
||||
|
||||
#undef USE_GRAPHICS_SERVER
|
||||
#ifdef USE_GRAPHICS_SERVER
|
||||
NetworkConfig::get()->setIsServer(true);
|
||||
// In case of a WAN game, we register this server with the
|
||||
// stk server, and will get the server's id when this
|
||||
// request is finished.
|
||||
@@ -200,13 +210,48 @@ void CreateServerScreen::createServer()
|
||||
else
|
||||
race_manager->setMinorMode(RaceManager::MINOR_MODE_NORMAL_RACE);
|
||||
|
||||
core::stringw password_w = getWidget<TextBoxWidget>("password")->getText();
|
||||
std::string password(core::stringc(password_w.c_str()).c_str());
|
||||
NetworkConfig::get()->setPassword(password);
|
||||
|
||||
race_manager->setReverseTrack(false);
|
||||
STKHost::create();
|
||||
#else
|
||||
|
||||
NetworkConfig::get()->setIsServer(false);
|
||||
std::ostringstream server_cfg;
|
||||
#ifdef WIN32
|
||||
server_cfg << " ";
|
||||
#endif
|
||||
|
||||
const std::string server_name = StringUtils::xmlEncode(name);
|
||||
if (NetworkConfig::get()->isWAN())
|
||||
{
|
||||
server_cfg << "--public-server --wan-server=" <<
|
||||
server_name << " --login-id=" <<
|
||||
NetworkConfig::get()->getCurrentUserId() << " --token=" <<
|
||||
NetworkConfig::get()->getCurrentUserToken();
|
||||
}
|
||||
else
|
||||
{
|
||||
server_cfg << "--lan-server=" << server_name;
|
||||
}
|
||||
|
||||
std::string server_id_file = "server_id_file_";
|
||||
server_id_file += StringUtils::toString(StkTime::getTimeSinceEpoch());
|
||||
NetworkConfig::get()->setServerIdFile(
|
||||
file_manager->getUserConfigFile(server_id_file));
|
||||
|
||||
server_cfg << " --no-graphics --stdout=server.log --type=" <<
|
||||
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";
|
||||
|
||||
SeparateProcess* sp =
|
||||
new SeparateProcess(SeparateProcess::getCurrentExecutableLocation(),
|
||||
server_cfg.str() + password);
|
||||
STKHost::create(server, sp);
|
||||
|
||||
#endif
|
||||
} // createServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -17,17 +17,12 @@
|
||||
|
||||
#include "states_screens/dialogs/server_info_dialog.hpp"
|
||||
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/protocols/request_connection.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "states_screens/dialogs/registration_dialog.hpp"
|
||||
#include "states_screens/networking_lobby.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
#include <IGUIEnvironment.h>
|
||||
|
||||
@@ -43,22 +38,17 @@ using namespace Online;
|
||||
* \param from_server_creation: true if the dialog shows the data of this
|
||||
* server (i.e. while it is being created).
|
||||
*/
|
||||
ServerInfoDialog::ServerInfoDialog(uint32_t server_id, uint32_t host_id,
|
||||
bool from_server_creation)
|
||||
: ModalDialog(0.8f,0.8f), m_server_id(server_id)
|
||||
, m_host_id(host_id)
|
||||
ServerInfoDialog::ServerInfoDialog(std::shared_ptr<Server> server)
|
||||
: ModalDialog(0.8f,0.8f), m_server(server)
|
||||
{
|
||||
Log::info("ServerInfoDialog", "Server id is %d, Host id is %d",
|
||||
server_id, host_id);
|
||||
server->getServerId(), server->getHostId());
|
||||
m_self_destroy = false;
|
||||
m_enter_lobby = false;
|
||||
m_from_server_creation = from_server_creation;
|
||||
|
||||
loadFromFile("online/server_info_dialog.stkgui");
|
||||
|
||||
GUIEngine::LabelWidget *name = getWidget<LabelWidget>("server_name");
|
||||
assert(name);
|
||||
const Server * server = ServersManager::get()->getServerByID(m_server_id);
|
||||
name->setText(server->getName(),false);
|
||||
|
||||
core::stringw difficulty = race_manager->getDifficultyName(server->getDifficulty());
|
||||
@@ -69,10 +59,6 @@ ServerInfoDialog::ServerInfoDialog(uint32_t server_id, uint32_t host_id,
|
||||
GUIEngine::LabelWidget *gamemode = getWidget<LabelWidget>("server_game_mode");
|
||||
gamemode->setText(mode, false);
|
||||
|
||||
m_info_widget = getWidget<LabelWidget>("info");
|
||||
assert(m_info_widget != NULL);
|
||||
if (m_from_server_creation)
|
||||
m_info_widget->setText(_("Server successfully created. You can now join it."), true);
|
||||
m_options_widget = getWidget<RibbonWidget>("options");
|
||||
assert(m_options_widget != NULL);
|
||||
m_join_widget = getWidget<IconButtonWidget>("join");
|
||||
@@ -92,9 +78,8 @@ ServerInfoDialog::~ServerInfoDialog()
|
||||
// -----------------------------------------------------------------------------
|
||||
void ServerInfoDialog::requestJoin()
|
||||
{
|
||||
ServersManager::get()->setJoinedServer(m_server_id);
|
||||
|
||||
STKHost::create();
|
||||
STKHost::create(m_server);
|
||||
NetworkingLobby::getInstance()->setJoinedServer(m_server);
|
||||
ModalDialog::dismiss();
|
||||
NetworkingLobby::getInstance()->push();
|
||||
} // requestJoin
|
||||
@@ -146,17 +131,10 @@ bool ServerInfoDialog::onEscapePressed()
|
||||
// -----------------------------------------------------------------------------
|
||||
void ServerInfoDialog::onUpdate(float dt)
|
||||
{
|
||||
//If we want to open the registration dialog, we need to close this one first
|
||||
if (m_enter_lobby) m_self_destroy = true;
|
||||
|
||||
// It's unsafe to delete from inside the event handler so we do it here
|
||||
if (m_self_destroy)
|
||||
{
|
||||
ModalDialog::dismiss();
|
||||
if (m_from_server_creation)
|
||||
StateManager::get()->popMenu();
|
||||
else if (m_enter_lobby)
|
||||
NetworkingLobby::getInstance()->push();
|
||||
return;
|
||||
}
|
||||
} // onUpdate
|
||||
|
||||
@@ -23,11 +23,13 @@
|
||||
#include "guiengine/widgets/icon_button_widget.hpp"
|
||||
#include "guiengine/widgets/ribbon_widget.hpp"
|
||||
#include "guiengine/widgets/label_widget.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "utils/types.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <irrString.h>
|
||||
|
||||
class Server;
|
||||
|
||||
/** \brief Dialog that allows a user to sign in
|
||||
* \ingroup states_screens
|
||||
*/
|
||||
@@ -35,16 +37,9 @@ class ServerInfoDialog : public GUIEngine::ModalDialog
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
bool m_self_destroy;
|
||||
bool m_enter_lobby;
|
||||
bool m_from_server_creation;
|
||||
|
||||
const uint32_t m_server_id;
|
||||
uint32_t m_host_id;
|
||||
|
||||
/** The gui element for messages. */
|
||||
GUIEngine::LabelWidget *m_info_widget;
|
||||
const std::shared_ptr<Server> m_server;
|
||||
|
||||
GUIEngine::RibbonWidget *m_options_widget;
|
||||
|
||||
@@ -56,7 +51,7 @@ private:
|
||||
|
||||
|
||||
public:
|
||||
ServerInfoDialog(uint32_t server_id, uint32_t host_id, bool just_created = false);
|
||||
ServerInfoDialog(std::shared_ptr<Server> server);
|
||||
~ServerInfoDialog();
|
||||
|
||||
void onEnterPressedInternal();
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "network/protocols/client_lobby.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "states_screens/race_setup_screen.hpp"
|
||||
#include "states_screens/server_selection.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "states_screens/tracks_screen.hpp"
|
||||
#include "states_screens/waiting_for_others.hpp"
|
||||
@@ -222,11 +221,6 @@ bool NetworkKartSelectionScreen::onEscapePressed()
|
||||
{
|
||||
// then remove the lobby screen (you left the server)
|
||||
StateManager::get()->popMenu();
|
||||
ServerSelection::getInstance()->refresh();
|
||||
// notify the server that we left
|
||||
auto clrp = LobbyProtocol::get<ClientLobby>();
|
||||
if (clrp)
|
||||
clrp->leave();
|
||||
STKHost::get()->shutdown();
|
||||
return true; // remove the screen
|
||||
} // onEscapePressed
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "network/network_player_profile.hpp"
|
||||
#include "network/protocols/client_lobby.hpp"
|
||||
#include "network/protocols/server_lobby.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "states_screens/dialogs/message_dialog.hpp"
|
||||
@@ -100,27 +100,8 @@ void NetworkingLobby::beforeAddingWidget()
|
||||
*/
|
||||
void NetworkingLobby::init()
|
||||
{
|
||||
m_server_info.clear();
|
||||
Screen::init();
|
||||
setInitialFocus();
|
||||
Server* server = ServersManager::get()->getJoinedServer();
|
||||
if (server)
|
||||
{
|
||||
m_server_name = server->getName();
|
||||
core::stringw each_line;
|
||||
each_line = _("Server name: %s", m_server_name);
|
||||
m_server_info.push_back(each_line);
|
||||
|
||||
const core::stringw& difficulty_name =
|
||||
race_manager->getDifficultyName(race_manager->getDifficulty());
|
||||
each_line = _("Difficulty: %s", difficulty_name);
|
||||
m_server_info.push_back(each_line);
|
||||
|
||||
core::stringw mode = RaceManager::getNameOf(server->getRaceMinorMode());
|
||||
each_line = _("Game mode: %s", mode);
|
||||
m_server_info.push_back(each_line);
|
||||
}
|
||||
|
||||
m_start_button->setVisible(false);
|
||||
|
||||
// For now create the active player and bind it to the right
|
||||
@@ -130,6 +111,44 @@ void NetworkingLobby::init()
|
||||
StateManager::get()->createActivePlayer(profile, device);
|
||||
} // init
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkingLobby::setJoinedServer(std::shared_ptr<Server> server)
|
||||
{
|
||||
if (server == m_joined_server)
|
||||
return;
|
||||
|
||||
m_joined_server = server;
|
||||
m_server_info.clear();
|
||||
|
||||
if (!m_joined_server)
|
||||
return;
|
||||
core::stringw each_line;
|
||||
|
||||
//I18N: In the networking lobby
|
||||
each_line = _("Server name: %s", m_joined_server->getName());
|
||||
m_server_info.push_back(each_line);
|
||||
|
||||
const core::stringw& difficulty_name =
|
||||
race_manager->getDifficultyName(m_joined_server->getDifficulty());
|
||||
//I18N: In the networking lobby
|
||||
each_line = _("Difficulty: %s", difficulty_name);
|
||||
m_server_info.push_back(each_line);
|
||||
|
||||
//I18N: In the networking lobby
|
||||
each_line = _("Max players: %d", m_joined_server->getMaxPlayers());
|
||||
m_server_info.push_back(each_line);
|
||||
|
||||
//I18N: In the networking lobby
|
||||
core::stringw mode = RaceManager::getNameOf(m_joined_server->getRaceMinorMode());
|
||||
each_line = _("Game mode: %s", mode);
|
||||
|
||||
race_manager->setMinorMode(m_joined_server->getRaceMinorMode());
|
||||
race_manager->setMajorMode(m_joined_server->getRaceMajorMode());
|
||||
race_manager->setDifficulty(m_joined_server->getDifficulty());
|
||||
|
||||
m_server_info.push_back(each_line);
|
||||
} // setJoinedServer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkingLobby::addMoreServerInfo(const core::stringw& info)
|
||||
{
|
||||
@@ -141,8 +160,17 @@ void NetworkingLobby::onUpdate(float delta)
|
||||
auto lp = LobbyProtocol::get<LobbyProtocol>();
|
||||
if (!lp)
|
||||
{
|
||||
const core::stringw connect_msg = StringUtils::loadingDots(
|
||||
_("Connecting to server %s", m_server_name));
|
||||
core::stringw connect_msg;
|
||||
if (m_joined_server)
|
||||
{
|
||||
connect_msg = StringUtils::loadingDots(
|
||||
_("Connecting to server %s", m_joined_server->getName()));
|
||||
}
|
||||
else if (NetworkConfig::get()->isClient())
|
||||
{
|
||||
connect_msg =
|
||||
StringUtils::loadingDots(_("Finding a quick play server"));
|
||||
}
|
||||
m_text_bubble->setText(connect_msg, true);
|
||||
m_start_button->setVisible(false);
|
||||
}
|
||||
@@ -165,7 +193,6 @@ void NetworkingLobby::onUpdate(float delta)
|
||||
} // onUpdate
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void NetworkingLobby::eventCallback(Widget* widget, const std::string& name,
|
||||
const int playerID)
|
||||
{
|
||||
@@ -212,10 +239,6 @@ void NetworkingLobby::tearDown()
|
||||
|
||||
bool NetworkingLobby::onEscapePressed()
|
||||
{
|
||||
// notify the server that we left
|
||||
auto clrp = LobbyProtocol::get<ClientLobby>();
|
||||
if (clrp)
|
||||
clrp->leave();
|
||||
STKHost::get()->shutdown();
|
||||
return true; // close the screen
|
||||
} // onEscapePressed
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#define HEADER_NETWORKING_LOBBY_HPP
|
||||
|
||||
#include "guiengine/screen.hpp"
|
||||
#include <memory>
|
||||
|
||||
class Server;
|
||||
|
||||
@@ -45,7 +46,7 @@ private:
|
||||
|
||||
NetworkingLobby();
|
||||
|
||||
core::stringw m_server_name;
|
||||
std::shared_ptr<Server> m_joined_server;
|
||||
std::vector<core::stringw> m_server_info;
|
||||
|
||||
GUIEngine::IconButtonWidget * m_back_widget;
|
||||
@@ -89,6 +90,7 @@ public:
|
||||
|
||||
/** Used to insert each client chat message (reserved). */
|
||||
void addMoreServerInfo(const core::stringw& info);
|
||||
void setJoinedServer(std::shared_ptr<Server> server);
|
||||
void addPlayer(NetworkPlayerProfile *profile);
|
||||
void removePlayer(NetworkPlayerProfile *profile);
|
||||
}; // class NetworkingLobby
|
||||
|
||||
@@ -55,9 +55,12 @@ OnlineLanScreen::OnlineLanScreen() : GUIEngine::Screen("online/lan.stkgui")
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void OnlineLanScreen::loadedFromFile()
|
||||
void OnlineLanScreen::beforeAddingWidget()
|
||||
{
|
||||
} // loadedFromFile
|
||||
#ifdef ANDROID
|
||||
getWidget("create_lan_server")->setVisible(false);
|
||||
#endif
|
||||
} // beforeAddingWidget
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -85,9 +88,7 @@ void OnlineLanScreen::eventCallback(Widget* widget, const std::string& name, con
|
||||
if (selection == "create_lan_server")
|
||||
{
|
||||
NetworkConfig::get()->setIsLAN();
|
||||
NetworkConfig::get()->setIsServer(true);
|
||||
CreateServerScreen::getInstance()->push();
|
||||
// TODO: create lan server
|
||||
}
|
||||
else if (selection == "find_lan_server")
|
||||
{
|
||||
|
||||
@@ -42,7 +42,10 @@ public:
|
||||
friend class GUIEngine::ScreenSingleton<OnlineLanScreen>;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void loadedFromFile() OVERRIDE;
|
||||
virtual void loadedFromFile() {}
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void beforeAddingWidget() OVERRIDE;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name,
|
||||
|
||||
@@ -20,13 +20,10 @@
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "config/player_manager.hpp"
|
||||
#include "guiengine/engine.hpp"
|
||||
#include "guiengine/scalable_font.hpp"
|
||||
#include "guiengine/screen.hpp"
|
||||
#include "guiengine/widget.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/protocols/connect_to_server.hpp"
|
||||
#include "network/protocols/request_connection.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "states_screens/create_server_screen.hpp"
|
||||
@@ -53,8 +50,7 @@ OnlineProfileServers::OnlineProfileServers() : GUIEngine::Screen("online/profile
|
||||
} // OnlineProfileServers
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void OnlineProfileServers::loadedFromFile()
|
||||
void OnlineProfileServers::beforeAddingWidget()
|
||||
{
|
||||
if (!PlayerManager::getCurrentOnlineId())
|
||||
{
|
||||
@@ -62,7 +58,10 @@ void OnlineProfileServers::loadedFromFile()
|
||||
getWidget<IconButtonWidget>("create_wan_server")->setActive(false);
|
||||
getWidget<IconButtonWidget>("quick_wan_play")->setActive(false);
|
||||
}
|
||||
} // loadedFromFile
|
||||
#ifdef ANDROID
|
||||
getWidget("create_wan_server")->setVisible(false);
|
||||
#endif
|
||||
} // beforeAddingWidget
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -96,11 +95,12 @@ void OnlineProfileServers::eventCallback(Widget* widget, const std::string& name
|
||||
else if (selection == "create_wan_server")
|
||||
{
|
||||
NetworkConfig::get()->setIsWAN();
|
||||
NetworkConfig::get()->setIsServer(true);
|
||||
CreateServerScreen::getInstance()->push();
|
||||
}
|
||||
else if (selection == "quick_wan_play")
|
||||
{
|
||||
NetworkConfig::get()->setIsWAN();
|
||||
NetworkConfig::get()->setIsServer(false);
|
||||
doQuickPlay();
|
||||
}
|
||||
}
|
||||
@@ -108,55 +108,11 @@ void OnlineProfileServers::eventCallback(Widget* widget, const std::string& name
|
||||
} // eventCallback
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void OnlineProfileServers::doQuickPlay()
|
||||
{
|
||||
// Refresh server list.
|
||||
HTTPRequest* refresh_request = ServersManager::get()->getRefreshRequest(false);
|
||||
if (refresh_request != NULL) // consider request done
|
||||
{
|
||||
refresh_request->executeNow();
|
||||
delete refresh_request;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log::error("OnlineScreen", "Could not get the server list.");
|
||||
return;
|
||||
}
|
||||
|
||||
// select first one
|
||||
const Server *server = ServersManager::get()->getQuickPlay();
|
||||
if(!server)
|
||||
{
|
||||
Log::error("OnlineProfileServers", "Can not find quick play server.");
|
||||
return;
|
||||
}
|
||||
|
||||
// do a join request
|
||||
XMLRequest *join_request = new RequestConnection::ServerJoinRequest();
|
||||
if (!join_request)
|
||||
{
|
||||
SFXManager::get()->quickSound("anvil");
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerManager::setUserDetails(join_request, "request-connection",
|
||||
Online::API::SERVER_PATH);
|
||||
join_request->addParameter("server_id", server->getServerId());
|
||||
|
||||
join_request->executeNow();
|
||||
if (join_request->isSuccess())
|
||||
{
|
||||
delete join_request;
|
||||
NetworkingLobby::getInstance()->push();
|
||||
auto cts = std::make_shared<ConnectToServer>(server->getServerId(),
|
||||
server->getHostId());
|
||||
ProtocolManager::lock()->requestStart(cts);
|
||||
}
|
||||
else
|
||||
{
|
||||
SFXManager::get()->quickSound("anvil");
|
||||
}
|
||||
STKHost::create();
|
||||
NetworkingLobby::getInstance()->setJoinedServer(nullptr);
|
||||
NetworkingLobby::getInstance()->push();
|
||||
} // doQuickPlay
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -44,7 +44,10 @@ public:
|
||||
friend class GUIEngine::ScreenSingleton<OnlineProfileServers>;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void loadedFromFile() OVERRIDE;
|
||||
virtual void loadedFromFile() OVERRIDE {}
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void beforeAddingWidget() OVERRIDE;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name,
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "guiengine/modaldialog.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "online/xml_request.hpp"
|
||||
#include "states_screens/dialogs/message_dialog.hpp"
|
||||
#include "states_screens/dialogs/server_info_dialog.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
@@ -40,7 +40,7 @@ DEFINE_SCREEN_SINGLETON( ServerSelection );
|
||||
*/
|
||||
ServerSelection::ServerSelection() : Screen("online/server_selection.stkgui")
|
||||
{
|
||||
m_refresh_request = NULL;
|
||||
m_refreshing_server = false;
|
||||
} // ServerSelection
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -55,12 +55,8 @@ ServerSelection::~ServerSelection()
|
||||
*/
|
||||
void ServerSelection::tearDown()
|
||||
{
|
||||
// If the refresh request is being executed, and stk should exit,
|
||||
// then a crash can happen when the refresh request is deleted, but
|
||||
// then the request manager tries to activate this request. So only
|
||||
// delete this request if it is finished.
|
||||
if(m_refresh_request && m_refresh_request->isDone())
|
||||
delete m_refresh_request;
|
||||
ServersManager::get()->cleanUpServers();
|
||||
m_server_list_widget->clear();
|
||||
} // tearDown
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -69,16 +65,13 @@ void ServerSelection::tearDown()
|
||||
*/
|
||||
void ServerSelection::refresh()
|
||||
{
|
||||
m_refresh_request = ServersManager::get()->getRefreshRequest();
|
||||
// If the request was created (i.e. no error, and not re-requested within
|
||||
// 5 seconds), clear the list and display the waiting message:
|
||||
if(m_refresh_request)
|
||||
if (ServersManager::get()->refresh())
|
||||
{
|
||||
m_server_list_widget->clear();
|
||||
m_server_list_widget->addItem("spacer", L"");
|
||||
m_server_list_widget->addItem("loading",
|
||||
StringUtils::loadingDots(_("Fetching servers")));
|
||||
m_reload_widget->setActive(false);
|
||||
m_refreshing_server = true;
|
||||
}
|
||||
} // refresh
|
||||
|
||||
@@ -113,10 +106,6 @@ void ServerSelection::init()
|
||||
{
|
||||
Screen::init();
|
||||
m_sort_desc = true;
|
||||
|
||||
// Set the default sort order
|
||||
Server::setSortOrder(Server::SO_NAME);
|
||||
|
||||
/** Triggers the loading of the server list in the servers manager. */
|
||||
refresh();
|
||||
} // init
|
||||
@@ -124,16 +113,37 @@ void ServerSelection::init()
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Loads the list of all servers. The gui element will be
|
||||
* updated.
|
||||
* \param type Must be 'kart' or 'track'.
|
||||
* \param sort_case what sorting method will be used.
|
||||
*/
|
||||
void ServerSelection::loadList()
|
||||
void ServerSelection::loadList(unsigned sort_case)
|
||||
{
|
||||
m_server_list_widget->clear();
|
||||
ServersManager *manager = ServersManager::get();
|
||||
manager->sort(m_sort_desc);
|
||||
for(int i=0; i < manager->getNumServers(); i++)
|
||||
m_server_list_widget->clear();
|
||||
ServersManager::get()->sortServers([sort_case, this]
|
||||
(const std::shared_ptr<Server> a,
|
||||
const std::shared_ptr<Server> b)->bool
|
||||
{
|
||||
std::shared_ptr<Server> c = m_sort_desc ? a : b;
|
||||
std::shared_ptr<Server> d = m_sort_desc ? b : a;
|
||||
switch (sort_case)
|
||||
{
|
||||
case 0:
|
||||
return c->getLowerCaseName() > d->getLowerCaseName();
|
||||
break;
|
||||
case 1:
|
||||
return c->getCurrentPlayers() > d->getCurrentPlayers();
|
||||
break;
|
||||
case 2:
|
||||
return c->getDifficulty() > d->getDifficulty();
|
||||
break;
|
||||
case 3:
|
||||
return c->getRaceMinorMode() > d->getRaceMinorMode();
|
||||
break;
|
||||
} // switch
|
||||
assert(false);
|
||||
return false;
|
||||
});
|
||||
for (auto server : ServersManager::get()->getServers())
|
||||
{
|
||||
const Server *server = manager->getServerBySort(i);
|
||||
core::stringw num_players;
|
||||
num_players.append(StringUtils::toWString(server->getCurrentPlayers()));
|
||||
num_players.append("/");
|
||||
@@ -142,7 +152,8 @@ void ServerSelection::loadList()
|
||||
row.push_back(GUIEngine::ListWidget::ListCell(server->getName(),-1,3));
|
||||
row.push_back(GUIEngine::ListWidget::ListCell(num_players,-1,1,true));
|
||||
|
||||
core::stringw difficulty = race_manager->getDifficultyName(server->getDifficulty());
|
||||
core::stringw difficulty =
|
||||
race_manager->getDifficultyName(server->getDifficulty());
|
||||
row.push_back(GUIEngine::ListWidget::ListCell(difficulty, -1, 1, true));
|
||||
|
||||
core::stringw mode = RaceManager::getNameOf(server->getRaceMinorMode());
|
||||
@@ -158,21 +169,14 @@ void ServerSelection::loadList()
|
||||
*/
|
||||
void ServerSelection::onColumnClicked(int column_id)
|
||||
{
|
||||
switch(column_id)
|
||||
{
|
||||
case 0: Server::setSortOrder(Server::SO_NAME); break;
|
||||
case 1: Server::setSortOrder(Server::SO_PLAYERS); break;
|
||||
default: assert(0); break;
|
||||
} // switch
|
||||
/** \brief Toggle the sort order after column click **/
|
||||
m_sort_desc = !m_sort_desc;
|
||||
loadList();
|
||||
loadList(column_id);
|
||||
} // onColumnClicked
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void ServerSelection::eventCallback( GUIEngine::Widget* widget,
|
||||
const std::string& name,
|
||||
const int playerID)
|
||||
void ServerSelection::eventCallback(GUIEngine::Widget* widget,
|
||||
const std::string& name,
|
||||
const int playerID)
|
||||
{
|
||||
if (name == "back")
|
||||
{
|
||||
@@ -189,17 +193,13 @@ void ServerSelection::eventCallback( GUIEngine::Widget* widget,
|
||||
int selected_index = m_server_list_widget->getSelectionID();
|
||||
// This can happen e.g. when the list is empty and the user
|
||||
// clicks somewhere.
|
||||
if(selected_index >= ServersManager::get()->getNumServers() ||
|
||||
selected_index<0 )
|
||||
if (selected_index < 0 || m_refreshing_server ||
|
||||
selected_index >= (int)ServersManager::get()->getServers().size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const Server *server =
|
||||
ServersManager::get()->getServerBySort(selected_index);
|
||||
uint32_t server_id = server->getServerId();
|
||||
uint32_t host_id = server->getHostId();
|
||||
new ServerInfoDialog(server_id, host_id);
|
||||
new ServerInfoDialog(
|
||||
ServersManager::get()->getServers()[selected_index]);
|
||||
} // click on server
|
||||
|
||||
} // eventCallback
|
||||
@@ -211,55 +211,42 @@ void ServerSelection::eventCallback( GUIEngine::Widget* widget,
|
||||
void ServerSelection::onUpdate(float dt)
|
||||
|
||||
{
|
||||
if (!m_refresh_request) return;
|
||||
|
||||
if (m_refresh_request->isDone())
|
||||
// In case of auto-connect command line parameter, select the first server asap
|
||||
if (NetworkConfig::get()->isAutoConnect() &&
|
||||
m_refreshing_server == false &&
|
||||
!ServersManager::get()->getServers().empty())
|
||||
{
|
||||
if (m_refresh_request->isSuccess())
|
||||
ServerInfoDialog *sid = new ServerInfoDialog(ServersManager::get()->getServers()[0]);
|
||||
sid->requestJoin();
|
||||
}
|
||||
|
||||
if (!m_refreshing_server) return;
|
||||
|
||||
if (ServersManager::get()->listUpdated())
|
||||
{
|
||||
m_refreshing_server = false;
|
||||
if (!ServersManager::get()->getServers().empty())
|
||||
{
|
||||
int selection = m_server_list_widget->getSelectionID();
|
||||
std::string selection_str = m_server_list_widget->getSelectionInternalName();
|
||||
|
||||
loadList();
|
||||
|
||||
loadList(0);
|
||||
// restore previous selection
|
||||
if (selection != -1 && selection_str != "spacer" && selection_str != "loading")
|
||||
if (selection != -1 && selection_str != "loading")
|
||||
m_server_list_widget->setSelectionID(selection);
|
||||
}
|
||||
else
|
||||
{
|
||||
SFXManager::get()->quickSound("anvil");
|
||||
new MessageDialog(m_refresh_request->getInfo());
|
||||
new MessageDialog(_("No server is available."));
|
||||
m_server_list_widget->clear();
|
||||
}
|
||||
delete m_refresh_request;
|
||||
m_refresh_request = NULL;
|
||||
m_reload_widget->setActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
int selection = m_server_list_widget->getSelectionID();
|
||||
std::string selection_str = m_server_list_widget->getSelectionInternalName();
|
||||
|
||||
m_server_list_widget->clear();
|
||||
|
||||
loadList();
|
||||
m_server_list_widget->addItem("spacer", L"");
|
||||
m_server_list_widget->addItem("loading",
|
||||
StringUtils::loadingDots(_("Fetching servers")));
|
||||
|
||||
// restore previous selection
|
||||
if (selection != -1 && selection_str != "spacer" && selection_str != "loading")
|
||||
m_server_list_widget->setSelectionID(selection);
|
||||
StringUtils::loadingDots(_("Fetching servers")));
|
||||
}
|
||||
|
||||
// In case of auto-connect command line parameter, select the first server asap
|
||||
if (NetworkConfig::get()->isAutoConnect() &&
|
||||
m_refresh_request == NULL &&
|
||||
m_server_list_widget->getItemCount() > 0)
|
||||
{
|
||||
ServerInfoDialog *sid = new ServerInfoDialog(/*server*/0,
|
||||
/*host id*/0, false);
|
||||
sid->requestJoin();
|
||||
}
|
||||
} // onUpdate
|
||||
|
||||
@@ -39,24 +39,21 @@ private:
|
||||
ServerSelection();
|
||||
~ServerSelection();
|
||||
|
||||
GUIEngine::IconButtonWidget * m_reload_widget;
|
||||
GUIEngine::LabelWidget * m_update_status;
|
||||
GUIEngine::ListWidget * m_server_list_widget;
|
||||
GUIEngine::IconButtonWidget* m_reload_widget;
|
||||
GUIEngine::LabelWidget* m_update_status;
|
||||
GUIEngine::ListWidget* m_server_list_widget;
|
||||
|
||||
/** \brief To check (and set) if sort order is descending **/
|
||||
bool m_sort_desc;
|
||||
bool m_sort_desc;
|
||||
|
||||
/** A pointer to the http request for getting a server list. */
|
||||
const Online::XMLRequest *m_refresh_request;
|
||||
bool m_refreshing_server;
|
||||
|
||||
|
||||
public:
|
||||
/** Load the servers into the main list.*/
|
||||
void loadList(unsigned sort_case);
|
||||
|
||||
void refresh();
|
||||
|
||||
/** Load the addons into the main list.*/
|
||||
void loadList();
|
||||
|
||||
public:
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void loadedFromFile() OVERRIDE;
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ DictionaryManager::get_dictionary(const Language& language)
|
||||
|
||||
if (language.get_country().size() > 0)
|
||||
{
|
||||
printf("Adding language fallback %s\n", language.get_language().c_str());
|
||||
Log::info("tinygettext", "Adding language fallback %s\n", language.get_language().c_str());
|
||||
dict->addFallback( &get_dictionary(Language::from_spec(language.get_language())) );
|
||||
}
|
||||
return *dict;
|
||||
|
||||
@@ -1185,11 +1185,7 @@ bool Track::loadMainTrack(const XMLNode &root)
|
||||
scene::CBatchingMesh *merged_mesh = new scene::CBatchingMesh();
|
||||
merged_mesh->addMesh(mesh);
|
||||
merged_mesh->finalize();
|
||||
#ifndef SERVER_ONLY
|
||||
tangent_mesh = merged_mesh;
|
||||
#else
|
||||
tangent_mesh = merged_mesh;
|
||||
#endif
|
||||
// The reference count of the mesh is 1, since it is in irrlicht's
|
||||
// cache. So we only have to remove it from the cache.
|
||||
irr_driver->removeMeshFromCache(mesh);
|
||||
@@ -1198,9 +1194,7 @@ bool Track::loadMainTrack(const XMLNode &root)
|
||||
{
|
||||
// SPM does the combine for you
|
||||
tangent_mesh = mesh;
|
||||
#ifndef SERVER_ONLY
|
||||
tangent_mesh->grab();
|
||||
#endif
|
||||
}
|
||||
// The merged mesh is grabbed by the octtree, so we don't need
|
||||
// to keep a reference to it.
|
||||
|
||||
@@ -61,9 +61,6 @@ void CommandLine::reportInvalidParameters()
|
||||
{
|
||||
for(unsigned int i=0; i<m_argv.size(); i++)
|
||||
{
|
||||
// invalid param needs to go to console
|
||||
UserConfigParams::m_log_errors_to_console = true;
|
||||
|
||||
Log::error("CommandLine", "Invalid parameter: %s.", m_argv[i].c_str() );
|
||||
}
|
||||
} // reportInvalidParameters
|
||||
|
||||
@@ -37,6 +37,7 @@ bool Log::m_no_colors = false;
|
||||
FILE* Log::m_file_stdout = NULL;
|
||||
std::string Log::m_prefix = "";
|
||||
size_t Log::m_buffer_size = 1;
|
||||
bool Log::m_console_log = true;
|
||||
Synchronised<std::vector<struct Log::LineInfo> > Log::m_line_buffer;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -46,6 +47,8 @@ Synchronised<std::vector<struct Log::LineInfo> > Log::m_line_buffer;
|
||||
*/
|
||||
void Log::setTerminalColor(LogLevel level)
|
||||
{
|
||||
if (!m_console_log) return;
|
||||
|
||||
if(m_no_colors) return;
|
||||
|
||||
// Thanks to funto for the colouring code!
|
||||
@@ -109,6 +112,8 @@ void Log::setTerminalColor(LogLevel level)
|
||||
*/
|
||||
void Log::resetTerminalColor()
|
||||
{
|
||||
if (!m_console_log) return;
|
||||
|
||||
if(m_no_colors) return;
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -198,32 +203,33 @@ void Log::writeLine(const char *line, int level)
|
||||
{
|
||||
|
||||
// If we don't have a console file, write to stdout and hope for the best
|
||||
if ( m_buffer_size <= 1 &&
|
||||
(!m_file_stdout || level >= LL_WARN ||
|
||||
UserConfigParams::m_log_errors_to_console) ) // log to console
|
||||
if (m_buffer_size <= 1 || !m_file_stdout)
|
||||
{
|
||||
setTerminalColor((LogLevel)level);
|
||||
#ifdef ANDROID
|
||||
android_LogPriority alp;
|
||||
switch (level)
|
||||
if (m_console_log)
|
||||
{
|
||||
// STK is using the levels slightly different from android
|
||||
// (debug lowest, verbose above it; while android reverses
|
||||
// this order. So to get the same behaviour (e.g. filter
|
||||
// out debug message, but still get verbose, we swap
|
||||
// the order here.
|
||||
case LL_VERBOSE: alp = ANDROID_LOG_DEBUG; break;
|
||||
case LL_DEBUG: alp = ANDROID_LOG_VERBOSE; break;
|
||||
case LL_INFO: alp = ANDROID_LOG_INFO; break;
|
||||
case LL_WARN: alp = ANDROID_LOG_WARN; break;
|
||||
case LL_ERROR: alp = ANDROID_LOG_ERROR; break;
|
||||
case LL_FATAL: alp = ANDROID_LOG_FATAL; break;
|
||||
default: alp = ANDROID_LOG_FATAL;
|
||||
}
|
||||
__android_log_print(alp, "SuperTuxKart", "%s", line);
|
||||
#ifdef ANDROID
|
||||
android_LogPriority alp;
|
||||
switch (level)
|
||||
{
|
||||
// STK is using the levels slightly different from android
|
||||
// (debug lowest, verbose above it; while android reverses
|
||||
// this order. So to get the same behaviour (e.g. filter
|
||||
// out debug message, but still get verbose, we swap
|
||||
// the order here.
|
||||
case LL_VERBOSE: alp = ANDROID_LOG_DEBUG; break;
|
||||
case LL_DEBUG: alp = ANDROID_LOG_VERBOSE; break;
|
||||
case LL_INFO: alp = ANDROID_LOG_INFO; break;
|
||||
case LL_WARN: alp = ANDROID_LOG_WARN; break;
|
||||
case LL_ERROR: alp = ANDROID_LOG_ERROR; break;
|
||||
case LL_FATAL: alp = ANDROID_LOG_FATAL; break;
|
||||
default: alp = ANDROID_LOG_FATAL;
|
||||
}
|
||||
__android_log_print(alp, "SuperTuxKart", "%s", line);
|
||||
#else
|
||||
printf("%s", line);
|
||||
printf("%s", line);
|
||||
#endif
|
||||
}
|
||||
resetTerminalColor(); // this prints a \n
|
||||
}
|
||||
|
||||
@@ -241,6 +247,12 @@ void Log::writeLine(const char *line, int level)
|
||||
#endif
|
||||
} // _fluhBuffers
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void Log::toggleConsoleLog(bool val)
|
||||
{
|
||||
m_console_log = val;
|
||||
} // toggleConsoleLog
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Flushes all stored log messages to the various output devices (thread safe).
|
||||
*/
|
||||
|
||||
@@ -60,6 +60,9 @@ private:
|
||||
/** If set this will disable coloring of log messages. */
|
||||
static bool m_no_colors;
|
||||
|
||||
/** If false that logging will only be saved to a file. */
|
||||
static bool m_console_log;
|
||||
|
||||
/** The file where stdout output will be written */
|
||||
static FILE* m_file_stdout;
|
||||
|
||||
@@ -117,6 +120,7 @@ public:
|
||||
|
||||
static void closeOutputFiles();
|
||||
static void flushBuffers();
|
||||
static void toggleConsoleLog(bool val);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the number of lines to buffer. Setting the buffer size to a
|
||||
|
||||
404
src/utils/separate_process.cpp
Normal file
404
src/utils/separate_process.cpp
Normal file
@@ -0,0 +1,404 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2018 Joerg Henrichs
|
||||
//
|
||||
// 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 "utils/separate_process.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "utils/log.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <iostream>
|
||||
# include <unistd.h>
|
||||
# include <signal.h>
|
||||
# include <sys/wait.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
std::string SeparateProcess::getCurrentExecutableLocation()
|
||||
{
|
||||
#ifdef WIN32
|
||||
HMODULE moudle = GetModuleHandle(NULL);
|
||||
char path[1024];
|
||||
if (GetModuleFileNameA(moudle, path, 1024) < 1024)
|
||||
return file_manager->getFileSystem()->getAbsolutePath(path).c_str();
|
||||
return "";
|
||||
#elif defined (__APPLE__)
|
||||
char path[1024];
|
||||
unsigned buf_size = 1024;
|
||||
if (_NSGetExecutablePath(path, &buf_size) == 0)
|
||||
{
|
||||
return file_manager->getFileSystem()->getAbsolutePath(path).c_str();
|
||||
}
|
||||
return "";
|
||||
#else
|
||||
// Assume Linux
|
||||
return file_manager->getFileSystem()->getAbsolutePath("/proc/self/exe")
|
||||
.c_str();
|
||||
#endif
|
||||
} // getCurrentExecutableLocation
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
SeparateProcess::SeparateProcess(const std::string& exe,
|
||||
const std::string& argument, bool create_pipe)
|
||||
{
|
||||
if (!createChildProcess(exe, argument, create_pipe))
|
||||
{
|
||||
Log::fatal("SeparateProcess", "Failed to run %s %s",
|
||||
exe.c_str(), argument.c_str());
|
||||
return;
|
||||
}
|
||||
} // SeparateProcess
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
SeparateProcess::~SeparateProcess()
|
||||
{
|
||||
bool dead = false;
|
||||
#ifdef WIN32
|
||||
std::string class_name = "separate_process";
|
||||
class_name += StringUtils::toString(m_child_pid);
|
||||
HWND hwnd = FindWindowEx(HWND_MESSAGE, NULL, &class_name[0], NULL);
|
||||
if (hwnd != NULL)
|
||||
{
|
||||
PostMessage(hwnd, WM_DESTROY, NULL, NULL);
|
||||
if (WaitForSingleObject(m_child_handle, 5000) != WAIT_TIMEOUT)
|
||||
{
|
||||
dead = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dead)
|
||||
{
|
||||
Log::info("SeparateProcess", "Timeout waiting for child process to "
|
||||
"self-destroying, killing it anyway");
|
||||
if (TerminateProcess(m_child_handle, 0) == 0)
|
||||
Log::warn("SeparateProcess", "Failed to kill child process.");
|
||||
}
|
||||
if (CloseHandle(m_child_handle) == 0)
|
||||
Log::warn("SeparateProcess", "Failed to close child process handle.");
|
||||
#else
|
||||
if (m_child_stdin_write != -1 && m_child_stdout_read != -1)
|
||||
{
|
||||
close(m_child_stdin_write);
|
||||
close(m_child_stdout_read);
|
||||
}
|
||||
kill(m_child_pid, SIGTERM);
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
int status;
|
||||
if (waitpid(m_child_pid, &status, WNOHANG) == m_child_pid)
|
||||
{
|
||||
dead = true;
|
||||
break;
|
||||
}
|
||||
StkTime::sleep(1000);
|
||||
}
|
||||
if (!dead)
|
||||
{
|
||||
Log::info("SeparateProcess", "Timeout waiting for child process to "
|
||||
"self-destroying, killing it anyway");
|
||||
kill(m_child_pid, SIGKILL);
|
||||
}
|
||||
#endif
|
||||
Log::info("SeparateProcess", "Destroyed");
|
||||
} // ~SeparateProcess
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Starts separate as a child process
|
||||
* and sets up communication via pipes.
|
||||
* \return True if the child process creation was successful.
|
||||
*/
|
||||
#ifdef WIN32
|
||||
bool SeparateProcess::createChildProcess(const std::string& exe,
|
||||
const std::string& argument,
|
||||
bool create_pipe)
|
||||
{
|
||||
// Based on: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
|
||||
SECURITY_ATTRIBUTES sec_attr;
|
||||
|
||||
// Set the bInheritHandle flag so pipe handles are inherited.
|
||||
sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
sec_attr.bInheritHandle = TRUE;
|
||||
sec_attr.lpSecurityDescriptor = NULL;
|
||||
|
||||
// Create a pipe for the child process's STDOUT if needed.
|
||||
if (create_pipe)
|
||||
{
|
||||
if (!CreatePipe(&m_child_stdout_read, &m_child_stdout_write, &sec_attr, 0))
|
||||
{
|
||||
Log::error("SeparateProcess", "Error creating StdoutRd CreatePipe");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the read handle to the pipe for STDOUT is not inherited.
|
||||
if (!SetHandleInformation(m_child_stdout_read, HANDLE_FLAG_INHERIT, 0))
|
||||
{
|
||||
Log::error("SeparateProcess", "Stdout SetHandleInformation");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a pipe for the child process's STDIN.
|
||||
if (!CreatePipe(&m_child_stdin_read, &m_child_stdin_write, &sec_attr, 0))
|
||||
{
|
||||
Log::error("SeparateProcess", "Stdin CreatePipe");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the write handle to the pipe for STDIN is not inherited.
|
||||
if (!SetHandleInformation(m_child_stdin_write, HANDLE_FLAG_INHERIT, 0))
|
||||
{
|
||||
Log::error("SeparateProcess", "Stdin SetHandleInformation");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PROCESS_INFORMATION piProcInfo;
|
||||
STARTUPINFO siStartInfo;
|
||||
|
||||
// Set up members of the PROCESS_INFORMATION structure.
|
||||
|
||||
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
// Set up members of the STARTUPINFO structure.
|
||||
// This structure specifies the STDIN and STDOUT handles for redirection.
|
||||
|
||||
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
|
||||
if (create_pipe)
|
||||
{
|
||||
siStartInfo.cb = sizeof(STARTUPINFO);
|
||||
siStartInfo.hStdError = m_child_stdout_write;
|
||||
siStartInfo.hStdOutput = m_child_stdout_write;
|
||||
siStartInfo.hStdInput = m_child_stdin_read;
|
||||
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
|
||||
}
|
||||
|
||||
// Create the child process.
|
||||
std::string cmd = exe + argument + " --parent-process=" +
|
||||
StringUtils::toString(GetCurrentProcessId());
|
||||
bool success = CreateProcess(NULL,
|
||||
&cmd[0], // command line
|
||||
NULL, // process security attributes
|
||||
NULL, // primary thread security attributes
|
||||
TRUE, // handles are inherited
|
||||
CREATE_NO_WINDOW, // creation flags
|
||||
NULL, // use parent's environment
|
||||
NULL, // use parent's current directory
|
||||
&siStartInfo, // STARTUPINFO pointer
|
||||
&piProcInfo) != 0; // receives PROCESS_INFORMATION
|
||||
|
||||
if (!success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_child_handle = piProcInfo.hProcess;
|
||||
m_child_pid = piProcInfo.dwProcessId;
|
||||
if (m_child_pid == 0)
|
||||
{
|
||||
Log::warn("SeparateProcess", "Invalid child pid.");
|
||||
return false;
|
||||
}
|
||||
if (CloseHandle(piProcInfo.hThread) == 0)
|
||||
Log::warn("SeparateProcess", "Failed to close child thread handle.");
|
||||
|
||||
return true;
|
||||
} // createChildProcess - windows version
|
||||
|
||||
#else // linux and osx
|
||||
|
||||
bool SeparateProcess::createChildProcess(const std::string& exe,
|
||||
const std::string& argument,
|
||||
bool create_pipe)
|
||||
{
|
||||
const int PIPE_READ=0;
|
||||
const int PIPE_WRITE=1;
|
||||
int stdin_pipe[2];
|
||||
int stdout_pipe[2];
|
||||
int child;
|
||||
|
||||
if (create_pipe)
|
||||
{
|
||||
if (pipe(stdin_pipe) < 0)
|
||||
{
|
||||
Log::error("SeparateProcess", "Can't allocate pipe for input "
|
||||
"redirection.");
|
||||
return -1;
|
||||
}
|
||||
if (pipe(stdout_pipe) < 0)
|
||||
{
|
||||
close(stdin_pipe[PIPE_READ]);
|
||||
close(stdin_pipe[PIPE_WRITE]);
|
||||
Log::error("SeparateProcess", "allocating pipe for child output "
|
||||
"redirect");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
child = fork();
|
||||
if (child == 0)
|
||||
{
|
||||
// Child process:
|
||||
Log::info("SeparateProcess", "Child process started.");
|
||||
|
||||
if (create_pipe)
|
||||
{
|
||||
// redirect stdin
|
||||
if (dup2(stdin_pipe[PIPE_READ], STDIN_FILENO) == -1)
|
||||
{
|
||||
Log::error("SeparateProcess", "Redirecting stdin");
|
||||
return false;
|
||||
}
|
||||
|
||||
// redirect stdout
|
||||
if (dup2(stdout_pipe[PIPE_WRITE], STDOUT_FILENO) == -1)
|
||||
{
|
||||
Log::error("SeparateProcess", "Redirecting stdout");
|
||||
return false;
|
||||
}
|
||||
|
||||
// all these are for use by parent only
|
||||
close(stdin_pipe[PIPE_READ]);
|
||||
close(stdin_pipe[PIPE_WRITE]);
|
||||
close(stdout_pipe[PIPE_READ]);
|
||||
close(stdout_pipe[PIPE_WRITE]);
|
||||
}
|
||||
|
||||
// run child process image
|
||||
std::vector<char*> argv;
|
||||
const std::string exe_file = StringUtils::getBasename(exe);
|
||||
auto rest_argv = StringUtils::split(argument, ' ');
|
||||
argv.push_back(const_cast<char*>(exe_file.c_str()));
|
||||
for (unsigned i = 0; i < rest_argv.size(); i++)
|
||||
argv.push_back(const_cast<char*>(rest_argv[i].c_str()));
|
||||
argv.push_back(NULL);
|
||||
execvp(exe.c_str(), argv.data());
|
||||
Log::error("SeparateProcess", "Error in execl: errnp %d", errno);
|
||||
|
||||
// if we get here at all, an error occurred, but we are in the child
|
||||
// process, so just exit
|
||||
perror("SeparateProcess: execl error");
|
||||
exit(-1);
|
||||
}
|
||||
else if (child > 0)
|
||||
{
|
||||
m_child_pid = child;
|
||||
if (create_pipe)
|
||||
{
|
||||
// parent continues here
|
||||
// close unused file descriptors, these are for child only
|
||||
close(stdin_pipe[PIPE_READ]);
|
||||
close(stdout_pipe[PIPE_WRITE]);
|
||||
m_child_stdin_write = stdin_pipe[PIPE_WRITE];
|
||||
m_child_stdout_read = stdout_pipe[PIPE_READ];
|
||||
}
|
||||
}
|
||||
else // child < 0
|
||||
{
|
||||
if (create_pipe)
|
||||
{
|
||||
// failed to create child
|
||||
close(stdin_pipe[PIPE_READ]);
|
||||
close(stdin_pipe[PIPE_WRITE]);
|
||||
close(stdout_pipe[PIPE_READ]);
|
||||
close(stdout_pipe[PIPE_WRITE]);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} // createChildProcess
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Reads a command from the input pipe.
|
||||
*/
|
||||
std::string SeparateProcess::getLine()
|
||||
{
|
||||
#define BUFSIZE 1024
|
||||
char buffer[BUFSIZE];
|
||||
|
||||
#ifdef WIN32
|
||||
DWORD bytes_read;
|
||||
// Read from pipe that is the standard output for child process.
|
||||
bool success = ReadFile(m_child_stdout_read, buffer, BUFSIZE-1,
|
||||
&bytes_read, NULL)!=0;
|
||||
if (success && bytes_read < BUFSIZE)
|
||||
{
|
||||
buffer[bytes_read] = 0;
|
||||
std::string s = buffer;
|
||||
return s;
|
||||
}
|
||||
#else
|
||||
//std::string s;
|
||||
//std::getline(std::cin, s);
|
||||
//return s;
|
||||
|
||||
int bytes_read = read(m_child_stdout_read, buffer, BUFSIZE-1);
|
||||
if(bytes_read>0)
|
||||
{
|
||||
buffer[bytes_read] = 0;
|
||||
std::string s = buffer;
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
return std::string("");
|
||||
} // getLine
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sends a command to the SeparateProcess via a pipe, and reads the answer.
|
||||
* \return Answer from SeparateProcess.
|
||||
*/
|
||||
std::string SeparateProcess::sendCommand(const std::string &command)
|
||||
{
|
||||
#ifdef WIN32
|
||||
// Write to the pipe that is the standard input for a child process.
|
||||
// Data is written to the pipe's buffers, so it is not necessary to wait
|
||||
// until the child process is running before writing data.
|
||||
DWORD bytes_written;
|
||||
bool success = WriteFile(m_child_stdin_write, command.c_str(),
|
||||
unsigned(command.size()) + 1, &bytes_written, NULL) != 0;
|
||||
#else
|
||||
write(m_child_stdin_write, (command+"\n").c_str(), command.size()+1);
|
||||
#endif
|
||||
return getLine();
|
||||
|
||||
return std::string("");
|
||||
} // sendCommand
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** All answer strings from SeparateProcess are in the form: "length string",
|
||||
* i.e. the length of the string, followed by a space and then the actual
|
||||
* strings. This allows for checking on some potential problems (e.g. if a
|
||||
* pipe should only send part of the answer string - todo: handle this problem
|
||||
* instead of ignoring it.
|
||||
*/
|
||||
std::string SeparateProcess::decodeString(const std::string &s)
|
||||
{
|
||||
std::vector<std::string> l = StringUtils::split(s, ' ');
|
||||
if (l.size() != 2) return "INVALID ANSWER - wrong number of fields";
|
||||
|
||||
int n;
|
||||
StringUtils::fromString(l[0], n);
|
||||
if (n != (int)l[1].size()) return "INVALID ANSWER - incorrect length";
|
||||
|
||||
return l[1];
|
||||
|
||||
} // decodeString
|
||||
66
src/utils/separate_process.hpp
Normal file
66
src/utils/separate_process.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2018 Joerg Henrichs
|
||||
//
|
||||
// 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_SEPERATE_PROCESS_HPP
|
||||
#define HEADER_SEPERATE_PROCESS_HPP
|
||||
|
||||
#ifdef WIN32
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string>
|
||||
|
||||
class SeparateProcess
|
||||
{
|
||||
private:
|
||||
#ifdef WIN32
|
||||
// Various handles for the window pipes
|
||||
HANDLE m_child_stdin_read;
|
||||
HANDLE m_child_stdin_write;
|
||||
HANDLE m_child_stdout_read;
|
||||
HANDLE m_child_stdout_write;
|
||||
HANDLE m_child_handle;
|
||||
DWORD m_child_pid;
|
||||
#else
|
||||
int m_child_stdin_write = -1;
|
||||
int m_child_stdout_read = -1;
|
||||
int m_child_pid = -1;
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
bool createChildProcess(const std::string& exe,
|
||||
const std::string& argument, bool create_pipe);
|
||||
// ------------------------------------------------------------------------
|
||||
std::string getLine();
|
||||
|
||||
public:
|
||||
// ------------------------------------------------------------------------
|
||||
static std::string getCurrentExecutableLocation();
|
||||
// ------------------------------------------------------------------------
|
||||
SeparateProcess(const std::string& exe, const std::string& argument,
|
||||
bool create_pipe = false);
|
||||
// ------------------------------------------------------------------------
|
||||
~SeparateProcess();
|
||||
// ------------------------------------------------------------------------
|
||||
std::string sendCommand(const std::string &command);
|
||||
// ------------------------------------------------------------------------
|
||||
std::string decodeString(const std::string &s);
|
||||
|
||||
}; // class SeparateProcess
|
||||
|
||||
#endif // HEADER_SEPERATE_PROCESS_HPP
|
||||
@@ -679,7 +679,8 @@ namespace StringUtils
|
||||
std::ostringstream output;
|
||||
for(unsigned int i=0; i<s.size(); i++)
|
||||
{
|
||||
if (s[i] >= 128 || s[i] == '&' || s[i] == '<' || s[i] == '>' || s[i] == '\"')
|
||||
if (s[i] >= 128 || s[i] == '&' || s[i] == '<' || s[i] == '>' ||
|
||||
s[i] == '\"' || s[i] == ' ')
|
||||
{
|
||||
output << "&#x" << std::hex << std::uppercase << s[i] << ";";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user