Merge branch 'master' of github.com:supertuxkart/stk-code

This commit is contained in:
hiker 2018-04-20 17:59:59 +10:00
commit 42d21ba9f9
76 changed files with 1352 additions and 712 deletions

View File

@ -23,10 +23,13 @@
<buttonbar id="menu_toprow" proportion="3" width="90%" align="center">
<icon-button id="lan" width="128" height="128"
icon="gui/menu_multi.png" focus_icon="gui/menu_multi_focus.png"
I18N="Networking menu button" text="Local Networking"/>
I18N="Networking menu button" text="Local networking"/>
<icon-button id="wan" width="128" height="128"
icon="gui/menu_multi.png" focus_icon="gui/menu_multi_focus.png"
I18N="Networking menu button" text="Global Networking"/>
I18N="Networking menu button" text="Global networking"/>
<icon-button id="enter-address" width="128" height="128"
icon="gui/online/menu_quick_play.png" focus_icon="gui/online/menu_quick_play_hover.png"
I18N="Networking menu button" text="Enter server address"/>
<icon-button id="online" width="128" height="128"
icon="gui/menu_online.png" focus_icon="gui/menu_online_focus.png"
I18N="Networking menu button" text="Your profile"/>

View File

@ -9,6 +9,10 @@
Older versions will be ignored. -->
<track-version min="6" max="7"/>
<!-- Minimum and maxium server versions that be be read by this binary.
Older versions will be ignored. -->
<server-version min="1" max="1"/>
<!-- Maximum number of karts to be used at the same time. This limit
can easily be increased, but some tracks might not have valid start
positions for those additional karts. -->

View File

@ -141,6 +141,8 @@ void STKConfig::load(const std::string &filename)
CHECK_NEG(m_max_kart_version, "<kart-version max=...>" );
CHECK_NEG(m_min_track_version, "min-track-version" );
CHECK_NEG(m_max_track_version, "max-track-version" );
CHECK_NEG(m_min_server_version, "min-server-version" );
CHECK_NEG(m_max_server_version, "max-server-version" );
CHECK_NEG(m_skid_fadeout_time, "skid-fadeout-time" );
CHECK_NEG(m_near_ground, "near-ground" );
CHECK_NEG(m_delay_finish_time, "delay-finish-time" );
@ -187,6 +189,8 @@ void STKConfig::init_defaults()
m_max_kart_version = -100;
m_min_track_version = -100;
m_max_track_version = -100;
m_min_server_version = -100;
m_max_server_version = -100;
m_max_display_news = -100;
m_replay_max_time = -100;
m_replay_delta_angle = -100;
@ -233,6 +237,12 @@ void STKConfig::getAllData(const XMLNode * root)
node->get("max", &m_max_track_version);
}
if(const XMLNode *node = root->getNode("server-version"))
{
node->get("min", &m_min_server_version);
node->get("max", &m_max_server_version);
}
if(const XMLNode *kart_node = root->getNode("karts"))
kart_node->get("max-number", &m_max_karts);

View File

@ -117,6 +117,8 @@ public:
m_max_kart_version; /**<version supported by this binary. */
int m_min_track_version, /**<The minimum and maximum .track file */
m_max_track_version; /**<version supported by this binary. */
int m_min_server_version, /**<The minimum and maximum server */
m_max_server_version; /**<version supported by this binary. */
int m_max_display_news; /**<How often a news message is displayed
before it is ignored. */

View File

@ -708,7 +708,7 @@ namespace UserConfigParams
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",
PARAM_DEFAULT(BoolUserConfigParam(true, "random-ports",
&m_network_group, "Use random ports for client and server connection"));
PARAM_PREFIX BoolUserConfigParam m_lobby_chat
PARAM_DEFAULT(BoolUserConfigParam(false, "lobby-chat",

View File

@ -29,6 +29,7 @@
#include "graphics/sp/sp_per_object_uniform.hpp"
#include "graphics/sp/sp_shader_manager.hpp"
#include "graphics/sp/sp_uniform_assigner.hpp"
#include "network/rewind_manager.hpp"
#include "physics/btKart.hpp"
#include "utils/mini_glm.hpp"
@ -75,7 +76,7 @@ void SkidMarks::update(float dt, bool force_skid_marks,
video::SColor* custom_color)
{
//if the kart is gnu, then don't skid because he floats!
if(m_kart.isWheeless())
if (m_kart.isWheeless() || RewindManager::get()->isRewinding())
return;
float f = dt / stk_config->m_skid_fadeout_time;

View File

@ -137,7 +137,14 @@ public:
return m_texture_trans;
}
// ------------------------------------------------------------------------
void setUpdateOffset(int offset) { m_update_offset = offset; }
void setUpdateOffset(int offset)
{
// Avoid skipping of vertex buffer update if this function is called
// more than once per frame
if (m_update_offset != -1 && offset > m_update_offset)
return;
m_update_offset = offset;
}
// ------------------------------------------------------------------------
bool isVisible() const { return m_visible; }
// ------------------------------------------------------------------------

View File

@ -37,6 +37,7 @@ const std::map<std::string, std::pair<unsigned, SamplerType> >
{ "skinning_tex", { 0, ST_TEXTURE_BUFFER } }
#endif
};
bool SPShader::m_sp_shader_debug = false;
// ----------------------------------------------------------------------------
void SPShader::addShaderFile(const std::string& name, GLint shader_type,
@ -226,20 +227,20 @@ void SPShader::addAllUniforms(RenderPass rp)
GLenum type;
char name[100] = {};
glGetActiveUniform(m_program[rp], i, 99, NULL, &size, &type, name);
if (size != 1)
if (size != 1 && m_sp_shader_debug)
{
Log::debug("SPShader", "Array of uniforms is not supported in"
" shader %s for %s.", m_name.c_str(), name);
continue;
}
auto ret = supported_types.find(type);
if (ret == supported_types.end())
if (ret == supported_types.end() && m_sp_shader_debug)
{
Log::debug("SPShader", "%d type not supported", (unsigned)type);
continue;
}
GLuint location = glGetUniformLocation(m_program[rp], name);
if (location == GL_INVALID_INDEX)
if (location == GL_INVALID_INDEX && m_sp_shader_debug)
{
Log::debug("SPShader", "%s uniform not found", name);
continue;

View File

@ -111,6 +111,8 @@ private:
const std::array<bool, 6> m_srgb;
public:
// ------------------------------------------------------------------------
static bool m_sp_shader_debug;
// ------------------------------------------------------------------------
SPShader(const std::string& name,
const std::function<void(SPShader*)>& init_func,

View File

@ -52,7 +52,7 @@ void AbstractStateManager::enterGameState()
if (getCurrentScreen() != NULL) getCurrentScreen()->tearDown();
m_menu_stack.clear();
m_menu_stack.push_back(RACE_STATE_NAME);
m_menu_stack.emplace_back(RACE_STATE_NAME, (Screen*)NULL);
setGameState(GAME);
GUIEngine::cleanForGame();
} // enterGameState
@ -83,7 +83,7 @@ void AbstractStateManager::setGameState(GameState state)
#pragma mark Push/pop menus
#endif
void AbstractStateManager::pushMenu(std::string name)
void AbstractStateManager::pushMenu(Screen* screen)
{
// currently, only a single in-game menu is supported
assert(m_game_mode != INGAME_MENU);
@ -94,14 +94,14 @@ void AbstractStateManager::pushMenu(std::string name)
if (UserConfigParams::logGUI())
{
Log::info("AbstractStateManager::pushMenu", "Switching to screen %s",
name.c_str());
screen->getName().c_str());
}
// Send tear-down event to previous menu
if (m_menu_stack.size() > 0 && m_game_mode != GAME)
getCurrentScreen()->tearDown();
m_menu_stack.push_back(name);
m_menu_stack.emplace_back(screen->getName(), screen);
if (m_game_mode == GAME)
{
setGameState(INGAME_MENU);
@ -110,7 +110,7 @@ void AbstractStateManager::pushMenu(std::string name)
{
setGameState(MENU);
}
switchToScreen(name.c_str());
switchToScreen(screen);
onTopMostScreenChanged();
} // pushMenu
@ -130,7 +130,7 @@ void AbstractStateManager::pushScreen(Screen* screen)
}
if (!screen->isLoaded()) screen->loadFromFile();
pushMenu(screen->getName());
pushMenu(screen);
screen->init();
onTopMostScreenChanged();
@ -162,9 +162,9 @@ void AbstractStateManager::replaceTopMostScreen(Screen* screen, GUIEngine::GameS
if (getCurrentScreen() != NULL)
getCurrentScreen()->tearDown();
m_menu_stack[m_menu_stack.size()-1] = name;
m_menu_stack[m_menu_stack.size()-1] = std::make_pair(name, screen);
setGameState(gameState);
switchToScreen(name.c_str());
switchToScreen(screen);
// Send init event to new menu
getCurrentScreen()->init();
@ -187,7 +187,7 @@ void AbstractStateManager::reshowTopMostMenu()
if (currScreen != NULL) getCurrentScreen()->tearDown();
}
switchToScreen( m_menu_stack[m_menu_stack.size()-1].c_str() );
switchToScreen(m_menu_stack[m_menu_stack.size()-1].second);
// Send init event to new menu
Screen* screen = getCurrentScreen();
@ -216,10 +216,10 @@ void AbstractStateManager::popMenu()
if (UserConfigParams::logGUI())
{
Log::info("AbstractStateManager::popMenu", "Switching to screen %s",
m_menu_stack[m_menu_stack.size()-1].c_str());
m_menu_stack[m_menu_stack.size()-1].first.c_str());
}
if (m_menu_stack[m_menu_stack.size()-1] == RACE_STATE_NAME)
if (m_menu_stack[m_menu_stack.size()-1].first == RACE_STATE_NAME)
{
setGameState(GAME);
GUIEngine::cleanForGame();
@ -227,7 +227,7 @@ void AbstractStateManager::popMenu()
else
{
setGameState(MENU);
switchToScreen(m_menu_stack[m_menu_stack.size()-1].c_str());
switchToScreen(m_menu_stack[m_menu_stack.size()-1].second);
Screen* screen = getCurrentScreen();
if (!screen->isLoaded()) screen->loadFromFile();
@ -254,10 +254,10 @@ void AbstractStateManager::resetAndGoToScreen(Screen* screen)
m_menu_stack.clear();
if (!screen->isLoaded()) screen->loadFromFile();
m_menu_stack.push_back(name);
m_menu_stack.emplace_back(name, screen);
setGameState(MENU);
switchToScreen(name.c_str());
switchToScreen(screen);
getCurrentScreen()->init();
onTopMostScreenChanged();
@ -277,12 +277,12 @@ void AbstractStateManager::resetAndSetStack(Screen* screens[])
for (int n=0; screens[n] != NULL; n++)
{
m_menu_stack.push_back(screens[n]->getName());
m_menu_stack.emplace_back(screens[n]->getName(), screens[n]);
}
setGameState(MENU);
switchToScreen(m_menu_stack[m_menu_stack.size()-1].c_str());
switchToScreen(m_menu_stack[m_menu_stack.size()-1].second);
getCurrentScreen()->init();
onTopMostScreenChanged();

View File

@ -59,11 +59,11 @@ namespace GUIEngine
/**
* This stack will contain menu names (e.g. main.stkgui),
* and/or 'race'.
* and/or 'race' with screen instance pointer.
*/
std::vector<std::string> m_menu_stack;
std::vector<std::pair<std::string, Screen*> > m_menu_stack;
void pushMenu(std::string name);
void pushMenu(Screen* screen);
void setGameState(GameState state);
@ -133,10 +133,10 @@ namespace GUIEngine
T* instance = T::getInstance();
m_menu_stack.push_back(instance->getName());
m_menu_stack.emplace_back(instance->getName(), instance);
setGameState(MENU);
switchToScreen(instance->getName().c_str());
switchToScreen(instance);
getCurrentScreen()->init();
onTopMostScreenChanged();

View File

@ -882,7 +882,7 @@ namespace GUIEngine
// ------------------------------------------------------------------------
void switchToScreen(const char* screen_name)
void switchToScreen(Screen* screen)
{
needsUpdate.clearWithoutDeleting();
@ -893,12 +893,12 @@ namespace GUIEngine
Widget::resetIDCounters();
// check if we already loaded this screen
const int screen_amount = g_loaded_screens.size();
for(int n=0; n<screen_amount; n++)
Screen* loaded_screen;
for_in (loaded_screen, g_loaded_screens)
{
if (g_loaded_screens[n].getName() == screen_name)
if (loaded_screen == screen)
{
g_current_screen = g_loaded_screens.get(n);
g_current_screen = loaded_screen;
break;
}
}
@ -925,20 +925,21 @@ namespace GUIEngine
// ------------------------------------------------------------------------
void removeScreen(const char* name)
void removeScreen(Screen* screen)
{
const int screen_amount = g_loaded_screens.size();
for(int n=0; n<screen_amount; n++)
int n = 0;
Screen* loaded_screen;
for_in (loaded_screen, g_loaded_screens)
{
if (g_loaded_screens[n].getName() == name)
if (loaded_screen == screen)
{
g_current_screen = g_loaded_screens.get(n);
g_current_screen->unload();
delete g_current_screen;
screen->unload();
delete screen;
g_current_screen = NULL;
g_loaded_screens.remove(n);
break;
}
n++;
}
}

View File

@ -199,12 +199,12 @@ namespace GUIEngine
/** \brief Add a screen to the list of screens known by the gui engine */
void addScreenToList(Screen* screen);
/** \brief Remove a screen from the list of screens known by the gui engine */
void removeScreen(const char* name);
void removeScreen(Screen* screen);
/** \brief Low-level mean to change current screen.
* \note Do not use directly. Use a state manager instead to get higher-level functionnality.
*/
void switchToScreen(const char* );
void switchToScreen(Screen* screen);
/** \brief erases the currently displayed screen, removing all added irrLicht widgets
* \note Do not use directly. Use a state manager instead to get higher-level functionnality.

View File

@ -269,13 +269,7 @@ void Attachment::saveState(BareNetworkString *buffer) const
void Attachment::rewindTo(BareNetworkString *buffer)
{
uint8_t type = buffer->getUInt8();
AttachmentType new_type = AttachmentType(type & 0x7f); // mask out bit 7
// FIXME Sometimes type == 255 is returned, reason unknown
if (new_type > ATTACH_NOTHING)
{
return;
}
// If there is no attachment, clear the attachment if necessary and exit
if(new_type==ATTACH_NOTHING)

View File

@ -25,6 +25,7 @@
#include "karts/kart_properties.hpp"
#include "karts/controller/ai_properties.hpp"
#include "modes/world.hpp"
#include "network/network_string.hpp"
#include "tracks/track.hpp"
#include "utils/constants.hpp"
@ -328,3 +329,18 @@ void AIBaseController::determineTurnRadius(const Vec3 &end, Vec3 *center,
}
} // determineTurnRadius
//-----------------------------------------------------------------------------
void AIBaseController::saveState(BareNetworkString *buffer) const
{
// Endcontroller needs this for proper offset in kart rewinder
buffer->addUInt32(0).addUInt32(0).addUInt32(0);
} // copyToBuffer
//-----------------------------------------------------------------------------
void AIBaseController::rewindTo(BareNetworkString *buffer)
{
// Endcontroller needs this for proper offset in kart rewinder
// Skip 3 uint32_t
buffer->skip(3 * 4);
} // rewindTo

View File

@ -104,9 +104,8 @@ public:
};
virtual void skidBonusTriggered() {};
// ------------------------------------------------------------------------
/** Not used for AIs. */
virtual void saveState(BareNetworkString *buffer) const OVERRIDE {}
virtual void rewindTo(BareNetworkString *buffer) OVERRIDE {}
virtual void saveState(BareNetworkString *buffer) const OVERRIDE;
virtual void rewindTo(BareNetworkString *buffer) OVERRIDE;
}; // AIBaseController

View File

@ -161,10 +161,11 @@ bool LocalPlayerController::action(PlayerAction action, int value,
NetworkConfig::get()->isClient() &&
!RewindManager::get()->isRewinding() )
{
GameProtocol::lock()
->controllerAction(m_kart->getWorldKartId(),
action, value,
m_steer_val_l, m_steer_val_r);
if (auto gp = GameProtocol::lock())
{
gp->controllerAction(m_kart->getWorldKartId(), action, value,
m_steer_val_l, m_steer_val_r);
}
}
return PlayerController::action(action, value, /*dry_run*/false);
} // action
@ -383,3 +384,11 @@ bool LocalPlayerController::canGetAchievements() const
{
return m_player->getConstProfile() == PlayerManager::getCurrentPlayer();
} // canGetAchievements
// ----------------------------------------------------------------------------
core::stringw LocalPlayerController::getName() const
{
if (NetworkConfig::get()->isNetworking())
return PlayerController::getName();
return m_player->getProfile()->getName();
} // getName

View File

@ -78,7 +78,7 @@ public:
virtual bool isLocalPlayerController() const OVERRIDE {return true;}
// ------------------------------------------------------------------------
/** Returns the name of the player profile. */
core::stringw getName() const OVERRIDE { return m_player->getProfile()->getName(); }
core::stringw getName() const OVERRIDE;
}; // LocalPlayerController

View File

@ -29,6 +29,10 @@
#include "karts/skidding.hpp"
#include "karts/rescue_animation.hpp"
#include "modes/world.hpp"
#include "network/game_setup.hpp"
#include "network/network_config.hpp"
#include "network/network_player_profile.hpp"
#include "network/protocols/lobby_protocol.hpp"
#include "race/history.hpp"
#include "states_screens/race_gui_base.hpp"
#include "utils/constants.hpp"
@ -384,4 +388,17 @@ void PlayerController::rewindTo(BareNetworkString *buffer)
m_steer_val = buffer->getUInt32();
m_steer_val_l = buffer->getUInt32();
m_steer_val_r = buffer->getUInt32();
} // rewindTo
} // rewindTo
// ----------------------------------------------------------------------------
core::stringw PlayerController::getName() const
{
if (NetworkConfig::get()->isNetworking())
{
auto& players = LobbyProtocol::get<LobbyProtocol>()->getGameSetup()
->getPlayers();
if (auto player = players.at(m_kart->getWorldKartId()).lock())
return player->getName();
}
return m_kart->getName();
} // getName

View File

@ -93,6 +93,9 @@ public:
virtual void finishedRace(float time) OVERRIDE
{
} // finishedRace
// ------------------------------------------------------------------------
/** Returns the name of the player profile. */
core::stringw getName() const OVERRIDE;
}; // class PlayerController

View File

@ -69,6 +69,7 @@
#include "modes/soccer_world.hpp"
#include "modes/world.hpp"
#include "network/network_config.hpp"
#include "network/race_event_manager.hpp"
#include "network/rewind_manager.hpp"
#include "physics/btKart.hpp"
#include "physics/btKartRaycast.hpp"
@ -910,23 +911,23 @@ void Kart::finishedRace(float time, bool from_server)
// because the race was over (i.e. estimating the finish time). If
// this kart then crosses the finish line (with the end controller)
// it would trigger a race end again.
if(m_finished_race) return;
if (m_finished_race) return;
/* if(!from_server)
if (NetworkConfig::get()->isNetworking() && !from_server)
{
if(NetworkConfig::get()->isServer())
if (NetworkConfig::get()->isServer())
{
RaceEventManager::getInstance()->kartFinishedRace(this, time);
} // isServer
// Ignore local detection of a kart finishing a race in a
// network game.
else if(NetworkConfig::get()->isClient())
else if (NetworkConfig::get()->isClient())
{
return;
}
} // !from_server
*/
m_finished_race = true;
m_finish_time = time;
m_controller->finishedRace(time);
@ -967,7 +968,7 @@ void Kart::finishedRace(float time, bool from_server)
{
// Save for music handling in race result gui
setRaceResult();
if(!isGhostKart())
if (!isGhostKart())
{
setController(new EndController(this, m_controller));
}
@ -998,15 +999,17 @@ void Kart::setRaceResult()
else
m_race_result = false;
}
else if (this->getPosition() <= 0.5f*race_manager->getNumberOfKarts() ||
this->getPosition() == 1)
else if (this->getPosition() <= 0.5f *
World::getWorld()->getCurrentNumKarts() ||
this->getPosition() == 1)
m_race_result = true;
else
m_race_result = false;
}
else
{
if (this->getPosition() <= 0.5f*race_manager->getNumberOfKarts() ||
if (this->getPosition() <= 0.5f *
World::getWorld()->getCurrentNumKarts() ||
this->getPosition() == 1)
m_race_result = true;
else

View File

@ -172,7 +172,7 @@ protected:
/** True if fire button was pushed and not released */
bool m_fire_clicked;
/** True if the kart has been selected to have a boosted ai */
bool m_boosted_ai;
@ -486,11 +486,9 @@ public:
// ------------------------------------------------------------------------
/** Returns the position 0.25s before */
virtual const Vec3& getPreviousXYZ() const;
// ------------------------------------------------------------------------
/** Returns a more recent different previous position */
virtual const Vec3& getRecentPreviousXYZ() const;
// ------------------------------------------------------------------------
/** For debugging only: check if a kart is flying. */
bool isFlying() const { return m_flying; }

View File

@ -191,6 +191,7 @@
#include "graphics/particle_kind_manager.hpp"
#include "graphics/referee.hpp"
#include "graphics/sp/sp_base.hpp"
#include "graphics/sp/sp_shader.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/event_handler.hpp"
#include "guiengine/dialog_queue.hpp"
@ -210,6 +211,9 @@
#include "modes/cutscene_world.hpp"
#include "modes/demo_world.hpp"
#include "modes/profile_world.hpp"
#include "network/protocols/connect_to_server.hpp"
#include "network/protocols/client_lobby.hpp"
#include "network/game_setup.hpp"
#include "network/network_config.hpp"
#include "network/network_string.hpp"
#include "network/rewind_manager.hpp"
@ -569,6 +573,7 @@ void cmdLineHelp()
" --unlock-all Permanently unlock all karts and tracks for testing.\n"
" --no-unlock-all Disable unlock-all (i.e. base unlocking on player achievement).\n"
" --no-graphics Do not display the actual race.\n"
" --sp-shader-debug Enables debug in sp shader, it will print all unavailable uniforms.\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\n"
@ -586,7 +591,7 @@ void cmdLineHelp()
" --server-password= Sets a password for a server (both client&server).\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"
" public 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"
@ -729,10 +734,13 @@ int handleCmdLinePreliminary()
if(CommandLine::has("--kartdir", &s))
KartPropertiesManager::addKartSearchDir(s);
#ifndef SERVER_ONLY
if(CommandLine::has("--no-graphics") || CommandLine::has("-l"))
{
#endif
ProfileWorld::disableGraphics();
}
if (CommandLine::has("--sp-shader-debug"))
SP::SPShader::m_sp_shader_debug = true;
if(CommandLine::has("--screensize", &s) || CommandLine::has("-s", &s))
{
@ -1012,7 +1020,6 @@ int handleCmdLine()
}
} // --type
if (CommandLine::has("--login", &s))
login = s.c_str();
if (CommandLine::has("--password", &s))
@ -1051,6 +1058,12 @@ int handleCmdLine()
NetworkConfig::get()->setPassword(server_password);
}
if (CommandLine::has("--motd", &s))
{
core::stringw motd = StringUtils::xmlDecode(s);
NetworkConfig::get()->setMOTD(motd);
}
if (CommandLine::has("--server-id-file", &s))
{
NetworkConfig::get()->setServerIdFile(
@ -1074,21 +1087,36 @@ int handleCmdLine()
}
if (CommandLine::has("--connect-now", &s))
{
TransportAddress ip(s);
NetworkConfig::get()->setIsLAN();
TransportAddress server_addr(s);
NetworkConfig::get()->setIsWAN();
NetworkConfig::get()->setIsServer(false);
Log::info("main", "Try to connect to server '%s'.",
ip.toString().c_str() );
irr::core::stringw name = StringUtils::utf8ToWide(ip.toString());
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, !server_password.empty());
NetworkingLobby::getInstance()->setJoinedServer(server);
STKHost::create(server);
auto server = std::make_shared<Server>(0, L"", 0, 0, 0, 0, server_addr,
!server_password.empty());
NetworkConfig::get()->addNetworkPlayer(
input_manager->getDeviceManager()->getLatestUsedDevice(),
PlayerManager::getCurrentPlayer(), false/*handicap*/);
NetworkConfig::get()->doneAddingNetworkPlayers();
STKHost::create();
auto cts = std::make_shared<ConnectToServer>(server);
cts->setup();
Log::info("main", "Trying to connect to server '%s'.",
server_addr.toString().c_str());
if (!cts->handleDirectConnect(10000))
{
Log::error("main", "Timeout trying to connect to server '%s'.",
server_addr.toString().c_str());
STKHost::get()->shutdown();
exit(0);
}
else
{
auto cl = LobbyProtocol::create<ClientLobby>();
cl->setAddress(server_addr);
cl->requestStart();
}
}
std::shared_ptr<LobbyProtocol> server_lobby;
if (CommandLine::has("--wan-server", &s))
{
// Try to use saved user token if exists
@ -1113,7 +1141,7 @@ int handleCmdLine()
NetworkConfig::get()->setIsServer(true);
NetworkConfig::get()->setIsWAN();
NetworkConfig::get()->setIsPublicServer();
STKHost::create();
server_lobby = STKHost::create();
Log::info("main", "Creating a WAN server '%s'.", s.c_str());
}
}
@ -1122,7 +1150,7 @@ int handleCmdLine()
NetworkConfig::get()->setServerName(StringUtils::xmlDecode(s));
NetworkConfig::get()->setIsServer(true);
NetworkConfig::get()->setIsLAN();
STKHost::create();
server_lobby = STKHost::create();
Log::info("main", "Creating a LAN server '%s'.", s.c_str());
}
if (CommandLine::has("--auto-connect"))
@ -1130,6 +1158,34 @@ int handleCmdLine()
NetworkConfig::get()->setAutoConnect(true);
}
if (CommandLine::has("--extra-server-info", &n))
{
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
{
LobbyProtocol::get<LobbyProtocol>()->getGameSetup()
->setSoccerGoalTarget((bool)n);
NetworkConfig::get()->setServerMode(
race_manager->getMinorMode(),
RaceManager::MAJOR_MODE_SINGLE);
}
else
{
LobbyProtocol::get<LobbyProtocol>()->getGameSetup()
->setGrandPrixTrack(n);
NetworkConfig::get()->setServerMode(
race_manager->getMinorMode(),
RaceManager::MAJOR_MODE_GRAND_PRIX);
}
}
else
{
NetworkConfig::get()->setServerMode(
race_manager->getMinorMode(), RaceManager::MAJOR_MODE_SINGLE);
}
// The extra server info has to be set before server lobby started
if (server_lobby)
server_lobby->requestStart();
/** Disable detection of LAN connection when connecting via WAN. This is
* mostly a debugging feature to force using WAN connection. */
if (CommandLine::has("--disable-lan"))
@ -1919,11 +1975,16 @@ int main(int argc, char *argv[] )
// If the window was closed in the middle of a race, remove players,
// so we don't crash later when StateManager tries to access input devices.
StateManager::get()->resetActivePlayers();
if(input_manager) delete input_manager; // if early crash avoid delete NULL
if (input_manager)
{
delete input_manager;
input_manager = NULL;
}
if (STKHost::existHost())
STKHost::get()->shutdown();
NetworkConfig::destroy();
cleanSuperTuxKart();
#ifdef DEBUG

View File

@ -25,10 +25,12 @@
#include "graphics/material_manager.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/message_queue.hpp"
#include "guiengine/modaldialog.hpp"
#include "input/input_manager.hpp"
#include "modes/profile_world.hpp"
#include "modes/world.hpp"
#include "network/network_config.hpp"
#include "network/protocols/lobby_protocol.hpp"
#include "network/protocol_manager.hpp"
#include "network/race_event_manager.hpp"
#include "network/rewind_manager.hpp"
@ -36,8 +38,6 @@
#include "online/request_manager.hpp"
#include "race/history.hpp"
#include "race/race_manager.hpp"
#include "states_screens/main_menu_screen.hpp"
#include "states_screens/online_screen.hpp"
#include "states_screens/state_manager.hpp"
#include "utils/profiler.hpp"
@ -300,8 +300,25 @@ void MainLoop::run()
}
#endif
while(!m_abort)
while (!m_abort)
{
bool loading_shutdown = false;
auto lb = LobbyProtocol::get<LobbyProtocol>();
if (World::getWorld() && lb &&
STKHost::existHost() && !STKHost::get()->requestedShutdown())
{
while (!lb->allPlayersReady())
{
if (STKHost::existHost() && STKHost::get()->requestedShutdown())
{
loading_shutdown = true;
break;
}
StkTime::sleep(1);
m_curr_time = irr_driver->getDevice()->getTimer()->getRealTime();
}
}
#ifdef WIN32
if (parent != 0 && parent != INVALID_HANDLE_VALUE)
{
@ -330,7 +347,9 @@ void MainLoop::run()
float dt = stk_config->ticks2Time(1);
left_over_time -= num_steps * dt ;
if (STKHost::existHost() &&
// Shutdown next frame if shutdown request is sent while loading the
// world
if (!loading_shutdown && STKHost::existHost() &&
STKHost::get()->requestedShutdown())
{
SFXManager::get()->quickSound("anvil");
@ -340,18 +359,16 @@ void MainLoop::run()
msg = STKHost::get()->getErrorMessage();
}
STKHost::get()->shutdown();
// In case the user opened a race pause dialog
GUIEngine::ModalDialog::dismiss();
if (World::getWorld())
{
race_manager->exitRace();
}
if (!ProfileWorld::isNoGraphics())
{
GUIEngine::Screen* new_stack[] =
{
MainMenuScreen::getInstance(),
OnlineScreen::getInstance(), NULL
};
StateManager::get()->resetAndSetStack(new_stack);
StateManager::get()->resetAndSetStack(
NetworkConfig::get()->getResetScreens().data());
MessageQueue::add(MessageQueue::MT_ERROR, msg);
}
NetworkConfig::get()->unsetNetworking();

View File

@ -383,7 +383,7 @@ void LinearWorld::newLap(unsigned int kart_index)
// Store the temporary string because clang would mess this up
// (remove the stringw before the wchar_t* is used).
const core::stringw &kart_name = kart->getName();
const core::stringw &kart_name = kart->getController()->getName();
//I18N: as in "fastest lap: 60 seconds by Wilber"
irr::core::stringw m_fastest_lap_message =

View File

@ -170,6 +170,18 @@ public:
{
return stk_config->ticks2Time(m_fastest_lap_ticks);
}
// ------------------------------------------------------------------------
/** Network use: get fastest lap in ticks */
int getFastestLapTicks() const
{
return m_fastest_lap_ticks;
}
// ------------------------------------------------------------------------
/** Network use: set fastest lap in ticks */
void setFastestLapTicks(int ticks)
{
m_fastest_lap_ticks = ticks;
}
}; // LinearWorld
#endif

View File

@ -30,6 +30,7 @@
#include "graphics/material.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/render_info.hpp"
#include "guiengine/modaldialog.hpp"
#include "io/file_manager.hpp"
#include "input/device_manager.hpp"
#include "input/keyboard_device.hpp"
@ -341,11 +342,13 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
gk = ReplayPlay::get()->getNumGhostKart();
std::shared_ptr<RenderInfo> ri = std::make_shared<RenderInfo>();
if (global_player_id > -1 && race_manager->getKartInfo(global_player_id)
.getDefaultKartColor() > 0.0f)
core::stringw online_name;
if (global_player_id > -1)
{
ri->setHue(race_manager->getKartInfo(global_player_id)
.getDefaultKartColor());
online_name = race_manager->getKartInfo(global_player_id)
.getPlayerName();
}
int position = index+1;
@ -378,6 +381,8 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
case RaceManager::KT_NETWORK_PLAYER:
{
controller = new NetworkPlayerController(new_kart);
if (!online_name.empty())
new_kart->setOnScreenText(online_name.c_str());
m_num_players++;
break;
}
@ -564,7 +569,7 @@ void World::terminateRace()
// to show it in the GUI
int best_highscore_rank = -1;
std::string highscore_who = "";
if (!this->isNetworkWorld())
if (!isNetworkWorld())
{
updateHighscores(&best_highscore_rank);
}
@ -656,6 +661,8 @@ void World::terminateRace()
results->clearHighscores();
}
// In case someone opened paused race dialog in network game
GUIEngine::ModalDialog::dismiss();
results->push();
WorldStatus::terminateRace();
} // terminateRace
@ -1081,7 +1088,7 @@ void World::updateTrack(int ticks)
// ----------------------------------------------------------------------------
Highscores* World::getHighscores() const
{
if(!m_use_highscores) return NULL;
if (isNetworkWorld() || !m_use_highscores) return NULL;
const Highscores::HighscoreType type = "HST_" + getIdent();
@ -1210,6 +1217,7 @@ AbstractKart *World::getLocalPlayerKart(unsigned int n) const
/** Remove (eliminate) a kart from the race */
void World::eliminateKart(int kart_id, bool notify_of_elimination)
{
assert(kart_id < (int)m_karts.size());
AbstractKart *kart = m_karts[kart_id];
if (kart->isGhostKart()) return;
@ -1226,7 +1234,7 @@ void World::eliminateKart(int kart_id, bool notify_of_elimination)
{
// Store the temporary string because clang would mess this up
// (remove the stringw before the wchar_t* is used).
const core::stringw &kart_name = kart->getName();
const core::stringw &kart_name = kart->getController()->getName();
m_race_gui->addMessage(_("'%s' has been eliminated.",
kart_name),
camera->getKart(),
@ -1306,7 +1314,9 @@ void World::unpause()
//-----------------------------------------------------------------------------
void World::escapePressed()
{
new RacePausedDialog(0.8f, 0.6f);
if (!(NetworkConfig::get()->isNetworking() &&
getPhase() < MUSIC_PHASE))
new RacePausedDialog(0.8f, 0.6f);
} // escapePressed
// ----------------------------------------------------------------------------

View File

@ -113,7 +113,6 @@ protected:
void updateHighscores (int* best_highscore_rank);
void resetAllKarts ();
void eliminateKart (int kart_number, bool notifyOfElimination=true);
Controller*
loadAIController (AbstractKart *kart);
@ -321,6 +320,8 @@ public:
virtual void escapePressed();
// ------------------------------------------------------------------------
virtual void loadCustomModels() {}
// ------------------------------------------------------------------------
void eliminateKart(int kart_number, bool notify_of_elimination = true);
/** Set the network mode (true if networked) */
void setNetworkWorld(bool is_networked) { m_is_network_world = is_networked; }

View File

@ -29,7 +29,6 @@
#include "modes/world.hpp"
#include "network/network_config.hpp"
#include "network/protocols/client_lobby.hpp"
#include "network/protocols/server_lobby.hpp"
#include "network/rewind_manager.hpp"
#include "network/race_event_manager.hpp"
#include "tracks/track.hpp"
@ -150,6 +149,11 @@ void WorldStatus::setClockMode(const ClockType mode, const float initial_time)
*/
void WorldStatus::enterRaceOverState()
{
// Waiting for server result info
auto cl = LobbyProtocol::get<ClientLobby>();
if (cl && !cl->receivedServerResult())
return;
// Don't enter race over if it's already race over
if (m_phase == DELAY_FINISH_PHASE || m_phase == RESULT_DISPLAY_PHASE ||
m_phase == FINISH_PHASE)
@ -257,12 +261,11 @@ void WorldStatus::updateTime(int ticks)
case WAIT_FOR_SERVER_PHASE:
{
// This stage is only reached in case of a networked game.
// A client waits for a message from the server that it can
// start the race (i.e. that all clients and the server have
// loaded the world). The server waits for a confirmation from
// The server waits for a confirmation from
// each client that they have started (to guarantee that the
// server is running with a local time behind all clients).
if (m_server_is_ready.load() == false) return;
if (NetworkConfig::get()->isServer() &&
m_server_is_ready.load() == false) return;
m_phase = READY_PHASE;
auto cl = LobbyProtocol::get<ClientLobby>();
@ -400,10 +403,12 @@ void WorldStatus::updateTime(int ticks)
break;
}
case FINISH_PHASE:
case IN_GAME_MENU_PHASE:
// Nothing to do here.
break;
case GOAL_PHASE:
// Nothing to do here as well.
break;
default: break;
}

View File

@ -21,24 +21,17 @@
#include "config/player_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/world.hpp"
#include "network/network_config.hpp"
#include "network/network_player_profile.hpp"
#include "online/online_profile.hpp"
#include "network/protocols/game_events_protocol.hpp"
#include "network/stk_host.hpp"
#include "race/race_manager.hpp"
#include "utils/log.hpp"
//-----------------------------------------------------------------------------
GameSetup::GameSetup()
{
m_num_local_players = 0;
m_local_master = 0;
m_laps = 0;
m_reverse = false;
} // GameSetup
//-----------------------------------------------------------------------------
/** Update and see if any player disconnects.
* \param remove_disconnected_players remove the disconnected players,
* otherwise replace with AI (when racing), so this function must be called
* otherwise eliminate the kart in world, so this function must be called
* in main thread.
*/
void GameSetup::update(bool remove_disconnected_players)
@ -54,16 +47,84 @@ void GameSetup::update(bool remove_disconnected_players)
return;
}
lock.unlock();
if (!World::getWorld())
if (!World::getWorld() ||
World::getWorld()->getPhase() < WorldStatus::MUSIC_PHASE)
return;
for (uint8_t i = 0; i < (uint8_t)m_players.size(); i++)
{
if (!m_players[i].expired())
continue;
AbstractKart* k = World::getWorld()->getKart(i);
if (!k->isEliminated())
{
World::getWorld()->eliminateKart(i,
false/*notify_of_elimination*/);
k->setPosition(
World::getWorld()->getCurrentNumKarts() + 1);
k->finishedRace(World::getWorld()->getTime());
NetworkString p(PROTOCOL_GAME_EVENTS);
p.setSynchronous(true);
p.addUInt8(GameEventsProtocol::GE_PLAYER_DISCONNECT).addUInt8(i);
STKHost::get()->sendPacketToAllPeers(&p, true);
}
}
} // removePlayer
//-----------------------------------------------------------------------------
void GameSetup::loadWorld()
{
assert(!m_track.empty());
assert(!m_tracks.empty());
// Disable accidentally unlocking of a challenge
PlayerManager::getCurrentPlayer()->setCurrentChallenge("");
race_manager->setTimeTarget(0.0f);
race_manager->setReverseTrack(m_reverse);
race_manager->startSingleRace(m_track, m_laps, false/*from_overworld*/);
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER)
{
if (isSoccerGoalTarget())
race_manager->setMaxGoal(m_laps);
else
race_manager->setTimeTarget((float)m_laps * 60.0f);
}
else
{
race_manager->startSingleRace(m_tracks.back(), m_laps,
false/*from_overworld*/);
}
} // loadWorld
//-----------------------------------------------------------------------------
bool GameSetup::isGrandPrix() const
{
return m_extra_server_info != -1 &&
NetworkConfig::get()->getLocalGameMode().second ==
RaceManager::MAJOR_MODE_GRAND_PRIX;
} // isGrandPrix
//-----------------------------------------------------------------------------
void GameSetup::addServerInfo(NetworkString* ns)
{
assert(NetworkConfig::get()->isServer());
ns->encodeString(NetworkConfig::get()->getServerName());
ns->addUInt8(race_manager->getDifficulty())
.addUInt8((uint8_t)NetworkConfig::get()->getMaxPlayers())
.addUInt8((uint8_t)NetworkConfig::get()->getServerMode());
if (hasExtraSeverInfo())
{
if (isGrandPrix())
{
ns->addUInt8((uint8_t)2).addUInt8((uint8_t)m_tracks.size())
.addUInt8(getExtraServerInfo());
}
else
{
// Soccer mode
ns->addUInt8((uint8_t)1).addUInt8(getExtraServerInfo());
}
}
else
{
// No extra server info
ns->addUInt8((uint8_t)0);
}
ns->encodeString(NetworkConfig::get()->getMOTD());
} // addServerInfo

View File

@ -24,12 +24,14 @@
#include "network/remote_kart_info.hpp"
#include <cassert>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
class NetworkPlayerProfile;
class NetworkString;
// ============================================================================
/*! \class GameSetup
@ -47,19 +49,22 @@ private:
/** Stores the number of local players. */
int m_num_local_players;
/** The player id of the local game master, used in
* kart selection screen. */
uint8_t m_local_master;
std::string m_track;
std::vector<std::string> m_tracks;
unsigned m_laps;
bool m_reverse;
int m_extra_server_info;
public:
// ------------------------------------------------------------------------
GameSetup();
GameSetup()
{
m_num_local_players = 0;
m_extra_server_info = -1;
reset();
}
// ------------------------------------------------------------------------
~GameSetup() {}
// ------------------------------------------------------------------------
@ -69,7 +74,7 @@ public:
void update(bool remove_disconnected_players);
// ------------------------------------------------------------------------
/** Sets the number of local players. */
void setNumLocalPlayers(int n) { m_num_local_players = n; }
void setNumLocalPlayers(int n) { m_num_local_players = n; }
// ------------------------------------------------------------------------
/** Returns the nunber of local players. */
int getNumLocalPlayers() const { return m_num_local_players; }
@ -104,17 +109,51 @@ public:
return (unsigned)m_players.size();
}
// ------------------------------------------------------------------------
/** Returns the id of the local master. */
int getLocalMasterID() const { return m_local_master; }
// ------------------------------------------------------------------------
void setRace(const std::string& track, unsigned laps, bool reverse)
{
m_track = track;
m_tracks.push_back(track);
m_laps = laps;
m_reverse = reverse;
}
// ------------------------------------------------------------------------
void reset()
{
m_tracks.clear();
m_laps = 0;
m_reverse = false;
}
// ------------------------------------------------------------------------
void setGrandPrixTrack(int tracks_no) { m_extra_server_info = tracks_no; }
// ------------------------------------------------------------------------
void addServerInfo(NetworkString* ns);
// ------------------------------------------------------------------------
void loadWorld();
// ------------------------------------------------------------------------
bool isGrandPrix() const;
// ------------------------------------------------------------------------
bool hasExtraSeverInfo() const { return m_extra_server_info != -1; }
// ------------------------------------------------------------------------
uint8_t getExtraServerInfo() const
{
assert(hasExtraSeverInfo());
return (uint8_t)m_extra_server_info;
}
// ------------------------------------------------------------------------
unsigned getTotalGrandPrixTracks() const
{
assert(isGrandPrix());
return m_extra_server_info;
}
// ------------------------------------------------------------------------
void setSoccerGoalTarget(bool val) { m_extra_server_info = (int)val; }
// ------------------------------------------------------------------------
bool isSoccerGoalTarget() const
{
assert(hasExtraSeverInfo());
return m_extra_server_info != 0;
}
// ------------------------------------------------------------------------
const std::vector<std::string>& getAllTracks() const { return m_tracks; }
};
#endif // GAME_SETUP_HPP

View File

@ -186,9 +186,9 @@ void Network::openLog()
std::string s = file_manager
->getUserConfigFile(FileManager::getStdoutName()+".packet");
m_log_file.setAtomic(fopen(s.c_str(), "w+"));
if (!m_log_file.getData())
Log::warn("STKHost", "Network packets won't be logged: no file.");
}
if (!m_log_file.getData())
Log::warn("STKHost", "Network packets won't be logged: no file.");
} // openLog
// ----------------------------------------------------------------------------

View File

@ -20,6 +20,11 @@
#include "config/stk_config.hpp"
#include "config/user_config.hpp"
#include "online/xml_request.hpp"
#include "states_screens/main_menu_screen.hpp"
#include "states_screens/networking_lobby.hpp"
#include "states_screens/online_lan.hpp"
#include "states_screens/online_profile_servers.hpp"
#include "states_screens/online_screen.hpp"
NetworkConfig *NetworkConfig::m_network_config = NULL;
bool NetworkConfig::m_disable_lan = false;
@ -72,39 +77,38 @@ void NetworkConfig::setIsServer(bool b)
} // setIsServer
// ----------------------------------------------------------------------------
unsigned NetworkConfig::getServerGameMode(RaceManager::MinorRaceModeType minor,
RaceManager::MajorRaceModeType major)
void NetworkConfig::setServerMode(RaceManager::MinorRaceModeType minor,
RaceManager::MajorRaceModeType major)
{
if (major == RaceManager::MAJOR_MODE_GRAND_PRIX)
{
if (minor == RaceManager::MINOR_MODE_NORMAL_RACE)
return 0;
m_server_mode = 0;
else if (minor == RaceManager::MINOR_MODE_TIME_TRIAL)
return 1;
m_server_mode = 1;
else if (minor == RaceManager::MINOR_MODE_FOLLOW_LEADER)
return 2;
m_server_mode = 2;
}
else
{
if (minor == RaceManager::MINOR_MODE_NORMAL_RACE)
return 3;
m_server_mode = 3;
else if (minor == RaceManager::MINOR_MODE_TIME_TRIAL)
return 4;
m_server_mode = 4;
else if (minor == RaceManager::MINOR_MODE_FOLLOW_LEADER)
return 5;
m_server_mode = 5;
else if (minor == RaceManager::MINOR_MODE_3_STRIKES)
return 6;
m_server_mode = 6;
else if (minor == RaceManager::MINOR_MODE_SOCCER)
return 7;
m_server_mode = 7;
}
return 0;
} // getServerGameMode
} // setServerMode
// ----------------------------------------------------------------------------
std::pair<RaceManager::MinorRaceModeType, RaceManager::MajorRaceModeType>
NetworkConfig::getLocalGameMode(unsigned id)
NetworkConfig::getLocalGameMode()
{
switch(id)
switch (m_server_mode)
{
case 0:
return { RaceManager::MINOR_MODE_NORMAL_RACE,
@ -147,3 +151,79 @@ void NetworkConfig::setUserDetails(Online::XMLRequest* r,
r->addParameter("userid", m_cur_user_id);
r->addParameter("token", m_cur_user_token);
} // setUserDetails
// ----------------------------------------------------------------------------
core::stringw NetworkConfig::getModeName(unsigned id)
{
switch(id)
{
case 0:
return _("Normal Race (Grand Prix)");
case 1:
return _("Time Trial (Grand Prix)");
case 3:
return _("Normal Race");
case 4:
return _("Time Trial");
case 6:
return _("3 Strikes Battle");
case 7:
return _("Soccer");
default:
return L"";
}
} // getModeName
// ----------------------------------------------------------------------------
std::vector<GUIEngine::Screen*>
NetworkConfig::getResetScreens(bool lobby) const
{
if (lobby)
{
if (isWAN())
{
return
{
MainMenuScreen::getInstance(),
OnlineScreen::getInstance(),
OnlineProfileServers::getInstance(),
NetworkingLobby::getInstance(),
nullptr
};
}
else
{
return
{
MainMenuScreen::getInstance(),
OnlineScreen::getInstance(),
OnlineLanScreen::getInstance(),
NetworkingLobby::getInstance(),
nullptr
};
}
}
else
{
if (isWAN())
{
return
{
MainMenuScreen::getInstance(),
OnlineScreen::getInstance(),
OnlineProfileServers::getInstance(),
nullptr
};
}
else
{
return
{
MainMenuScreen::getInstance(),
OnlineScreen::getInstance(),
OnlineLanScreen::getInstance(),
nullptr
};
}
}
} // getResetScreens

View File

@ -34,6 +34,11 @@ namespace Online
class XMLRequest;
}
namespace GUIEngine
{
class Screen;
}
class InputDevice;
class PlayerProfile;
@ -86,6 +91,8 @@ private:
/** If this is a server, the server name. */
irr::core::stringw m_server_name;
unsigned m_server_mode;
/** Used by wan server. */
uint32_t m_cur_user_id;
std::string m_cur_user_token;
@ -96,6 +103,8 @@ private:
std::vector<std::tuple<InputDevice*, PlayerProfile*,
/*is_handicap*/bool> > m_network_players;
core::stringw m_motd;
NetworkConfig();
public:
@ -249,13 +258,9 @@ public:
* 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);
getLocalGameMode();
// ------------------------------------------------------------------------
void setCurrentUserId(uint32_t id) { m_cur_user_id = id ; }
// ------------------------------------------------------------------------
@ -270,6 +275,21 @@ public:
void setServerIdFile(const std::string& id) { m_server_id_file = id; }
// ------------------------------------------------------------------------
const std::string& getServerIdFile() const { return m_server_id_file; }
// ------------------------------------------------------------------------
void setMOTD(const core::stringw& motd) { m_motd = motd; }
// ------------------------------------------------------------------------
const core::stringw& getMOTD() const { return m_motd; }
// ------------------------------------------------------------------------
void setServerMode(RaceManager::MinorRaceModeType mode,
RaceManager::MajorRaceModeType);
// ------------------------------------------------------------------------
void setServerMode(unsigned mode) { m_server_mode = mode; }
// ------------------------------------------------------------------------
unsigned getServerMode() const { return m_server_mode; }
// ------------------------------------------------------------------------
core::stringw getModeName(unsigned id);
// ------------------------------------------------------------------------
std::vector<GUIEngine::Screen*> getResetScreens(bool lobby = false) const;
}; // class NetworkConfig

View File

@ -30,7 +30,7 @@ void NetworkString::unitTesting()
{
NetworkString s(PROTOCOL_LOBBY_ROOM);
assert(s.getProtocolType() == PROTOCOL_LOBBY_ROOM);
assert(s.getProtocolType() != PROTOCOL_KART_UPDATE);
assert(s.getProtocolType() != PROTOCOL_CONTROLLER_EVENTS);
assert(!s.isSynchronous());
s.setSynchronous(true);
assert(s.isSynchronous());

View File

@ -46,10 +46,9 @@ enum ProtocolType
PROTOCOL_LOBBY_ROOM = 0x02, //!< Protocol that is used during the lobby room phase.
PROTOCOL_START_GAME = 0x03, //!< Protocol used when starting the game.
PROTOCOL_SYNCHRONIZATION = 0x04, //!< Protocol used to determine latency
PROTOCOL_KART_UPDATE = 0x05, //!< Protocol to update karts position, rotation etc...
PROTOCOL_GAME_EVENTS = 0x06, //!< Protocol to communicate the game events.
PROTOCOL_CONTROLLER_EVENTS = 0x07, //!< Protocol to transfer controller modifications
PROTOCOL_SILENT = 0x08, //!< Used for protocols that do not subscribe to any network event.
PROTOCOL_GAME_EVENTS = 0x05, //!< Protocol to communicate the game events.
PROTOCOL_CONTROLLER_EVENTS = 0x06, //!< Protocol to transfer controller modifications
PROTOCOL_SILENT = 0x07, //!< Used for protocols that do not subscribe to any network event.
PROTOCOL_MAX , //!< Maximum number of different protocol types
PROTOCOL_SYNCHRONOUS = 0x80, //!< Flag, indicates synchronous delivery
}; // ProtocolType

View File

@ -24,12 +24,13 @@
#include "guiengine/message_queue.hpp"
#include "input/device_manager.hpp"
#include "karts/kart_properties_manager.hpp"
#include "modes/world_with_rank.hpp"
#include "modes/linear_world.hpp"
#include "network/event.hpp"
#include "network/game_setup.hpp"
#include "network/network_config.hpp"
#include "network/network_player_profile.hpp"
#include "network/protocol_manager.hpp"
#include "network/protocols/game_protocol.hpp"
#include "network/protocols/game_events_protocol.hpp"
#include "network/race_event_manager.hpp"
#include "network/stk_host.hpp"
#include "network/stk_peer.hpp"
@ -81,10 +82,13 @@ ClientLobby::~ClientLobby()
void ClientLobby::clearPlayers()
{
StateManager::get()->resetActivePlayers();
input_manager->getDeviceManager()->setAssignMode(NO_ASSIGN);
input_manager->getDeviceManager()->setSinglePlayer(NULL);
input_manager->setMasterPlayerOnly(false);
input_manager->getDeviceManager()->clearLatestUsedDevice();
if (input_manager)
{
input_manager->getDeviceManager()->setAssignMode(NO_ASSIGN);
input_manager->getDeviceManager()->setSinglePlayer(NULL);
input_manager->setMasterPlayerOnly(false);
input_manager->getDeviceManager()->clearLatestUsedDevice();
}
} // clearPlayers
//-----------------------------------------------------------------------------
@ -99,9 +103,10 @@ void ClientLobby::setAddress(const TransportAddress &address)
void ClientLobby::setup()
{
clearPlayers();
m_received_server_result = false;
TracksScreen::getInstance()->resetVote();
LobbyProtocol::setup();
m_state = NONE;
m_state.store(NONE);
} // setup
//-----------------------------------------------------------------------------
@ -111,7 +116,8 @@ void ClientLobby::setup()
*/
void ClientLobby::doneWithResults()
{
NetworkString *done = getNetworkString(1);
NetworkString* done = getNetworkString(1);
done->setSynchronous(true);
done->addUInt8(LE_RACE_FINISHED_ACK);
sendToServer(done, /*reliable*/true);
delete done;
@ -135,6 +141,8 @@ bool ClientLobby::notifyEvent(Event* event)
case LE_EXIT_RESULT: exitResultScreen(event); break;
case LE_UPDATE_PLAYER_LIST: updatePlayerList(event); break;
case LE_CHAT: handleChat(event); break;
case LE_CONNECTION_ACCEPTED: connectionAccepted(event); break;
case LE_SERVER_INFO: handleServerInfo(event); break;
default:
return false;
break;
@ -159,7 +167,6 @@ bool ClientLobby::notifyEventAsynchronous(Event* event)
case LE_PLAYER_DISCONNECTED : disconnectedPlayer(event); break;
case LE_START_RACE: startGame(event); break;
case LE_CONNECTION_REFUSED: connectionRefused(event); break;
case LE_CONNECTION_ACCEPTED: connectionAccepted(event); break;
case LE_VOTE: displayPlayerVote(event); break;
case LE_SERVER_OWNERSHIP: becomingServerOwner(); break;
default: break;
@ -216,10 +223,9 @@ void ClientLobby::addAllPlayers(Event* event)
std::shared_ptr<STKPeer> peer = event->getPeerSP();
peer->cleanPlayerProfiles();
m_game_setup->update(true/*remove_disconnected_players*/);
std::vector<std::shared_ptr<NetworkPlayerProfile> > players;
unsigned player_count = data.getUInt8();
assert(m_game_setup->getPlayerCount() == 0);
for (unsigned i = 0; i < player_count; i++)
{
@ -245,18 +251,19 @@ void ClientLobby::addAllPlayers(Event* event)
//-----------------------------------------------------------------------------
void ClientLobby::update(int ticks)
{
switch (m_state)
switch (m_state.load())
{
case NONE:
if (STKHost::get()->isConnectedTo(m_server_address))
{
m_state = LINKED;
m_state.store(LINKED);
}
break;
case LINKED:
{
NetworkString *ns = getNetworkString();
ns->addUInt8(LE_CONNECTION_REQUESTED)
.addUInt8(NetworkConfig::m_server_version)
.encodeString(NetworkConfig::get()->getPassword());
assert(!NetworkConfig::get()->isAddingNetworkPlayers());
@ -305,7 +312,7 @@ void ClientLobby::update(int ticks)
sendToServer(ns);
delete ns;
m_state = REQUESTING_CONNECTION;
m_state.store(REQUESTING_CONNECTION);
}
break;
case REQUESTING_CONNECTION:
@ -337,7 +344,7 @@ void ClientLobby::update(int ticks)
{
screen->push();
}
m_state = SELECTING_KARTS;
m_state.store(SELECTING_KARTS);
}
break;
case SELECTING_KARTS:
@ -347,7 +354,7 @@ void ClientLobby::update(int ticks)
case RACE_FINISHED:
break;
case DONE:
m_state = EXITING;
m_state.store(EXITING);
requestTerminate();
break;
case EXITING:
@ -419,7 +426,7 @@ void ClientLobby::disconnectedPlayer(Event* event)
*/
void ClientLobby::connectionAccepted(Event* event)
{
// At least 4 byte should remain now
// At least 4 bytes should remain now
if (!checkDataSize(event, 4)) return;
NetworkString &data = event->data();
@ -435,11 +442,88 @@ void ClientLobby::connectionAccepted(Event* event)
NetworkConfig::get()->getNetworkPlayers().size());
// connection token
uint32_t token = data.getToken();
if (!peer->isClientServerTokenSet())
peer->setClientServerToken(token);
m_state = CONNECTED;
peer->setClientServerToken(token);
m_state.store(CONNECTED);
} // connectionAccepted
//-----------------------------------------------------------------------------
void ClientLobby::handleServerInfo(Event* event)
{
// At least 6 bytes should remain now
if (!checkDataSize(event, 6)) return;
NetworkString &data = event->data();
// Add server info
core::stringw str, each_line;
uint8_t u_data;
data.decodeStringW(&str);
//I18N: In the networking lobby
each_line = _("Server name: %s", str);
NetworkingLobby::getInstance()->addMoreServerInfo(each_line);
u_data = data.getUInt8();
const core::stringw& difficulty_name =
race_manager->getDifficultyName((RaceManager::Difficulty)u_data);
race_manager->setDifficulty((RaceManager::Difficulty)u_data);
//I18N: In the networking lobby
each_line = _("Difficulty: %s", difficulty_name);
NetworkingLobby::getInstance()->addMoreServerInfo(each_line);
u_data = data.getUInt8();
//I18N: In the networking lobby
each_line = _("Max players: %d", (int)u_data);
NetworkingLobby::getInstance()->addMoreServerInfo(each_line);
u_data = data.getUInt8();
NetworkConfig::get()->setServerMode(u_data);
auto game_mode = NetworkConfig::get()->getLocalGameMode();
race_manager->setMinorMode(game_mode.first);
// We may use single mode in network even it's grand prix
//race_manager->setMajorMode(game_mode.second);
//I18N: In the networking lobby
core::stringw mode_name = NetworkConfig::get()->getModeName(u_data);
each_line = _("Game mode: %s", mode_name);
NetworkingLobby::getInstance()->addMoreServerInfo(each_line);
uint8_t extra_server_info = data.getUInt8();
switch (extra_server_info)
{
case 0:
break;
case 1:
{
u_data = data.getUInt8();
core::stringw tl = _("Time limit");
core::stringw gl = _("Goals limit");
core::stringw sgt = u_data == 0 ? tl : gl;
m_game_setup->setSoccerGoalTarget(u_data != 0);
//I18N: In the networking lobby
each_line = _("Soccer game type: %s", sgt);
NetworkingLobby::getInstance()->addMoreServerInfo(each_line);
break;
}
case 2:
{
unsigned cur_gp_track = data.getUInt8();
unsigned total_gp_track = data.getUInt8();
m_game_setup->setGrandPrixTrack(total_gp_track);
each_line = _("Grand prix progress: %d / %d", cur_gp_track,
total_gp_track);
NetworkingLobby::getInstance()->addMoreServerInfo(each_line);
break;
}
}
// MOTD
data.decodeStringW(&str);
if (!str.empty())
NetworkingLobby::getInstance()->addMoreServerInfo(str);
} // handleServerInfo
//-----------------------------------------------------------------------------
void ClientLobby::updatePlayerList(Event* event)
{
@ -464,10 +548,10 @@ void ClientLobby::updatePlayerList(Event* event)
//-----------------------------------------------------------------------------
void ClientLobby::becomingServerOwner()
{
MessageQueue::add(MessageQueue::MT_GENERIC,
_("You are now the owner of server."));
core::stringw msg = _("You are now the owner of server.");
MessageQueue::add(MessageQueue::MT_GENERIC, msg);
STKHost::get()->setAuthorisedToControl(true);
if (m_state == CONNECTED && NetworkConfig::get()->isAutoConnect())
if (m_state.load() == CONNECTED && NetworkConfig::get()->isAutoConnect())
{
// Send a message to the server to start
NetworkString start(PROTOCOL_LOBBY_ROOM);
@ -537,12 +621,12 @@ void ClientLobby::connectionRefused(Event* event)
//-----------------------------------------------------------------------------
/*! \brief Called when the server broadcasts to start the race to all clients.
* \param event : Event providing the information (no additional information
* \param event : Event providing the information (no additional informati
* in this case).
*/
void ClientLobby::startGame(Event* event)
{
m_state = PLAYING;
m_state.store(PLAYING);
// Triggers the world finite state machine to go from WAIT_FOR_SERVER_PHASE
// to READY_PHASE.
World::getWorld()->setReadyToRace();
@ -560,9 +644,10 @@ void ClientLobby::startGame(Event* event)
*/
void ClientLobby::startingRaceNow()
{
NetworkString *ns = getNetworkString(2);
NetworkString* ns = getNetworkString(2);
ns->addUInt8(LE_STARTED_RACE);
sendToServer(ns, /*reliable*/true);
delete ns;
Log::verbose("ClientLobby", "StartingRaceNow at %lf",
StkTime::getRealTime());
} // startingRaceNow
@ -574,7 +659,7 @@ void ClientLobby::startingRaceNow()
*/
void ClientLobby::startSelection(Event* event)
{
m_state = KART_SELECTION;
m_state.store(KART_SELECTION);
const NetworkString& data = event->data();
const unsigned kart_num = data.getUInt16();
const unsigned track_num = data.getUInt16();
@ -609,35 +694,30 @@ void ClientLobby::startSelection(Event* event)
*/
void ClientLobby::raceFinished(Event* event)
{
if(!checkDataSize(event, 1)) return;
NetworkString &data = event->data();
Log::error("ClientLobby",
"Server notified that the race is finished.");
Log::info("ClientLobby", "Server notified that the race is finished.");
if (m_game_setup->isGrandPrix())
{
// fastest lap, and than each kart before / after grand prix points
}
else if (race_manager->modeHasLaps())
{
int t = data.getUInt32();
static_cast<LinearWorld*>(World::getWorld())->setFastestLapTicks(t);
}
// stop race protocols
auto pm = ProtocolManager::lock();
assert(pm);
pm->findAndTerminate(PROTOCOL_CONTROLLER_EVENTS);
pm->findAndTerminate(PROTOCOL_KART_UPDATE);
pm->findAndTerminate(PROTOCOL_GAME_EVENTS);
RaceEventManager::getInstance()->stop();
// finish the race
WorldWithRank* ranked_world = (WorldWithRank*)(World::getWorld());
ranked_world->beginSetKartPositions();
ranked_world->setPhase(WorldStatus::RESULT_DISPLAY_PHASE);
int position = 1;
while(data.size()>0)
{
uint8_t kart_id = data.getUInt8();
ranked_world->setKartPosition(kart_id,position);
Log::info("ClientLobby", "Kart %d has finished #%d",
kart_id, position);
position++;
}
ranked_world->endSetKartPositions();
m_state = RACE_FINISHED;
ranked_world->terminateRace();
RaceEventManager::getInstance()->getProtocol()->requestTerminate();
GameProtocol::lock()->requestTerminate();
while (!RaceEventManager::getInstance()->protocolStopped())
StkTime::sleep(1);
while (!GameProtocol::emptyInstance())
StkTime::sleep(1);
m_received_server_result = true;
} // raceFinished
//-----------------------------------------------------------------------------
@ -646,16 +726,8 @@ void ClientLobby::raceFinished(Event* event)
*/
void ClientLobby::exitResultScreen(Event *event)
{
// stop race protocols
auto pm = ProtocolManager::lock();
assert(pm);
pm->findAndTerminate(PROTOCOL_CONTROLLER_EVENTS);
pm->findAndTerminate(PROTOCOL_KART_UPDATE);
pm->findAndTerminate(PROTOCOL_GAME_EVENTS);
// Will be reset to linked if connected to server, see update(float dt)
setup();
m_state.store(CONNECTED);
RaceResultGUI::getInstance()->backToLobby();
} // exitResultScreen

View File

@ -4,6 +4,8 @@
#include "network/protocols/lobby_protocol.hpp"
#include "network/transport_address.hpp"
#include "utils/cpp2011.hpp"
#include <atomic>
#include <set>
class ClientLobby : public LobbyProtocol
@ -20,13 +22,14 @@ private:
void displayPlayerVote(Event* event);
void updatePlayerList(Event* event);
void handleChat(Event* event);
void handleServerInfo(Event* event);
void becomingServerOwner();
void clearPlayers();
TransportAddress m_server_address;
enum STATE
enum ClientState : unsigned int
{
NONE,
LINKED,
@ -41,11 +44,13 @@ private:
};
/** The state of the finite state machine. */
STATE m_state;
std::atomic<ClientState> m_state;
std::set<std::string> m_available_karts;
std::set<std::string> m_available_tracks;
bool m_received_server_result = false;
void addAllPlayers(Event* event);
public:
@ -53,6 +58,7 @@ public:
virtual ~ClientLobby();
void setAddress(const TransportAddress &address);
void doneWithResults();
bool receivedServerResult() { return m_received_server_result; }
void startingRaceNow();
const std::set<std::string>& getAvailableKarts() const
{ return m_available_karts; }
@ -64,9 +70,10 @@ public:
virtual void setup() OVERRIDE;
virtual void update(int ticks) OVERRIDE;
virtual bool waitingForPlayers() const OVERRIDE
{ return m_state == LINKED; }
{ return m_state.load() == CONNECTED; }
virtual void asynchronousUpdate() OVERRIDE {}
virtual bool allPlayersReady() const OVERRIDE
{ return m_state.load() >= PLAYING; }
};
#endif // CLIENT_LOBBY_HPP

View File

@ -37,7 +37,6 @@ ConnectToPeer::ConnectToPeer(uint32_t peer_id) : Protocol(PROTOCOL_CONNECTION)
m_peer_address.clear();
m_peer_id = peer_id;
m_state = NONE;
m_is_lan = false;
} // ConnectToPeer(peer_id)
// ----------------------------------------------------------------------------
@ -51,7 +50,6 @@ ConnectToPeer::ConnectToPeer(const TransportAddress &address)
// We don't need to find the peer address, so we can start
// with the state when we found the peer address.
m_state = WAIT_FOR_CONNECTION;
m_is_lan = true;
} // ConnectToPeers(TransportAddress)
// ----------------------------------------------------------------------------

View File

@ -39,9 +39,6 @@ protected:
* gone. */
std::shared_ptr<Protocol> m_current_protocol;
/** True if this is a LAN connection. */
bool m_is_lan;
/** Timer use for tracking broadcast. */
double m_timer = 0.0;

View File

@ -168,12 +168,17 @@ void ConnectToServer::asynchronousUpdate()
}
if (m_tried_connection++ > 7)
{
Log::warn("ConnectToServer", "Timeout waiting for"
" aloha, trying to connect anyway.");
m_state = CONNECTING;
// Reset timer for next usage
m_timer = 0.0;
m_tried_connection = 0;
if (NetworkConfig::get()->isWAN())
{
Log::warn("ConnectToServer", "Timeout waiting for"
" aloha, trying to connect anyway.");
m_state = CONNECTING;
// Reset timer for next usage
m_timer = 0.0;
m_tried_connection = 0;
}
else
m_state = DONE;
return;
}
if ((!NetworkConfig::m_disable_lan &&
@ -257,7 +262,9 @@ void ConnectToServer::update(int ticks)
switch(m_state.load())
{
case REQUESTING_CONNECTION:
case CONNECTING:
{
// Make sure lobby display the quick play server name
assert(m_server);
NetworkingLobby::getInstance()->setJoinedServer(m_server);
break;
@ -292,7 +299,7 @@ void ConnectToServer::update(int ticks)
} // update
// ----------------------------------------------------------------------------
bool ConnectToServer::handleDirectConnect()
bool ConnectToServer::handleDirectConnect(int timeout)
{
// Direct connection to server should only possbile if public and private
// ports of server are the same
@ -308,10 +315,32 @@ bool ConnectToServer::handleDirectConnect()
/*max_in_bandwidth*/0, /*max_out_bandwidth*/0, &ea,
true/*change_port_if_bound*/);
assert(dc);
if (m_server_address.getPort() == 0)
{
// Get the server port of server from (common) server discovery port
Log::info("ConnectToServer", "Detect port for server address.");
BareNetworkString s(std::string("stk-server-port"));
TransportAddress address(m_server_address.getIP(),
NetworkConfig::get()->getServerDiscoveryPort());
dc->sendRawPacket(s, address);
TransportAddress sender;
const int LEN = 2048;
char buffer[LEN];
int len = dc->receiveRawPacket(buffer, LEN, &sender, 2000);
if (len != 2)
{
Log::error("ConnectToServer", "Invalid port number");
delete dc;
return false;
}
BareNetworkString server_port(buffer, len);
uint16_t port = server_port.getUInt16();
m_server_address.setPort(port);
}
ENetPeer* p = dc->connectTo(m_server_address);
if (p)
{
while (enet_host_service(dc->getENetHost(), &event, 2000) != 0)
while (enet_host_service(dc->getENetHost(), &event, timeout) != 0)
{
if (event.type == ENET_EVENT_TYPE_CONNECT)
{

View File

@ -56,7 +56,6 @@ private:
void registerWithSTKServer();
void waitingAloha(bool is_wan);
bool handleDirectConnect();
public:
ConnectToServer(std::shared_ptr<Server> server);
virtual ~ConnectToServer();
@ -65,6 +64,8 @@ public:
virtual void setup() OVERRIDE;
virtual void asynchronousUpdate() OVERRIDE;
virtual void update(int ticks) OVERRIDE;
bool handleDirectConnect(int timeout = 2000);
}; // class ConnectToServer
#endif // CONNECT_TO_SERVER_HPP

View File

@ -33,15 +33,6 @@ GameEventsProtocol::~GameEventsProtocol()
{
} // ~GameEventsProtocol
// ----------------------------------------------------------------------------
/** Once the GameEventsProtocol is ready, signal the world that the timer
* can start.
*/
void GameEventsProtocol::setup()
{
m_count_ready_clients = 0;
} // setup
// ----------------------------------------------------------------------------
bool GameEventsProtocol::notifyEvent(Event* event)
{
@ -55,21 +46,15 @@ bool GameEventsProtocol::notifyEvent(Event* event)
Log::warn("GameEventsProtocol", "Too short message.");
return true;
}
if ( event->getPeer()->getClientServerToken() != data.getToken())
{
Log::warn("GameEventsProtocol", "Bad token.");
return true;
}
int8_t type = data.getUInt8();
uint8_t type = data.getUInt8();
switch (type)
{
case GE_CLIENT_STARTED_RSG:
receivedClientHasStarted(event); break;
case GE_ITEM_COLLECTED:
collectedItem(data); break;
case GE_KART_FINISHED_RACE:
kartFinishedRace(data); break;
case GE_PLAYER_DISCONNECT:
eliminatePlayer(data); break;
default:
Log::warn("GameEventsProtocol", "Unkown message type.");
break;
@ -95,12 +80,28 @@ void GameEventsProtocol::collectedItem(Item* item, AbstractKart* kart)
ns->addUInt8(GE_ITEM_COLLECTED).addUInt32(item->getItemId())
.addUInt8(powerup).addUInt8(kart->getWorldKartId());
Log::info("GameEventsProtocol",
"Notified a peer that a kart collected item %d.",
(int)(kart->getPowerup()->getType()));
"Notified a peer that a kart collected item %d index %d",
(int)(kart->getPowerup()->getType()), item->getItemId());
STKHost::get()->sendPacketToAllPeers(ns, /*reliable*/true);
delete ns;
} // collectedItem
// ----------------------------------------------------------------------------
void GameEventsProtocol::eliminatePlayer(const NetworkString &data)
{
assert(NetworkConfig::get()->isClient());
if (data.size() < 1)
{
Log::warn("GameEventsProtocol", "eliminatePlayer: Too short message.");
}
int kartid = data.getUInt8();
World::getWorld()->eliminateKart(kartid, false/*notify_of_elimination*/);
World::getWorld()->getKart(kartid)->setPosition(
World::getWorld()->getCurrentNumKarts() + 1);
World::getWorld()->getKart(kartid)->finishedRace(
World::getWorld()->getTime());
} // eliminatePlayer
// ----------------------------------------------------------------------------
/** Called on the client when an itemCollected message is received.
*/
@ -115,10 +116,10 @@ void GameEventsProtocol::collectedItem(const NetworkString &data)
uint8_t kart_id = data.getUInt8();
// now set the kart powerup
AbstractKart* kart = World::getWorld()->getKart(kart_id);
Log::info("GameEventsProtocol", "Item %d of index %d picked by a player.",
powerup_type, item_id);
ItemManager::get()->collectedItem(ItemManager::get()->getItem(item_id),
kart, powerup_type);
Log::info("GameEventsProtocol", "Item %d picked by a player.",
powerup_type);
} // collectedItem
// ----------------------------------------------------------------------------
@ -155,39 +156,3 @@ void GameEventsProtocol::kartFinishedRace(const NetworkString &ns)
World::getWorld()->getKart(kart_id)->finishedRace(time,
/*from_server*/true);
} // kartFinishedRace
// ----------------------------------------------------------------------------
/** Called on a client when it has started its ready-set-go. The client will
* inform the server anout this. The server will wait for all clients to
* have started before it will start its own countdown.
*/
void GameEventsProtocol::clientHasStarted()
{
assert(NetworkConfig::get()->isClient());
NetworkString *ns = getNetworkString(1);
ns->setSynchronous(true);
ns->addUInt8(GE_CLIENT_STARTED_RSG);
sendToServer(ns, /*reliable*/true);
delete ns;
} // clientHasStarted
// ----------------------------------------------------------------------------
/** Called on the server when a client has signaled that it has started ready
* set go. The server waits for the last client before it starts its own
* ready set go. */
void GameEventsProtocol::receivedClientHasStarted(Event *event)
{
/* assert(NetworkConfig::get()->isServer());
m_count_ready_clients++;
Log::verbose("GameEvent",
"Host %d has started ready-set-go: %d out of %d done",
event->getPeer()->getHostId(), m_count_ready_clients,
STKHost::get()->getGameSetup()->getPlayerCount() );
if (m_count_ready_clients==STKHost::get()->getGameSetup()->getPlayerCount())
{
Log::verbose("GameEvent", "All %d clients have started.",
STKHost::get()->getGameSetup()->getPlayerCount());
// SIgnal the server to start now - since it is now behind the client
// times by the latency of the 'slowest' client.
World::getWorld()->startReadySetGo();
}*/
} // receivedClientHasStarted

View File

@ -9,19 +9,15 @@ class Item;
class GameEventsProtocol : public Protocol
{
private:
enum GameEventType {
GE_CLIENT_STARTED_RSG = 0x01,
GE_ITEM_COLLECTED = 0x02,
GE_KART_FINISHED_RACE = 0x03
public:
enum GameEventType : uint8_t
{
GE_ITEM_COLLECTED = 1,
GE_KART_FINISHED_RACE = 2,
GE_PLAYER_DISCONNECT = 3
}; // GameEventType
/** Count how many clients have started 'ready'. The server
* will only go to its 'ready' phase if all client shave done so.
* This means the server time is far enough behind the clients
* that at time T all client messages for time T have been
* received (short of latency spikes). */
int m_count_ready_clients;
private:
void eliminatePlayer(const NetworkString &ns);
public:
GameEventsProtocol();
@ -31,16 +27,14 @@ public:
void collectedItem(Item* item, AbstractKart* kart);
void collectedItem(const NetworkString &ns);
void kartFinishedRace(AbstractKart *kart, float time);
void clientHasStarted();
void receivedClientHasStarted(Event *event);
void kartFinishedRace(const NetworkString &ns);
virtual void setup() OVERRIDE;
virtual void setup() OVERRIDE {}
virtual void update(int ticks) OVERRIDE {};
virtual void asynchronousUpdate() OVERRIDE{}
// ------------------------------------------------------------------------
virtual bool notifyEventAsynchronous(Event* event) OVERRIDE
{
return false;
return false;
} // notifyEventAsynchronous

View File

@ -334,8 +334,7 @@ void GameProtocol::rewind(BareNetworkString *buffer)
int value_r = buffer->getUInt32();
Controller *c = World::getWorld()->getKart(kart_id)->getController();
PlayerController *pc = dynamic_cast<PlayerController*>(c);
// FIXME this can be endcontroller when finishing the race
//assert(pc);
if(pc)
// This can be endcontroller when finishing the race
if (pc)
pc->actionFromNetwork(action, value, value_l, value_r);
} // rewind

View File

@ -36,14 +36,15 @@ std::weak_ptr<LobbyProtocol> LobbyProtocol::m_lobby;
LobbyProtocol::LobbyProtocol(CallbackObject* callback_object)
: Protocol(PROTOCOL_LOBBY_ROOM, callback_object)
{
m_game_setup = NULL;
m_game_setup = new GameSetup();
} // LobbyProtocol
// ----------------------------------------------------------------------------
LobbyProtocol::~LobbyProtocol()
{
if (m_game_setup)
delete m_game_setup;
if (RaceEventManager::getInstance())
RaceEventManager::getInstance()->stop();
delete m_game_setup;
} // ~LobbyProtocol
//-----------------------------------------------------------------------------
@ -62,24 +63,21 @@ void LobbyProtocol::loadWorld()
// Race startup sequence
// ---------------------
// This creates the network world.
RaceEventManager::getInstance<RaceEventManager>()->start();
auto gep = std::make_shared<GameEventsProtocol>();
RaceEventManager::getInstance<RaceEventManager>()->start(gep);
// Make sure that if there is only a single local player this player can
// use all input devices.
StateManager::ActivePlayer *ap = race_manager->getNumLocalPlayers()>1
? NULL
: StateManager::get()->getActivePlayer(0);
// Reset the ai kart list in the race manager, otherwise in network race
// we can get an assertion if previously a local race with AI was done
std::vector<std::string> ai_kart_list;
race_manager->setAIKartList(ai_kart_list);
input_manager->getDeviceManager()->setSinglePlayer(ap);
// Load the actual world.
m_game_setup->loadWorld();
World::getWorld()->setNetworkWorld(true);
GameProtocol::createInstance()->requestStart();
std::make_shared<GameEventsProtocol>()->requestStart();
gep->requestStart();
} // loadWorld
@ -134,6 +132,8 @@ void LobbyProtocol::configRemoteKart(
// Inform the race manager about the data for this kart.
race_manager->setPlayerKart(i, rki);
} // for i in players
// Clean all previous AI if exists in offline game
race_manager->computeRandomKartList();
Log::info("LobbyProtocol", "Player configuration ready.");
} // configRemoteKart
@ -143,7 +143,5 @@ void LobbyProtocol::configRemoteKart(
*/
void LobbyProtocol::setup()
{
if (m_game_setup)
delete m_game_setup;
m_game_setup = new GameSetup();
m_game_setup->reset();
} // setupNewGame

View File

@ -43,9 +43,8 @@ public:
LE_CONNECTION_REQUESTED = 1, // a connection to the server
LE_CONNECTION_REFUSED, // Connection to server refused
LE_CONNECTION_ACCEPTED, // Connection to server accepted
LE_KART_SELECTION_UPDATE, // inform client about kart selected
LE_SERVER_INFO, // inform client about server info
LE_REQUEST_BEGIN, // begin of kart selection
LE_KART_SELECTION_REFUSED, // Client not auth. to start selection
LE_UPDATE_PLAYER_LIST, // inform client about player list update
LE_KART_SELECTION, // Player selected kart
LE_PLAYER_DISCONNECTED, // Client disconnected
@ -114,6 +113,7 @@ public:
virtual void finishedLoadingWorld() = 0;
virtual void loadWorld();
virtual bool waitingForPlayers() const = 0;
virtual bool allPlayersReady() const = 0;
GameSetup* getGameSetup() const { return m_game_setup; }
}; // class LobbyProtocol

View File

@ -20,13 +20,14 @@
#include "config/user_config.hpp"
#include "karts/kart_properties_manager.hpp"
#include "modes/world.hpp"
#include "modes/linear_world.hpp"
#include "network/event.hpp"
#include "network/game_setup.hpp"
#include "network/network_config.hpp"
#include "network/network_player_profile.hpp"
#include "network/protocols/connect_to_peer.hpp"
#include "network/protocol_manager.hpp"
#include "network/protocols/game_protocol.hpp"
#include "network/protocols/game_events_protocol.hpp"
#include "network/race_event_manager.hpp"
#include "network/stk_host.hpp"
#include "network/stk_peer.hpp"
@ -106,6 +107,7 @@ ServerLobby::~ServerLobby()
void ServerLobby::setup()
{
LobbyProtocol::setup();
StateManager::get()->resetActivePlayers();
// We use maximum 16bit unsigned limit
auto all_k = kart_properties_manager->getAllAvailableKarts();
auto all_t = track_manager->getAllTrackIdentifiers();
@ -122,7 +124,7 @@ void ServerLobby::setup()
// Initialise the data structures to detect if all clients and
// the server are ready:
m_server_has_loaded_world.store(false);
m_peers_ready.clear();
resetPeersReady();
m_peers_votes.clear();
m_server_delay = 0.0;
Log::info("ServerLobby", "Reset server to initial state.");
@ -144,6 +146,7 @@ bool ServerLobby::notifyEvent(Event* event)
switch (message_type)
{
case LE_REQUEST_BEGIN: startSelection(event); break;
case LE_RACE_FINISHED_ACK: playerFinishedResult(event); break;
default: Log::error("ServerLobby", "Unknown message type %d - ignored.",
message_type);
break;
@ -205,7 +208,6 @@ bool ServerLobby::notifyEventAsynchronous(Event* event)
case LE_CLIENT_LOADED_WORLD: finishedLoadingWorldClient(event); break;
case LE_STARTED_RACE: startedRaceOnClient(event); break;
case LE_VOTE: playerVote(event); break;
case LE_RACE_FINISHED_ACK: playerFinishedResult(event); break;
case LE_KICK_HOST: kickHost(event); break;
case LE_CHAT: handleChat(event); break;
default: break;
@ -256,6 +258,7 @@ void ServerLobby::asynchronousUpdate()
}
else
{
m_server_address.copy(STKHost::get()->getPublicAddress());
STKHost::get()->startListening();
m_state = REGISTER_SELF_ADDRESS;
}
@ -298,10 +301,7 @@ void ServerLobby::asynchronousUpdate()
return;
m_state = WAIT_FOR_RACE_STARTED;
// Reset for next state usage
for (auto p : m_peers_ready)
{
p.second = false;
}
resetPeersReady();
signalRaceStartToClients();
break;
}
@ -351,10 +351,7 @@ void ServerLobby::asynchronousUpdate()
configRemoteKart(players);
// Reset for next state usage
for (auto p : m_peers_ready)
{
p.second = false;
}
resetPeersReady();
m_state = LOAD_WORLD;
sendMessageToPeersChangingToken(load_world);
delete load_world;
@ -366,21 +363,6 @@ void ServerLobby::asynchronousUpdate()
} // asynchronousUpdate
//-----------------------------------------------------------------------------
bool ServerLobby::checkPeersReady() const
{
bool all_ready = true;
for (auto p : m_peers_ready)
{
if (p.first.expired())
continue;
all_ready = all_ready && p.second;
if (!all_ready)
return false;
}
return true;
} // checkPeersReady
//-----------------------------------------------------------------------------
/** Simple finite state machine. Once this
* is known, register the server and its address with the stk server so that
@ -388,6 +370,22 @@ bool ServerLobby::checkPeersReady() const
*/
void ServerLobby::update(int ticks)
{
// Reset server to initial state if no more connected players
if (m_state.load() > ACCEPTING_CLIENTS &&
STKHost::get()->getPeerCount() == 0 &&
NetworkConfig::get()->getServerIdFile().empty())
{
if (RaceEventManager::getInstance() &&
RaceEventManager::getInstance()->isRunning())
{
stopCurrentRace();
}
std::lock_guard<std::mutex> lock(m_connection_mutex);
m_state = NetworkConfig::get()->isLAN() ?
ACCEPTING_CLIENTS : REGISTER_SELF_ADDRESS;
setup();
}
// Check if server owner has left
updateServerOwner();
if (m_game_setup)
@ -402,7 +400,7 @@ void ServerLobby::update(int ticks)
case REGISTER_SELF_ADDRESS:
case ACCEPTING_CLIENTS:
case WAIT_FOR_WORLD_LOADED:
case WAIT_FOR_RACE_STARTED:
case WAIT_FOR_RACE_STARTED:
case DELAY_SERVER:
{
// Waiting for asynchronousUpdate
@ -426,20 +424,9 @@ void ServerLobby::update(int ticks)
}
break;
case RESULT_DISPLAY:
if(StkTime::getRealTime() > m_timeout.load())
if (checkPeersReady() ||
StkTime::getRealTime() > m_timeout.load())
{
RaceResultGUI::getInstance()->backToLobby();
// notify the network world that it is stopped
RaceEventManager::getInstance()->stop();
// stop race protocols
auto pm = ProtocolManager::lock();
assert(pm);
pm->findAndTerminate(PROTOCOL_CONTROLLER_EVENTS);
pm->findAndTerminate(PROTOCOL_KART_UPDATE);
pm->findAndTerminate(PROTOCOL_GAME_EVENTS);
setup();
m_state = NetworkConfig::get()->isLAN() ?
ACCEPTING_CLIENTS : REGISTER_SELF_ADDRESS;
// Send a notification to all clients to exit
// the race result screen
NetworkString *exit_result_screen = getNetworkString(1);
@ -448,6 +435,17 @@ void ServerLobby::update(int ticks)
sendMessageToPeersChangingToken(exit_result_screen,
/*reliable*/true);
delete exit_result_screen;
std::lock_guard<std::mutex> lock(m_connection_mutex);
m_state = NetworkConfig::get()->isLAN() ?
ACCEPTING_CLIENTS : REGISTER_SELF_ADDRESS;
updatePlayerList();
NetworkString* server_info = getNetworkString();
server_info->setSynchronous(true);
server_info->addUInt8(LE_SERVER_INFO);
m_game_setup->addServerInfo(server_info);
sendMessageToPeersChangingToken(server_info);
delete server_info;
setup();
}
break;
case ERROR_LEAVE:
@ -466,25 +464,23 @@ void ServerLobby::update(int ticks)
void ServerLobby::registerServer()
{
Online::XMLRequest *request = new Online::XMLRequest();
const TransportAddress& addr = STKHost::get()->getPublicAddress();
NetworkConfig::get()->setUserDetails(request, "create");
request->addParameter("address", addr.getIP() );
request->addParameter("port", addr.getPort() );
request->addParameter("address", m_server_address.getIP() );
request->addParameter("port", m_server_address.getPort() );
request->addParameter("private_port",
STKHost::get()->getPrivatePort() );
request->addParameter("name", NetworkConfig::get()->getServerName() );
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()));
request->addParameter("game_mode", NetworkConfig::get()->getServerMode());
request->addParameter("password",
(unsigned)(!NetworkConfig::get()->getPassword().empty()));
request->addParameter("version",
(unsigned)NetworkConfig::m_server_version);
Log::info("ServerLobby", "Public server addr %s", addr.toString().c_str());
Log::info("ServerLobby", "Public server address %s",
m_server_address.toString().c_str());
request->executeNow();
@ -511,14 +507,13 @@ void ServerLobby::registerServer()
*/
void ServerLobby::unregisterServer()
{
const TransportAddress &addr = STKHost::get()->getPublicAddress();
Online::XMLRequest* request = new Online::XMLRequest();
NetworkConfig::get()->setUserDetails(request, "stop");
request->addParameter("address", addr.getIP());
request->addParameter("port", addr.getPort());
Log::info("ServerLobby", "address %s", addr.toString().c_str());
request->addParameter("address", m_server_address.getIP());
request->addParameter("port", m_server_address.getPort());
Log::info("ServerLobby", "Unregister server address %s",
m_server_address.toString().c_str());
request->executeNow();
const XMLNode * result = request->getXMLData();
@ -593,6 +588,24 @@ void ServerLobby::startSelection(const Event *event)
// a new screen, which must be donefrom the main thread.
ns->setSynchronous(true);
ns->addUInt8(LE_START_SELECTION);
// Remove karts / tracks from server that are not supported on all clients
std::set<std::string> karts_erase, tracks_erase;
auto peers = STKHost::get()->getPeers();
for (auto peer : peers)
{
peer->eraseServerKarts(m_available_kts.first, karts_erase);
peer->eraseServerTracks(m_available_kts.second, tracks_erase);
}
for (const std::string& kart_erase : karts_erase)
{
m_available_kts.first.erase(kart_erase);
}
for (const std::string& track_erase : tracks_erase)
{
m_available_kts.second.erase(track_erase);
}
const auto& all_k = m_available_kts.first;
const auto& all_t = m_available_kts.second;
ns->addUInt16((uint16_t)all_k.size()).addUInt16((uint16_t)all_t.size());
@ -672,51 +685,60 @@ void ServerLobby::checkIncomingConnectionRequests()
* to state RESULT_DISPLAY, during which the race result gui is shown and all
* clients can click on 'continue'.
*/
void ServerLobby::checkRaceFinished()
void ServerLobby::checkRaceFinished()
{
assert(RaceEventManager::getInstance()->isRunning());
assert(World::getWorld());
if(!RaceEventManager::getInstance()->isRaceOver()) return;
if (!RaceEventManager::getInstance()->isRaceOver()) return;
m_player_ready_counter = 0;
// Set the delay before the server forces all clients to exit the race
// result screen and go back to the lobby
m_timeout.store((float)(StkTime::getRealTime()+15.0f));
m_state = RESULT_DISPLAY;
// calculate karts ranks :
int num_karts = race_manager->getNumberOfKarts();
std::vector<int> karts_results;
std::vector<float> karts_times;
for (int j = 0; j < num_karts; j++)
{
float kart_time = race_manager->getKartRaceTime(j);
for (unsigned int i = 0; i < karts_times.size(); i++)
{
if (kart_time < karts_times[i])
{
karts_times.insert(karts_times.begin() + i, kart_time);
karts_results.insert(karts_results.begin() + i, j);
break;
}
}
}
NetworkString *total = getNetworkString(1 + karts_results.size());
// Reset for next state usage
resetPeersReady();
NetworkString* total = getNetworkString();
total->setSynchronous(true);
total->addUInt8(LE_RACE_FINISHED);
for (unsigned int i = 0; i < karts_results.size(); i++)
if (m_game_setup->isGrandPrix())
{
total->addUInt8(karts_results[i]); // kart pos = i+1
Log::info("ServerLobby", "Kart %d finished #%d",
karts_results[i], i + 1);
// fastest lap, and than each kart before / after grand prix points
}
else if (race_manager->modeHasLaps())
{
int fastest_lap =
static_cast<LinearWorld*>(World::getWorld())->getFastestLapTicks();
total->addUInt32(fastest_lap);
}
stopCurrentRace();
// Set the delay before the server forces all clients to exit the race
// result screen and go back to the lobby
m_timeout.store((float)StkTime::getRealTime() + 15.0f);
m_state = RESULT_DISPLAY;
sendMessageToPeersChangingToken(total, /*reliable*/ true);
delete total;
Log::info("ServerLobby", "End of game message sent");
} // checkRaceFinished
//-----------------------------------------------------------------------------
/** Stop any race currently in server, should only be called in main thread.
*/
void ServerLobby::stopCurrentRace()
{
// notify the network world that it is stopped
RaceEventManager::getInstance()->stop();
// stop race protocols before going back to lobby (end race)
RaceEventManager::getInstance()->getProtocol()->requestTerminate();
GameProtocol::lock()->requestTerminate();
while (!RaceEventManager::getInstance()->protocolStopped())
StkTime::sleep(1);
while (!GameProtocol::emptyInstance())
StkTime::sleep(1);
// This will go back to lobby in server (and exit the current race)
RaceResultGUI::getInstance()->backToLobby();
} // stopCurrentRace
//-----------------------------------------------------------------------------
/** Called when a client disconnects.
* \param event The disconnect event.
@ -775,6 +797,21 @@ void ServerLobby::connectionRequested(Event* event)
return;
}
// Check server version
int version = data.getUInt8();
if (version < stk_config->m_max_server_version ||
version > stk_config->m_max_server_version)
{
NetworkString *message = getNetworkString(2);
message->addUInt8(LE_CONNECTION_REFUSED)
.addUInt8(RR_INCOMPATIBLE_DATA);
peer->sendPacket(message);
peer->reset();
delete message;
Log::verbose("ServerLobby", "Player refused: wrong server version");
return;
}
// Check for password
std::string password;
data.decodeString(&password);
@ -869,9 +906,8 @@ void ServerLobby::connectionRequested(Event* event)
client_tracks.insert(track);
}
// Remove karts/tracks from server that are not supported on the new client
// so that in the end the server has a list of all karts/tracks available
// on all clients
// Drop this player if he doesn't have at least 1 kart / track the same
// as server
std::set<std::string> karts_erase, tracks_erase;
for (const std::string& server_kart : m_available_kts.first)
{
@ -888,8 +924,6 @@ void ServerLobby::connectionRequested(Event* event)
}
}
// Drop this player if he doesn't have at least 1 kart / track the same
// from server
if (karts_erase.size() == m_available_kts.first.size() ||
tracks_erase.size() == m_available_kts.second.size())
{
@ -904,14 +938,9 @@ void ServerLobby::connectionRequested(Event* event)
return;
}
for (const std::string& kart_erase : karts_erase)
{
m_available_kts.first.erase(kart_erase);
}
for (const std::string& track_erase : tracks_erase)
{
m_available_kts.second.erase(track_erase);
}
// Save available karts and tracks from clients in STKPeer so if this peer
// disconnects later in lobby it won't affect current players
peer->setAvailableKartsTracks(client_karts, client_tracks);
if (!peer->isClientServerTokenSet())
{
@ -926,13 +955,22 @@ void ServerLobby::connectionRequested(Event* event)
peer->setClientServerToken(token);
}
// send a message to the one that asked to connect
NetworkString *message_ack = getNetworkString(4);
NetworkString* message_ack = getNetworkString(4);
message_ack->setSynchronous(true);
// connection success -- return the host id of peer
message_ack->addUInt8(LE_CONNECTION_ACCEPTED).addUInt32(peer->getHostId());
peer->sendPacket(message_ack);
delete message_ack;
NetworkString* server_info = getNetworkString();
server_info->setSynchronous(true);
server_info->addUInt8(LE_SERVER_INFO);
m_game_setup->addServerInfo(server_info);
peer->sendPacket(server_info);
delete server_info;
m_peers_ready[peer] = false;
for (std::shared_ptr<NetworkPlayerProfile> npp : peer->getPlayerProfiles())
{
@ -947,7 +985,7 @@ void ServerLobby::connectionRequested(Event* event)
//-----------------------------------------------------------------------------
void ServerLobby::updatePlayerList()
{
if (m_state.load() != ACCEPTING_CLIENTS)
if (m_state.load() > ACCEPTING_CLIENTS)
return;
auto all_profiles = STKHost::get()->getAllPlayerProfiles();
NetworkString* pl = getNetworkString();
@ -1045,7 +1083,7 @@ void ServerLobby::kartSelectionRequested(Event* event)
{
peer->getPlayerProfiles()[i]->setKartName(kart);
}
Log::verbose("ServerLobby", "Player %d from peer %d chose %s", i,
Log::debug("ServerLobby", "Player %d from peer %d chose %s", i,
peer->getHostId(), kart.c_str());
}
} // kartSelectionRequested
@ -1083,8 +1121,8 @@ void ServerLobby::playerVote(Event* event)
NetworkString other = NetworkString(PROTOCOL_LOBBY_ROOM);
std::string name = StringUtils::wideToUtf8(event->getPeer()
->getPlayerProfiles()[0]->getName());
other.addUInt8(LE_VOTE).addFloat(m_timeout.load()).encodeString(name)
.addUInt32(event->getPeer()->getHostId());
other.addUInt8(LE_VOTE).addFloat(UserConfigParams::m_voting_timeout)
.encodeString(name).addUInt32(event->getPeer()->getHostId());
other += data;
std::string track_name;
@ -1227,14 +1265,10 @@ void ServerLobby::startedRaceOnClient(Event *event)
*/
void ServerLobby::playerFinishedResult(Event *event)
{
m_player_ready_counter++;
if(m_player_ready_counter >= (int)STKHost::get()->getPeerCount())
{
// We can't trigger the world/race exit here, since this is called
// from the protocol manager thread. So instead we force the timeout
// to get triggered (which is done from the main thread):
m_timeout.store(0);
}
if (m_state.load() != RESULT_DISPLAY)
return;
std::shared_ptr<STKPeer> peer = event->getPeerSP();
m_peers_ready.at(peer) = true;
} // playerFinishedResult
//-----------------------------------------------------------------------------

View File

@ -2,6 +2,7 @@
#define SERVER_LOBBY_HPP
#include "network/protocols/lobby_protocol.hpp"
#include "network/transport_address.hpp"
#include "utils/cpp2011.hpp"
#include <atomic>
@ -65,9 +66,6 @@ private:
/** It indicates if this server is registered with the stk server. */
std::atomic_bool m_server_registered;
/** Counts how many players are ready to go on. */
int m_player_ready_counter;
/** Timeout counter for various state. */
std::atomic<float> m_timeout;
@ -78,6 +76,8 @@ private:
/** Ban list ip (in decimal) with online user id. */
std::map<uint32_t, uint32_t> m_ban_list;
TransportAddress m_server_address;
// connection management
void clientDisconnected(Event* event);
void connectionRequested(Event* event);
@ -95,8 +95,36 @@ private:
void createServerIdFile();
void updatePlayerList();
void updateServerOwner();
bool checkPeersReady() const;
bool checkPeersReady() const
{
bool all_ready = true;
for (auto p : m_peers_ready)
{
if (p.first.expired())
continue;
all_ready = all_ready && p.second;
if (!all_ready)
return false;
}
return true;
}
void resetPeersReady()
{
for (auto it = m_peers_ready.begin(); it != m_peers_ready.end();)
{
if (it->first.expired())
{
it = m_peers_ready.erase(it);
}
else
{
it->second = false;
it++;
}
}
}
std::tuple<std::string, uint8_t, bool> handleVote();
void stopCurrentRace();
public:
ServerLobby();
@ -117,6 +145,8 @@ public:
void updateBanList();
virtual bool waitingForPlayers() const OVERRIDE
{ return m_state.load() == ACCEPTING_CLIENTS; }
virtual bool allPlayersReady() const OVERRIDE
{ return m_state.load() >= WAIT_FOR_RACE_STARTED; }
}; // class ServerLobby

View File

@ -4,7 +4,6 @@
#include "karts/controller/controller.hpp"
#include "modes/world.hpp"
#include "network/network_config.hpp"
#include "network/protocol_manager.hpp"
#include "network/protocols/game_events_protocol.hpp"
#include "network/rewind_manager.hpp"
#include "utils/profiler.hpp"
@ -26,18 +25,13 @@ RaceEventManager::~RaceEventManager()
*/
void RaceEventManager::update(int ticks)
{
// Replay all recorded events up to the current time (only if the
// timer isn't stopped, otherwise a potential rewind will trigger
// an infinite loop since world time does not increase)
if (World::getWorld()->getPhase() != WorldStatus::IN_GAME_MENU_PHASE)
{
// This might adjust dt - if a new state is being played, the dt is
// determined from the last state till 'now'
PROFILER_PUSH_CPU_MARKER("RaceEvent:play event", 100, 100, 100);
RewindManager::get()->playEventsTill(World::getWorld()->getTimeTicks(),
&ticks);
PROFILER_POP_CPU_MARKER();
}
// Replay all recorded events up to the current time
// This might adjust dt - if a new state is being played, the dt is
// determined from the last state till 'now'
PROFILER_PUSH_CPU_MARKER("RaceEvent:play event", 100, 100, 100);
RewindManager::get()->playEventsTill(World::getWorld()->getTimeTicks(),
&ticks);
PROFILER_POP_CPU_MARKER();
World::getWorld()->updateWorld(ticks);
// if the race is over
@ -50,18 +44,6 @@ void RaceEventManager::update(int ticks)
}
} // update
// ----------------------------------------------------------------------------
void RaceEventManager::start()
{
m_running = true;
} // start
// ----------------------------------------------------------------------------
void RaceEventManager::stop()
{
m_running = false;
} // stop
// ----------------------------------------------------------------------------
bool RaceEventManager::isRaceOver()
{
@ -74,9 +56,8 @@ bool RaceEventManager::isRaceOver()
// ----------------------------------------------------------------------------
void RaceEventManager::kartFinishedRace(AbstractKart *kart, float time)
{
auto protocol = std::static_pointer_cast<GameEventsProtocol>(
ProtocolManager::lock()->getProtocol(PROTOCOL_GAME_EVENTS));
protocol->kartFinishedRace(kart, time);
if (auto game_events_protocol = m_game_events_protocol.lock())
game_events_protocol->kartFinishedRace(kart, time);
} // kartFinishedRace
// ----------------------------------------------------------------------------
@ -89,9 +70,7 @@ void RaceEventManager::collectedItem(Item *item, AbstractKart *kart)
{
// this is only called in the server
assert(NetworkConfig::get()->isServer());
auto protocol = std::static_pointer_cast<GameEventsProtocol>(
ProtocolManager::lock()->getProtocol(PROTOCOL_GAME_EVENTS));
protocol->collectedItem(item,kart);
if (auto game_events_protocol = m_game_events_protocol.lock())
game_events_protocol->collectedItem(item, kart);
} // collectedItem

View File

@ -21,10 +21,10 @@
#include "input/input.hpp"
#include "utils/singleton.hpp"
#include <map>
#include <memory>
class Controller;
class KartUpdateProtocol;
class GameEventsProtocol;
class AbstractKart;
class Item;
@ -40,23 +40,38 @@ private:
bool m_running;
float m_race_time;
std::weak_ptr<GameEventsProtocol> m_game_events_protocol;
friend class AbstractSingleton<RaceEventManager>;
RaceEventManager();
virtual ~RaceEventManager();
public:
// ------------------------------------------------------------------------
void update(int ticks);
void start();
void stop();
bool isRaceOver();
void collectedItem(Item *item, AbstractKart *kart);
void kartFinishedRace(AbstractKart *kart, float time);
// ------------------------------------------------------------------------
void start(std::shared_ptr<GameEventsProtocol> gep)
{
m_game_events_protocol = gep;
m_running = true;
}
// ------------------------------------------------------------------------
void stop() { m_running = false; }
// ------------------------------------------------------------------------
/** Returns if this instance is in running state or not. */
bool isRunning() { return m_running; }
bool isRunning() { return m_running; }
// ------------------------------------------------------------------------
std::shared_ptr<GameEventsProtocol> getProtocol() const
{ return m_game_events_protocol.lock(); }
// ------------------------------------------------------------------------
bool protocolStopped() const { return m_game_events_protocol.expired(); }
// ------------------------------------------------------------------------
bool isRaceOver();
// ------------------------------------------------------------------------
void collectedItem(Item *item, AbstractKart *kart);
// ------------------------------------------------------------------------
void kartFinishedRace(AbstractKart *kart, float time);
};

View File

@ -346,15 +346,6 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
// Now start the rewind with the full state:
world->setTicks(exact_rewind_ticks);
// Need to exit loop if in-game menu is open, since world clock
// will not be increased while the game is paused
if (World::getWorld()->getPhase() == WorldStatus::IN_GAME_MENU_PHASE)
{
m_is_rewinding = false;
history->setReplayHistory(is_history);
return;
}
// Get the (first) full state to which we have to rewind
RewindInfo *current = m_rewind_queue.getCurrent();
assert(current->isState());
@ -395,5 +386,3 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
history->setReplayHistory(is_history);
m_is_rewinding = false;
} // rewindTo
// ----------------------------------------------------------------------------

View File

@ -39,10 +39,9 @@ Server::Server(const XMLNode& xml)
m_current_players = 0;
m_max_players = 0;
m_distance = 0.0f;
m_server_mode = 0;
xml.get("game_mode", &m_server_mode);
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;
@ -121,8 +120,7 @@ Server::Server(unsigned server_id, const core::stringw &name, int max_players,
// In case of LAN server, public and private port are the same.
m_private_port = m_address.getPort();
m_difficulty = (RaceManager::Difficulty)difficulty;
m_minor_mode = NetworkConfig::get()->getLocalGameMode(server_mode).first;
m_major_mode = NetworkConfig::get()->getLocalGameMode(server_mode).second;
m_server_mode = server_mode;
m_password_protected = password_protected;
m_distance = 0.0f;
} // server(server_id, ...)

View File

@ -68,9 +68,7 @@ protected:
* connection using the private port with a broadcast is possible. */
uint16_t m_private_port;
RaceManager::MinorRaceModeType m_minor_mode;
RaceManager::MajorRaceModeType m_major_mode;
unsigned m_server_mode;
RaceManager::Difficulty m_difficulty;
@ -115,11 +113,7 @@ public:
/** Returns the number of currently connected players. */
const int getCurrentPlayers() const { return m_current_players; }
// ------------------------------------------------------------------------
RaceManager::MinorRaceModeType getRaceMinorMode() const
{ return m_minor_mode; }
// ------------------------------------------------------------------------
RaceManager::MajorRaceModeType getRaceMajorMode() const
{ return m_major_mode; }
unsigned getServerMode() const { return m_server_mode; }
// ------------------------------------------------------------------------
RaceManager::Difficulty getDifficulty() const { return m_difficulty; }
// ------------------------------------------------------------------------

View File

@ -18,6 +18,7 @@
#include "network/servers_manager.hpp"
#include "config/stk_config.hpp"
#include "config/user_config.hpp"
#include "network/network.hpp"
#include "network/network_config.hpp"
@ -160,8 +161,9 @@ Online::XMLRequest* ServersManager::getLANRefreshRequest() const
if (len > 0)
{
BareNetworkString s(buffer, len);
uint8_t version = s.getUInt8();
if (version != NetworkConfig::m_server_version)
int version = s.getUInt8();
if (version < stk_config->m_max_server_version ||
version > stk_config->m_max_server_version)
{
Log::verbose("ServersManager", "Skipping a server");
continue;
@ -236,10 +238,11 @@ void ServersManager::setWanServers(bool success, const XMLNode* input)
const XMLNode *servers_xml = input->getNode("servers");
for (unsigned int i = 0; i < servers_xml->getNumNodes(); i++)
{
unsigned version = 0;
int version = 0;
servers_xml->getNode(i)->get("version", &version);
assert(version != 0);
if (version != NetworkConfig::m_server_version)
if (version < stk_config->m_max_server_version ||
version > stk_config->m_max_server_version)
{
Log::verbose("ServersManager", "Skipping a server");
continue;

View File

@ -67,25 +67,27 @@
STKHost *STKHost::m_stk_host = NULL;
bool STKHost::m_enable_console = false;
void STKHost::create(std::shared_ptr<Server> server, SeparateProcess* p)
std::shared_ptr<LobbyProtocol> STKHost::create(SeparateProcess* p)
{
assert(m_stk_host == NULL);
std::shared_ptr<LobbyProtocol> lp;
if (NetworkConfig::get()->isServer())
{
std::shared_ptr<ServerLobby> sl = LobbyProtocol::create<ServerLobby>();
m_stk_host = new STKHost(NetworkConfig::get()->getServerName());
sl->requestStart();
lp = LobbyProtocol::create<ServerLobby>();
m_stk_host = new STKHost(true/*server*/);
}
else
{
m_stk_host = new STKHost(server);
m_stk_host = new STKHost(false/*server*/);
}
// Separate process for client-server gui if exists
m_stk_host->m_separate_process = p;
if (!m_stk_host->m_network)
{
delete m_stk_host;
m_stk_host = NULL;
}
return lp;
} // create
// ============================================================================
@ -258,57 +260,42 @@ void STKHost::create(std::shared_ptr<Server> server, SeparateProcess* p)
*/
// ============================================================================
/** Constructor for a client
/** The constructor for a server or client.
*/
STKHost::STKHost(std::shared_ptr<Server> server)
{
// Will be overwritten with the correct value once a connection with the
// server is made.
m_host_id = 0;
init();
ENetAddress ea;
ea.host = STKHost::HOST_ANY;
ea.port = NetworkConfig::get()->getClientPort();
m_network = new Network(/*peer_count*/1, /*channel_limit*/2,
/*max_in_bandwidth*/0, /*max_out_bandwidth*/0,
&ea, true/*change_port_if_bound*/);
if (!m_network)
{
Log::fatal ("STKHost", "An error occurred while trying to create "
"an ENet client host.");
}
setPrivatePort();
} // STKHost
// ----------------------------------------------------------------------------
/** The constructor for a server.
* The server control flow starts with the ServerLobby.
*/
STKHost::STKHost(const irr::core::stringw &server_name)
STKHost::STKHost(bool server)
{
init();
m_host_id = 0; // indicates a server host.
ENetAddress addr;
addr.host = STKHost::HOST_ANY;
addr.port = NetworkConfig::get()->getServerPort();
// Reserver 1 peer to handle full server message
m_network = new Network(NetworkConfig::get()->getMaxPlayers() + 1,
/*channel_limit*/2,
/*max_in_bandwidth*/0,
/*max_out_bandwidth*/ 0, &addr,
true/*change_port_if_bound*/);
if (server)
{
addr.port = NetworkConfig::get()->getServerPort();
// Reserve 1 peer to deliver full server message
m_network = new Network(NetworkConfig::get()->getMaxPlayers() + 1,
/*channel_limit*/2, /*max_in_bandwidth*/0,
/*max_out_bandwidth*/ 0, &addr, true/*change_port_if_bound*/);
}
else
{
addr.port = NetworkConfig::get()->getClientPort();
// Client only has 1 peer
m_network = new Network(/*peer_count*/1, /*channel_limit*/2,
/*max_in_bandwidth*/0, /*max_out_bandwidth*/0, &addr,
true/*change_port_if_bound*/);
}
if (!m_network)
{
Log::fatal("STKHost", "An error occurred while trying to create an "
"ENet server host.");
}
setPrivatePort();
} // STKHost(server_name)
if (server)
Log::info("STKHost", "Server port is %d", m_private_port);
} // STKHost
// ----------------------------------------------------------------------------
/** Initialises the internal data structures and starts the protocol manager
@ -941,9 +928,7 @@ void STKHost::handleDirectSocketRequest(Network* direct_socket,
s.addUInt8((uint8_t)sl->getGameSetup()->getPlayerCount());
s.addUInt16(m_private_port);
s.addUInt8((uint8_t)race_manager->getDifficulty());
s.addUInt8((uint8_t)
NetworkConfig::get()->getServerGameMode(race_manager->getMinorMode(),
race_manager->getMajorMode()));
s.addUInt8((uint8_t)NetworkConfig::get()->getServerMode());
s.addUInt8(!NetworkConfig::get()->getPassword().empty());
direct_socket->sendRawPacket(s, sender);
} // if message is server-requested
@ -974,6 +959,12 @@ void STKHost::handleDirectSocketRequest(Network* direct_socket,
Log::error("STKHost", "which is not localhost - rejected.");
}
}
else if (command == "stk-server-port")
{
BareNetworkString s;
s.addUInt16(m_private_port);
direct_socket->sendRawPacket(s, sender);
}
else
Log::info("STKHost", "Received unknown command '%s'",
std::string(buffer, len).c_str());

View File

@ -43,6 +43,7 @@
#include <tuple>
class GameSetup;
class LobbyProtocol;
class NetworkPlayerProfile;
class Server;
class ServerLobby;
@ -132,9 +133,7 @@ private:
uint16_t m_private_port;
// ------------------------------------------------------------------------
STKHost(std::shared_ptr<Server> server);
// ------------------------------------------------------------------------
STKHost(const irr::core::stringw &server_name);
STKHost(bool server);
// ------------------------------------------------------------------------
~STKHost();
// ------------------------------------------------------------------------
@ -154,9 +153,7 @@ public:
/** Creates the STKHost. It takes all confifguration parameters from
* NetworkConfig. This STKHost can either be a client or a server.
*/
static void create(std::shared_ptr<Server> server = nullptr,
SeparateProcess* p = NULL);
static std::shared_ptr<LobbyProtocol> create(SeparateProcess* p = NULL);
// ------------------------------------------------------------------------
/** Returns the instance of STKHost. */
static STKHost *get()

View File

@ -31,6 +31,7 @@
#include <atomic>
#include <memory>
#include <set>
#include <vector>
class NetworkPlayerProfile;
@ -72,6 +73,9 @@ protected:
float m_connected_time;
/** Available karts and tracks from this peer */
std::pair<std::set<std::string>, std::set<std::string> > m_available_kts;
public:
STKPeer(ENetPeer *enet_peer, STKHost* host, uint32_t host_id);
~STKPeer() {}
@ -126,6 +130,40 @@ public:
// ------------------------------------------------------------------------
float getConnectedTime() const { return m_connected_time; }
// ------------------------------------------------------------------------
void setAvailableKartsTracks(std::set<std::string>& k,
std::set<std::string>& t)
{ m_available_kts = std::make_pair(std::move(k), std::move(t)); }
// ------------------------------------------------------------------------
void eraseServerKarts(const std::set<std::string>& server_karts,
std::set<std::string>& karts_erase)
{
if (m_available_kts.first.empty())
return;
for (const std::string& server_kart : server_karts)
{
if (m_available_kts.first.find(server_kart) ==
m_available_kts.first.end())
{
karts_erase.insert(server_kart);
}
}
}
// ------------------------------------------------------------------------
void eraseServerTracks(const std::set<std::string>& server_tracks,
std::set<std::string>& tracks_erase)
{
if (m_available_kts.second.empty())
return;
for (const std::string& server_track : server_tracks)
{
if (m_available_kts.second.find(server_track) ==
m_available_kts.second.end())
{
tracks_erase.insert(server_track);
}
}
}
// ------------------------------------------------------------------------
uint32_t getPing() const;
}; // STKPeer

View File

@ -250,8 +250,7 @@ void CreateServerScreen::createServer()
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, !password.empty());
0, server_address, !password.empty());
#undef USE_GRAPHICS_SERVER
#ifdef USE_GRAPHICS_SERVER
@ -276,7 +275,9 @@ void CreateServerScreen::createServer()
race_manager->setMinorMode(RaceManager::MINOR_MODE_NORMAL_RACE);
race_manager->setReverseTrack(false);
STKHost::create();
auto sl = STKHost::create();
assert(sl);
sl->requestStart();
#else
NetworkConfig::get()->setIsServer(false);
@ -311,10 +312,26 @@ void CreateServerScreen::createServer()
" --server-id-file=" << server_id_file <<
" --log=1 --no-console-log";
if (m_more_options_spinner->isVisible())
{
int esi = m_more_options_spinner->getValue();
if (gamemode_widget->getSelection(PLAYER_ID_GAME_MASTER)
!= 3/*is soccer*/)
{
// Grand prix track count
if (esi > 0)
server_cfg << " --extra-server-info=" << esi;
}
else
{
server_cfg << " --extra-server-info=" << esi;
}
}
SeparateProcess* sp =
new SeparateProcess(SeparateProcess::getCurrentExecutableLocation(),
server_cfg.str() + password);
STKHost::create(server, sp);
STKHost::create(sp);
NetworkingLobby::getInstance()->setJoinedServer(server);
#endif
} // createServer

View File

@ -71,6 +71,11 @@ public:
// ------------------------------------------------------------------------
GUIEngine::EventPropagation processEvent(const std::string& eventSource)
OVERRIDE;
// ------------------------------------------------------------------------
GUIEngine::TextBoxWidget* getTextField() const { return m_text_field; }
// ------------------------------------------------------------------------
GUIEngine::LabelWidget* getTitle() const { return m_title; }
};
#endif

View File

@ -19,6 +19,8 @@
#include <string>
#include "audio/music_manager.hpp"
#include "audio/sfx_manager.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/scalable_font.hpp"
#include "guiengine/widgets/icon_button_widget.hpp"
@ -32,9 +34,9 @@
#include "race/race_manager.hpp"
#include "states_screens/help_screen_1.hpp"
#include "states_screens/main_menu_screen.hpp"
#include "states_screens/race_gui_base.hpp"
#include "states_screens/race_setup_screen.hpp"
#include "states_screens/options_screen_video.hpp"
#include "states_screens/online_screen.hpp"
#include "states_screens/state_manager.hpp"
#include "utils/translation.hpp"
@ -57,16 +59,32 @@ RacePausedDialog::RacePausedDialog(const float percentWidth,
loadFromFile("race_paused_dialog.stkgui");
}
World::getWorld()->schedulePause(WorldStatus::IN_GAME_MENU_PHASE);
IconButtonWidget* back_btn = getWidget<IconButtonWidget>("backbtn");
back_btn->setFocusForPlayer( PLAYER_ID_GAME_MASTER );
if (NetworkConfig::get()->isNetworking())
{
music_manager->pauseMusic();
SFXManager::get()->pauseAll();
}
else
{
World::getWorld()->schedulePause(WorldStatus::IN_GAME_MENU_PHASE);
}
} // RacePausedDialog
// ----------------------------------------------------------------------------
RacePausedDialog::~RacePausedDialog()
{
World::getWorld()->scheduleUnpause();
if (NetworkConfig::get()->isNetworking())
{
music_manager->resumeMusic();
SFXManager::get()->resumeAll();
}
else
{
World::getWorld()->scheduleUnpause();
}
} // ~RacePausedDialog
// ----------------------------------------------------------------------------
@ -172,18 +190,23 @@ GUIEngine::EventPropagation
}
World::getWorld()->scheduleUnpause();
race_manager->exitRace();
Screen* newStack[] = {MainMenuScreen::getInstance(),
NetworkConfig::get()->isNetworking() ?
static_cast<Screen*>(OnlineScreen::getInstance()) :
static_cast<Screen*>(RaceSetupScreen::getInstance()),
NULL};
StateManager::get()->resetAndSetStack( newStack );
Screen* new_stack[] =
{
MainMenuScreen::getInstance(),
RaceSetupScreen::getInstance(),
NULL
};
StateManager::get()->resetAndSetStack(
NetworkConfig::get()->isNetworking() ?
NetworkConfig::get()->getResetScreens().data() :
new_stack);
NetworkConfig::get()->unsetNetworking();
return GUIEngine::EVENT_BLOCK;
}
else if (selection == "endrace")
{
ModalDialog::dismiss();
World::getWorld()->getRaceGUI()->removeReferee();
World::getWorld()->endRaceEarly();
return GUIEngine::EVENT_BLOCK;
}

View File

@ -60,7 +60,7 @@ ServerInfoDialog::ServerInfoDialog(std::shared_ptr<Server> server)
GUIEngine::LabelWidget *lbldifficulty = getWidget<LabelWidget>("server_difficulty");
lbldifficulty->setText(difficulty, false);
core::stringw mode = RaceManager::getNameOf(server->getRaceMinorMode());
core::stringw mode = NetworkConfig::get()->getModeName(server->getServerMode());
GUIEngine::LabelWidget *gamemode = getWidget<LabelWidget>("server_game_mode");
gamemode->setText(mode, false);
@ -104,7 +104,7 @@ void ServerInfoDialog::requestJoin()
{
NetworkConfig::get()->setPassword("");
}
STKHost::create(m_server);
STKHost::create();
NetworkingLobby::getInstance()->setJoinedServer(m_server);
ModalDialog::dismiss();
NetworkingLobby::getInstance()->push();

View File

@ -425,7 +425,9 @@ void KartSelectionScreen::tearDown()
Screen::tearDown();
m_kart_widgets.clearAndDeleteAll();
GUIEngine::removeScreen(getName().c_str());
if (m_must_delete_on_back)
GUIEngine::removeScreen(this);
} // tearDown
// ----------------------------------------------------------------------------

View File

@ -54,13 +54,6 @@ public:
// ------------------------------------------------------------------------
virtual bool playerQuit(StateManager::ActivePlayer* player) OVERRIDE
{ return true; }
// ------------------------------------------------------------------------
/** \brief implement callback from parent class GUIEngine::Screen */
virtual void tearDown() OVERRIDE
{
m_must_delete_on_back = true;
KartSelectionScreen::tearDown();
}
};

View File

@ -152,44 +152,6 @@ void NetworkingLobby::init()
} // 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(core::stringw info)
{
@ -253,7 +215,8 @@ void NetworkingLobby::onUpdate(float delta)
}
else
{
if (m_server_peer.expired() && STKHost::existHost())
if (m_server_peer.expired() && NetworkConfig::get()->isClient()
&& STKHost::existHost())
m_server_peer = STKHost::get()->getServerPeerForClient();
core::stringw total_msg;
for (auto& string : m_server_info)

View File

@ -115,7 +115,11 @@ public:
void finishAddingPlayers();
void addMoreServerInfo(core::stringw info);
void setJoinedServer(std::shared_ptr<Server> server);
void setJoinedServer(std::shared_ptr<Server> server)
{
m_joined_server = server;
m_server_info.clear();
}
void updatePlayers(const std::vector<std::tuple<uint32_t/*host id*/,
uint32_t/*online id*/, core::stringw/*player name*/,
int/*icon id*/> >& p);

View File

@ -50,14 +50,9 @@ OnlineProfileServers::OnlineProfileServers() : GUIEngine::Screen("online/profile
// -----------------------------------------------------------------------------
void OnlineProfileServers::beforeAddingWidget()
{
if (!PlayerManager::getCurrentOnlineId())
{
getWidget<IconButtonWidget>("find_wan_server")->setActive(false);
getWidget<IconButtonWidget>("create_wan_server")->setActive(false);
getWidget<IconButtonWidget>("quick_wan_play")->setActive(false);
}
#ifdef ANDROID
getWidget("create_wan_server")->setVisible(false);
if (getWidget("create_wan_server"))
getWidget("create_wan_server")->setVisible(false);
#endif
} // beforeAddingWidget
@ -65,10 +60,28 @@ void OnlineProfileServers::beforeAddingWidget()
void OnlineProfileServers::init()
{
RibbonWidget* ribbon = getWidget<RibbonWidget>("wan");
assert(ribbon != NULL);
ribbon->select("find_wan_server", PLAYER_ID_GAME_MASTER);
ribbon->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
if (!PlayerManager::getCurrentOnlineId())
{
getWidget("back")->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
getWidget<IconButtonWidget>("find_wan_server")->setActive(false);
getWidget<IconButtonWidget>("create_wan_server")->setActive(false);
getWidget<IconButtonWidget>("quick_wan_play")->setActive(false);
}
else
{
getWidget<IconButtonWidget>("find_wan_server")->setActive(true);
getWidget<IconButtonWidget>("create_wan_server")->setActive(true);
getWidget<IconButtonWidget>("quick_wan_play")->setActive(true);
RibbonWidget* ribbon = getWidget<RibbonWidget>("wan");
assert(ribbon != NULL);
ribbon->select("find_wan_server", PLAYER_ID_GAME_MASTER);
ribbon->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
}
#ifdef ANDROID
if (getWidget("create_wan_server") &&
getWidget("create_wan_server")->isVisible())
getWidget("create_wan_server")->setVisible(false);
#endif
} // init
// -----------------------------------------------------------------------------

View File

@ -20,19 +20,28 @@
#include "config/player_manager.hpp"
#include "config/user_config.hpp"
#include "guiengine/message_queue.hpp"
#include "guiengine/widgets/check_box_widget.hpp"
#include "guiengine/widgets/label_widget.hpp"
#include "guiengine/widgets/list_widget.hpp"
#include "guiengine/widgets/ribbon_widget.hpp"
#include "guiengine/widgets/text_box_widget.hpp"
#include "input/device_manager.hpp"
#include "network/protocols/connect_to_server.hpp"
#include "network/protocols/client_lobby.hpp"
#include "network/network_config.hpp"
#include "network/server.hpp"
#include "network/stk_host.hpp"
#include "network/stk_peer.hpp"
#include "online/request_manager.hpp"
#include "states_screens/networking_lobby.hpp"
#include "states_screens/online_lan.hpp"
#include "states_screens/online_profile_achievements.hpp"
#include "states_screens/online_profile_servers.hpp"
#include "states_screens/online_screen.hpp"
#include "states_screens/state_manager.hpp"
#include "states_screens/user_screen.hpp"
#include "states_screens/dialogs/general_text_field_dialog.hpp"
#include "states_screens/dialogs/message_dialog.hpp"
#include "utils/string_utils.hpp"
@ -134,6 +143,13 @@ void OnlineScreen::onUpdate(float delta)
m_online->setLabel(PlayerManager::getCurrentOnlineId() ? m_online_string
: m_login_string);
// In case for entering server address finished
if (auto lb = LobbyProtocol::get<LobbyProtocol>())
{
NetworkingLobby::getInstance()->setJoinedServer(nullptr);
StateManager::get()->resetAndSetStack(
NetworkConfig::get()->getResetScreens(true/*lobby*/).data());
}
} // onUpdate
// ----------------------------------------------------------------------------
@ -143,6 +159,7 @@ void OnlineScreen::eventCallback(Widget* widget, const std::string& name,
{
if (name == "user-id")
{
NetworkConfig::get()->cleanNetworkPlayers();
UserScreen::getInstance()->push();
return;
}
@ -197,7 +214,7 @@ void OnlineScreen::eventCallback(Widget* widget, const std::string& name,
"\"Connect to the Internet\"."));
return;
}
if (PlayerManager::getCurrentOnlineId())
{
ProfileManager::get()->setVisiting(PlayerManager::getCurrentOnlineId());
@ -208,6 +225,65 @@ void OnlineScreen::eventCallback(Widget* widget, const std::string& name,
UserScreen::getInstance()->push();
}
}
else if (selection == "enter-address")
{
if (NetworkConfig::get()->isAddingNetworkPlayers())
{
core::stringw msg =
_("No player available for connecting to server.");
MessageQueue::add(MessageQueue::MT_ERROR, msg);
return;
}
core::stringw instruction =
_("Enter the server address with IP (optional) followed by : and"
" then port.");
auto gtfd = new GeneralTextFieldDialog(instruction.c_str(),
[] (const irr::core::stringw& text) {},
[this] (GUIEngine::LabelWidget* lw,
GUIEngine::TextBoxWidget* tb)->bool
{
TransportAddress server_addr(
StringUtils::wideToUtf8(tb->getText()));
if (server_addr.getIP() == 0)
{
core::stringw err = _("Invalid server address: %s.",
tb->getText());
lw->setText(err, true);
return false;
}
NetworkConfig::get()->setIsWAN();
NetworkConfig::get()->setIsServer(false);
NetworkConfig::get()->setPassword("");
auto server = std::make_shared<Server>(0, L"", 0, 0, 0, 0,
server_addr, false);
STKHost::create();
auto cts = std::make_shared<ConnectToServer>(server);
cts->setup();
Log::info("OnlineScreen", "Trying to connect to server '%s'.",
server_addr.toString().c_str());
if (!cts->handleDirectConnect(10000))
{
core::stringw err = _("Cannot connect to server %s.",
server_addr.toString().c_str());
STKHost::get()->shutdown();
NetworkConfig::get()->unsetNetworking();
lw->setText(err, true);
return false;
}
m_entered_server_address.copy(
STKHost::get()->getServerPeerForClient()->getAddress());
auto cl = LobbyProtocol::create<ClientLobby>();
cl->setAddress(m_entered_server_address);
cl->requestStart();
return true;
});
if (!m_entered_server_address.isUnset())
{
gtfd->getTextField()->setText(StringUtils::utf8ToWide(
m_entered_server_address.toString()));
}
}
} // eventCallback
// ----------------------------------------------------------------------------
@ -220,5 +296,3 @@ bool OnlineScreen::onEscapePressed()
NetworkConfig::get()->unsetNetworking();
return true;
} // onEscapePressed

View File

@ -19,6 +19,8 @@
#define HEADER_ONLINE_SCREEN_HPP
#include "guiengine/screen.hpp"
#include "network/transport_address.hpp"
namespace GUIEngine { class CheckBoxWidget; class ListWidget;
class ButtonWidget; class IconButtonWidget; }
@ -44,6 +46,8 @@ private:
GUIEngine::CheckBoxWidget* m_enable_splitscreen;
TransportAddress m_entered_server_address;
OnlineScreen();
public:

View File

@ -1067,3 +1067,12 @@ void RaceGUIBase::drawPlungerInFace(const Camera *camera, float dt)
true /* alpha */ );
#endif // !SERVER_ONLY
} // drawPlungerInFace
// ----------------------------------------------------------------------------
void RaceGUIBase::removeReferee()
{
if (m_referee->isAttached()) // race phase:
{
m_referee->removeFromSceneGraph();
}
} // removeReferee

View File

@ -248,6 +248,7 @@ public:
const core::vector2df &scaling) {};
void cleanupMessages(const float dt);
void removeReferee();
}; // RaceGUIBase

View File

@ -51,9 +51,7 @@
#include "scriptengine/property_animator.hpp"
#include "states_screens/feature_unlocked.hpp"
#include "states_screens/main_menu_screen.hpp"
#include "states_screens/networking_lobby.hpp"
#include "states_screens/network_kart_selection.hpp"
#include "states_screens/online_screen.hpp"
#include "states_screens/race_setup_screen.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
@ -168,21 +166,14 @@ void RaceResultGUI::enableAllButtons()
// If we're in a network world, change the buttons text
if (World::getWorld()->isNetworkWorld())
{
Log::info("This work was networked", "This is a network world.");
top->setVisible(false);
middle->setText(_("Continue"));
middle->setVisible(true);
middle->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
bottom->setText(_("Quit the server"));
bottom->setVisible(true);
if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX)
{
middle->setVisible(false); // you have to wait the server to start again
bottom->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
}
return;
}
Log::info("This work was NOT networked", "This is NOT a network world.");
// If something was unlocked
// -------------------------
@ -342,16 +333,15 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
// If we're playing online :
if (World::getWorld()->isNetworkWorld())
{
StateManager::get()->popMenu();
if (name == "middle") // Continue button (return to server lobby)
{
// Signal to the server that this client is back in the lobby now.
auto clrp = LobbyProtocol::get<ClientLobby>();
if(clrp)
clrp->doneWithResults();
backToLobby();
auto cl = LobbyProtocol::get<ClientLobby>();
if (cl)
cl->doneWithResults();
getWidget("middle")->setText(_("Waiting for others"));
}
if (name == "bottom") // Quit server (return to main menu)
if (name == "bottom") // Quit server (return to online lan / wan menu)
{
if (STKHost::existHost())
{
@ -359,7 +349,8 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
}
race_manager->exitRace();
race_manager->setAIKartOverride("");
StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
StateManager::get()->resetAndSetStack(
NetworkConfig::get()->getResetScreens().data());
NetworkConfig::get()->unsetNetworking();
}
return;
@ -430,18 +421,16 @@ void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
} // eventCallback
//-----------------------------------------------------------------------------
/** Sets up the giu to go back to the lobby. Can only be called in case of a
/** Sets up the gui to go back to the lobby. Can only be called in case of a
* networked game.
*/
void RaceResultGUI::backToLobby()
{
race_manager->exitRace();
race_manager->setAIKartOverride("");
Screen* newStack[] = { MainMenuScreen::getInstance(),
OnlineScreen::getInstance(),
NetworkingLobby::getInstance(),
NULL };
StateManager::get()->resetAndSetStack(newStack);
GUIEngine::ModalDialog::dismiss();
StateManager::get()->resetAndSetStack(
NetworkConfig::get()->getResetScreens(true/*lobby*/).data());
} // backToLobby
//-----------------------------------------------------------------------------

View File

@ -149,7 +149,7 @@ void ServerSelection::loadList(unsigned sort_case)
return c->getDifficulty() > d->getDifficulty();
break;
case 3:
return c->getRaceMinorMode() > d->getRaceMinorMode();
return c->getServerMode() > d->getServerMode();
break;
case 4:
return c->getServerOwnerName() > d->getServerOwnerName();
@ -175,7 +175,8 @@ void ServerSelection::loadList(unsigned sort_case)
race_manager->getDifficultyName(server->getDifficulty());
row.push_back(GUIEngine::ListWidget::ListCell(difficulty, -1, 1, true));
core::stringw mode = RaceManager::getNameOf(server->getRaceMinorMode());
core::stringw mode =
NetworkConfig::get()->getModeName(server->getServerMode());
row.push_back(GUIEngine::ListWidget::ListCell(mode, -1, 2, true));
if (NetworkConfig::get()->isWAN())

View File

@ -52,7 +52,12 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name,
const int playerID)
{
// -- track selection screen
if (name == "tracks")
if ((name == "lap-spinner" || name == "reverse") &&
STKHost::existHost() && m_selected_track != NULL)
{
voteForPlayer();
}
else if (name == "tracks")
{
DynamicRibbonWidget* w2 = dynamic_cast<DynamicRibbonWidget*>(widget);
if(!w2) return;
@ -84,27 +89,17 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name,
m_random_track_list.push_back(selection);
} // selection=="random_track"
Track *track = track_manager->getTrack(selection);
m_selected_track = track_manager->getTrack(selection);
if (track)
if (m_selected_track)
{
if (STKHost::existHost())
{
assert(m_laps);
assert(m_reversed);
// Remember reverse globally for each stk instance
m_reverse_checked = m_reversed->getState();
UserConfigParams::m_num_laps = m_laps->getValue();
NetworkString vote(PROTOCOL_LOBBY_ROOM);
vote.addUInt8(LobbyProtocol::LE_VOTE);
vote.encodeString(track->getIdent())
.addUInt8(m_laps->getValue())
.addUInt8(m_reversed->getState());
STKHost::get()->sendToServer(&vote, true);
voteForPlayer();
}
else
{
TrackInfoScreen::getInstance()->setTrack(track);
TrackInfoScreen::getInstance()->setTrack(m_selected_track);
TrackInfoScreen::getInstance()->push();
}
} // if clicked_track
@ -139,6 +134,7 @@ void TracksScreen::tearDown()
{
m_network_tracks = false;
m_vote_timeout = -1.0f;
m_selected_track = NULL;
} // tearDown
// -----------------------------------------------------------------------------
@ -354,6 +350,31 @@ void TracksScreen::setFocusOnTrack(const std::string& trackName)
tracks_widget->setSelection(trackName, PLAYER_ID_GAME_MASTER, true);
} // setFocusOnTrack
// -----------------------------------------------------------------------------
void TracksScreen::setVoteTimeout(float timeout)
{
if (m_vote_timeout != -1.0f)
return;
m_vote_timeout = (float)StkTime::getRealTime() + timeout;
} // setVoteTimeout
// -----------------------------------------------------------------------------
void TracksScreen::voteForPlayer()
{
assert(STKHost::existHost());
assert(m_selected_track);
assert(m_laps);
assert(m_reversed);
// Remember reverse globally for each stk instance
m_reverse_checked = m_reversed->getState();
UserConfigParams::m_num_laps = m_laps->getValue();
NetworkString vote(PROTOCOL_LOBBY_ROOM);
vote.addUInt8(LobbyProtocol::LE_VOTE);
vote.encodeString(m_selected_track->getIdent())
.addUInt8(m_laps->getValue()).addUInt8(m_reversed->getState());
STKHost::get()->sendToServer(&vote, true);
} // voteForPlayer
// -----------------------------------------------------------------------------
void TracksScreen::onUpdate(float dt)
{
@ -365,7 +386,7 @@ void TracksScreen::onUpdate(float dt)
}
m_votes->setVisible(true);
int remaining_time = int(m_vote_timeout - float(StkTime::getRealTime()));
int remaining_time = (int)(m_vote_timeout - StkTime::getRealTime());
if (remaining_time < 0)
remaining_time = 0;
//I18N: In tracks screen, about voting of tracks in network

View File

@ -24,6 +24,8 @@
#include <map>
#include <string>
class Track;
namespace GUIEngine
{
class CheckBoxWidget;
@ -47,6 +49,7 @@ private:
m_reverse_checked = false;
}
Track* m_selected_track = NULL;
GUIEngine::CheckBoxWidget* m_reversed;
GUIEngine::SpinnerWidget* m_laps;
GUIEngine::LabelWidget* m_votes;
@ -59,10 +62,12 @@ private:
Synchronised<std::map<std::string, core::stringw> > m_vote_messages;
std::deque<std::string> m_random_track_list;
/** adds the tracks from the current track group into the tracks ribbon */
void buildTrackList();
std::deque<std::string> m_random_track_list;
void voteForPlayer();
public:
@ -101,12 +106,7 @@ public:
m_vote_timeout = -1.0f;
}
void setVoteTimeout(float timeout)
{
if (m_vote_timeout != -1.0f)
return;
m_vote_timeout = timeout;
}
void setVoteTimeout(float timeout);
void addVoteMessage(const std::string& user,
const irr::core::stringw& message)

View File

@ -82,35 +82,53 @@ public:
static void reportInvalidParameters();
static bool has(const std::string &option);
// ------------------------------------------------------------------------
/** Searches for an option 'option=XX'. If found, *t will contain 'XX'.
* If the value was found, the entry is removed from the list of all
* command line arguments. This is the interface for any integer
* values (i.e. using %d as format while scanning).
/** Searches for an option 'option=XX'. If found, *value will contain 'XX'.
* If the value was found and the type of XX and value matches each other,
* the entry is removed from the list of all command line arguments.
* \param option The option (must include '-' or '--' as required).
* \param t Address of a variable to store the value.
* \param format The '%' format to sscanf the value in t with.
* \param value Pointer to store the value.
* \return true if the value was found, false otherwise.
*/
static bool has(const std::string &option, int *t)
template<typename T> static bool has(const std::string& option, T* value)
{
return has(option, t, "%d");
std::string equal = option + "=";
std::vector<std::string>::iterator i;
for (i = m_argv.begin(); i < m_argv.end(); i++)
{
if (i->compare(0, equal.size(), equal) == 0)
{
std::string result =
i->substr(equal.size(), std::string::npos);
if (StringUtils::fromString(result, *value))
{
m_argv.erase(i);
return true;
}
}
}
return false;
}
// ------------------------------------------------------------------------
/** Searches for an option 'option=XX'. If found, *t will contain 'XX'.
* If the value was found, the entry is removed from the list of all
* command line arguments. This is the interface for a std::string
/** Searches for an option 'option=XX'. If found, *value will contain 'XX'.
* If the value was found and the type of XX and value matches each other,
* the entry is removed from the list of all command line arguments.
* It copies the result directly to value to include space.
* \param option The option (must include '-' or '--' as required).
* \param t Address of a variable to store the value.
* \param format The '%' format to sscanf the value in t with.
* \param value String pointer to store the value.
* \return true if the value was found, false otherwise.
*/
static bool has(const std::string &option, std::string *t)
static bool has(const std::string& option, std::string* value)
{
char s[1024];
if(has(option, s, "%1023s"))
std::string equal = option + "=";
std::vector<std::string>::iterator i;
for (i = m_argv.begin(); i < m_argv.end(); i++)
{
*t = s;
return true;
if (i->compare(0, equal.size(), equal) == 0)
{
*value = i->substr(equal.size(), std::string::npos);
m_argv.erase(i);
return true;
}
}
return false;
} // has<std::string>