Merge remote-tracking branch 'origin/network_improvements' into game_protocol

This commit is contained in:
hiker
2018-03-31 00:38:57 +11:00
66 changed files with 1658 additions and 958 deletions

View File

@@ -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" >

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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
// ----------------------------------------------------------------------------

View File

@@ -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. */

View File

@@ -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;

View File

@@ -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");

View File

@@ -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;

View File

@@ -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",

View File

@@ -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());

View File

@@ -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
//-----------------------------------------------------------------------------

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -416,3 +416,13 @@ void IconButtonWidget::setLabelFont()
}
}
}
// -----------------------------------------------------------------------------
void IconButtonWidget::setVisible(bool visible)
{
Widget::setVisible(visible);
if (m_label != NULL)
m_label->setVisible(visible);
}

View File

@@ -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;
}
};
}

View File

@@ -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();

View File

@@ -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)

View File

@@ -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
//-----------------------------------------------------------------------------

View File

@@ -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();

View File

@@ -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>

View File

@@ -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
// ----------------------------------------------------------------------------

View File

@@ -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

View File

@@ -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

View File

@@ -210,7 +210,6 @@ void ClientLobby::leave()
m_server->disconnect();
STKHost::get()->removePeer(m_server);
m_server_address.clear();
ServersManager::get()->unsetJoinedServer();
} // leave
//-----------------------------------------------------------------------------

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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.");

View File

@@ -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;
}

View File

@@ -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
//-----------------------------------------------------------------------------

View File

@@ -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

View File

@@ -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;

View File

@@ -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());

View File

@@ -83,6 +83,7 @@ private:
void finishedLoadingWorldClient(Event *event);
void startedRaceOnClient(Event *event);
void unregisterServer();
void createServerIdFile();
public:
ServerLobby();
virtual ~ServerLobby();

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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());

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -89,7 +89,7 @@ private:
} // TransportAddress(const TransportAddress&)
public:
// ------------------------------------------------------------------------
bool isPublicAddressLAN() const;
bool isPublicAddressLocalhost() const;
// ------------------------------------------------------------------------
bool isLAN() const;
// ------------------------------------------------------------------------

View File

@@ -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())
{

View File

@@ -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);

View File

@@ -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,

View File

@@ -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
// ----------------------------------------------------------------------------

View File

@@ -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

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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")
{

View File

@@ -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,

View File

@@ -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
// ----------------------------------------------------------------------------

View File

@@ -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,

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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.

View File

@@ -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

View File

@@ -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).
*/

View File

@@ -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

View 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

View 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

View File

@@ -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] << ";";
}