@@ -9,7 +9,7 @@
|
||||
<div layout="horizontal-row" width="100%" height="fit">
|
||||
<checkbox id="pixelshaders"/>
|
||||
<spacer width="10" height="10"/>
|
||||
<label text="Pixel Shaders" I18N="Video settings"/>
|
||||
<label text="Pixel shaders" I18N="Video settings"/>
|
||||
</div>
|
||||
|
||||
<spacer height="4" width="10" />
|
||||
@@ -61,7 +61,7 @@
|
||||
<div layout="horizontal-row" proportion="1" height="fit">
|
||||
<checkbox id="ssao"/>
|
||||
<spacer width="10" height="10"/>
|
||||
<label text="Ambient Occlusion" I18N="Video settings"/>
|
||||
<label text="Ambient occlusion" I18N="Video settings"/>
|
||||
</div>
|
||||
|
||||
<spacer height="4" width="10" />
|
||||
@@ -81,7 +81,7 @@
|
||||
<div layout="horizontal-row" proportion="1" height="fit">
|
||||
<checkbox id="glow"/>
|
||||
<spacer width="10" height="10"/>
|
||||
<label text="Glow (outlines)" I18N="Video settings"/>
|
||||
<label text="Glow (Outlines)" I18N="Video settings"/>
|
||||
</div>
|
||||
|
||||
<spacer height="4" width="10" />
|
||||
@@ -119,7 +119,7 @@
|
||||
<div layout="horizontal-row" proportion="1" height="fit">
|
||||
<checkbox id="animated_characters"/>
|
||||
<spacer width="10" height="10"/>
|
||||
<label text="Animated Characters" I18N="Video settings"/>
|
||||
<label text="Animated characters" I18N="Video settings"/>
|
||||
</div>
|
||||
|
||||
<spacer height="4" width="10" />
|
||||
@@ -134,7 +134,7 @@
|
||||
<spacer height="20" width="10" />
|
||||
|
||||
<div layout="horizontal-row" width="100%" proportion="1">
|
||||
<label text="Particles Effects" I18N="Video settings" width="40%"/>
|
||||
<label text="Particle effects" I18N="Video settings" width="40%"/>
|
||||
<spacer width="10" height="10"/>
|
||||
<gauge id="particles_effects" min_value="1" max_value="2" width="50%" />
|
||||
</div>
|
||||
|
||||
@@ -122,6 +122,13 @@
|
||||
<replay max-time="600" delta-t="0.05" delta-pos="0.1"
|
||||
delta-angle="0.5" />
|
||||
|
||||
<!-- Determines the minimap related values.
|
||||
size: The size of the minimap (scaled afterwards) 480 = full screen height)
|
||||
ai-icon: The size of the icons for the AI karts on the minimap.
|
||||
player-icon: The size of the icons for the player karts. -->
|
||||
|
||||
<minimap size="180.0" ai-icon="16.0" player-icon="20.0"/>
|
||||
|
||||
<!-- Skidmark data: maximum number of skid marks, and
|
||||
time for skidmarks to fade out. Maximum number will over
|
||||
current number of karts, so the more karts, the less
|
||||
|
||||
@@ -199,7 +199,24 @@ namespace irr
|
||||
IRR_KEY_BUTTON_SELECT = 0x111,
|
||||
IRR_KEY_BUTTON_MODE = 0x112,
|
||||
|
||||
IRR_KEY_CODES_COUNT = 0x113 // this is not a key, but the amount of keycodes there are.
|
||||
// For Azerty layout
|
||||
IRR_KEY_AMPERSAND = 0x113,
|
||||
IRR_KEY_EACUTE = 0x114,
|
||||
IRR_KEY_QUOTEDBL = 0x115,
|
||||
IRR_KEY_PARENLEFT = 0x116,
|
||||
IRR_KEY_EGRAVE = 0x117,
|
||||
IRR_KEY_CCEDILLA = 0x118,
|
||||
IRR_KEY_AGRAVE = 0x119,
|
||||
IRR_KEY_PARENRIGHT = 0x120,
|
||||
IRR_KEY_UGRAVE = 0x121,
|
||||
IRR_KEY_COLON = 0x122,
|
||||
IRR_KEY_DOLLAR = 0x123,
|
||||
IRR_KEY_EXCLAM = 0x124,
|
||||
IRR_KEY_TWOSUPERIOR = 0x125,
|
||||
IRR_KEY_MU = 0x126,
|
||||
IRR_KEY_SECTION = 0x127,
|
||||
|
||||
IRR_KEY_CODES_COUNT = 0x128 // this is not a key, but the amount of keycodes there are.
|
||||
};
|
||||
|
||||
} // end namespace irr
|
||||
|
||||
@@ -1493,7 +1493,7 @@ int CIrrDeviceLinux::getNumlockMask(Display* display)
|
||||
|
||||
EKEY_CODE CIrrDeviceLinux::getKeyCode(XEvent &event)
|
||||
{
|
||||
EKEY_CODE keyCode = (EKEY_CODE)0;
|
||||
int keyCode = 0;
|
||||
SKeyMap mp;
|
||||
|
||||
// First check for numpad keys
|
||||
@@ -1515,30 +1515,25 @@ EKEY_CODE CIrrDeviceLinux::getKeyCode(XEvent &event)
|
||||
const s32 idx = KeyMap.binary_search(mp);
|
||||
if (idx != -1)
|
||||
{
|
||||
keyCode = (EKEY_CODE)KeyMap[idx].Win32Key;
|
||||
keyCode = KeyMap[idx].Win32Key;
|
||||
}
|
||||
if (keyCode == 0)
|
||||
{
|
||||
// Any value is better than none, that allows at least using the keys.
|
||||
// Worst case is that some keys will be identical, still better than _all_
|
||||
// unknown keys being identical.
|
||||
if ( !mp.X11Key )
|
||||
if (mp.X11Key)
|
||||
{
|
||||
keyCode = (EKEY_CODE)event.xkey.keycode;
|
||||
os::Printer::log("No such X11Key, using event keycode", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION);
|
||||
}
|
||||
else if (idx == -1)
|
||||
{
|
||||
keyCode = (EKEY_CODE)mp.X11Key;
|
||||
os::Printer::log("EKEY_CODE not found, using orig. X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION);
|
||||
keyCode = (int)IRR_KEY_CODES_COUNT + mp.X11Key;
|
||||
}
|
||||
else
|
||||
{
|
||||
keyCode = (EKEY_CODE)mp.X11Key;
|
||||
os::Printer::log("EKEY_CODE is 0, using orig. X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION);
|
||||
keyCode = (int)IRR_KEY_CODES_COUNT + event.xkey.keycode;
|
||||
}
|
||||
|
||||
os::Printer::log("EKEY_CODE is 0, fallback keycode", core::stringc(keyCode).c_str(), ELL_INFORMATION);
|
||||
}
|
||||
return keyCode;
|
||||
return (EKEY_CODE)keyCode;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2441,16 +2436,16 @@ void CIrrDeviceLinux::createKeyMap()
|
||||
KeyMap.push_back(SKeyMap(XK_ISO_Level3_Shift, IRR_KEY_RMENU));
|
||||
KeyMap.push_back(SKeyMap(XK_Menu, IRR_KEY_MENU));
|
||||
KeyMap.push_back(SKeyMap(XK_space, IRR_KEY_SPACE));
|
||||
KeyMap.push_back(SKeyMap(XK_exclam, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_quotedbl, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_section, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_exclam, IRR_KEY_EXCLAM));
|
||||
KeyMap.push_back(SKeyMap(XK_quotedbl, IRR_KEY_QUOTEDBL));
|
||||
KeyMap.push_back(SKeyMap(XK_section, IRR_KEY_SECTION)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_numbersign, IRR_KEY_OEM_2));
|
||||
KeyMap.push_back(SKeyMap(XK_dollar, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_dollar, IRR_KEY_DOLLAR));
|
||||
KeyMap.push_back(SKeyMap(XK_percent, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_ampersand, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_ampersand, IRR_KEY_AMPERSAND));
|
||||
KeyMap.push_back(SKeyMap(XK_apostrophe, IRR_KEY_OEM_7));
|
||||
KeyMap.push_back(SKeyMap(XK_parenleft, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_parenright, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_parenleft, IRR_KEY_PARENLEFT));
|
||||
KeyMap.push_back(SKeyMap(XK_parenright, IRR_KEY_PARENRIGHT));
|
||||
KeyMap.push_back(SKeyMap(XK_asterisk, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_plus, IRR_KEY_PLUS)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_comma, IRR_KEY_COMMA)); //?
|
||||
@@ -2467,14 +2462,14 @@ void CIrrDeviceLinux::createKeyMap()
|
||||
KeyMap.push_back(SKeyMap(XK_7, IRR_KEY_7));
|
||||
KeyMap.push_back(SKeyMap(XK_8, IRR_KEY_8));
|
||||
KeyMap.push_back(SKeyMap(XK_9, IRR_KEY_9));
|
||||
KeyMap.push_back(SKeyMap(XK_colon, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_colon, IRR_KEY_COLON));
|
||||
KeyMap.push_back(SKeyMap(XK_semicolon, IRR_KEY_OEM_1));
|
||||
KeyMap.push_back(SKeyMap(XK_less, IRR_KEY_OEM_102));
|
||||
KeyMap.push_back(SKeyMap(XK_equal, IRR_KEY_PLUS));
|
||||
KeyMap.push_back(SKeyMap(XK_greater, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_question, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_at, IRR_KEY_2)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_mu, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_mu, IRR_KEY_MU)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_EuroSign, 0)); //?
|
||||
KeyMap.push_back(SKeyMap(XK_A, IRR_KEY_A));
|
||||
KeyMap.push_back(SKeyMap(XK_B, IRR_KEY_B));
|
||||
@@ -2542,6 +2537,12 @@ void CIrrDeviceLinux::createKeyMap()
|
||||
KeyMap.push_back(SKeyMap(XK_udiaeresis, IRR_KEY_OEM_1));
|
||||
KeyMap.push_back(SKeyMap(XK_Super_L, IRR_KEY_LWIN));
|
||||
KeyMap.push_back(SKeyMap(XK_Super_R, IRR_KEY_RWIN));
|
||||
KeyMap.push_back(SKeyMap(XK_agrave, IRR_KEY_AGRAVE));
|
||||
KeyMap.push_back(SKeyMap(XK_ccedilla, IRR_KEY_CCEDILLA ));
|
||||
KeyMap.push_back(SKeyMap(XK_eacute, IRR_KEY_EACUTE));
|
||||
KeyMap.push_back(SKeyMap(XK_egrave, IRR_KEY_EGRAVE));
|
||||
KeyMap.push_back(SKeyMap(XK_ugrave, IRR_KEY_UGRAVE));
|
||||
KeyMap.push_back(SKeyMap(XK_twosuperior, IRR_KEY_TWOSUPERIOR));
|
||||
|
||||
KeyMap.sort();
|
||||
#endif
|
||||
|
||||
@@ -154,6 +154,9 @@ void STKConfig::load(const std::string &filename)
|
||||
CHECK_NEG(m_replay_delta_angle, "replay delta-angle" );
|
||||
CHECK_NEG(m_replay_delta_pos2, "replay delta-position" );
|
||||
CHECK_NEG(m_replay_dt, "replay delta-t" );
|
||||
CHECK_NEG(m_minimap_size, "minimap size" );
|
||||
CHECK_NEG(m_minimap_ai_icon, "minimap ai_icon" );
|
||||
CHECK_NEG(m_minimap_player_icon, "minimap player_icon" );
|
||||
CHECK_NEG(m_smooth_angle_limit, "physics smooth-angle-limit" );
|
||||
CHECK_NEG(m_default_track_friction, "physics default-track-friction");
|
||||
CHECK_NEG(m_physics_fps, "physics fps" );
|
||||
@@ -196,6 +199,9 @@ void STKConfig::init_defaults()
|
||||
m_replay_delta_angle = -100;
|
||||
m_replay_delta_pos2 = -100;
|
||||
m_replay_dt = -100;
|
||||
m_minimap_size = -100;
|
||||
m_minimap_ai_icon = -100;
|
||||
m_minimap_player_icon = -100;
|
||||
m_network_state_frequeny = -100;
|
||||
m_title_music = NULL;
|
||||
m_smooth_normals = false;
|
||||
@@ -406,6 +412,13 @@ void STKConfig::getAllData(const XMLNode * root)
|
||||
|
||||
}
|
||||
|
||||
if(const XMLNode *replay_node = root->getNode("minimap"))
|
||||
{
|
||||
replay_node->get("size", &m_minimap_size );
|
||||
replay_node->get("ai-icon", &m_minimap_ai_icon );
|
||||
replay_node->get("player-icon", &m_minimap_player_icon );
|
||||
}
|
||||
|
||||
if (const XMLNode *fonts_list = root->getNode("fonts-list"))
|
||||
{
|
||||
fonts_list->get("normal-ttf", &m_normal_ttf);
|
||||
|
||||
@@ -163,6 +163,13 @@ public:
|
||||
* be generated. */
|
||||
float m_replay_delta_angle;
|
||||
|
||||
/** The minimap size */
|
||||
float m_minimap_size;
|
||||
|
||||
/* The size of icons for AIs and human players, respectively */
|
||||
float m_minimap_ai_icon;
|
||||
float m_minimap_player_icon;
|
||||
|
||||
/** The field of view for 1, 2, 3, 4 player split screen. */
|
||||
float m_camera_fov[MAX_PLAYER_COUNT];
|
||||
|
||||
|
||||
@@ -715,7 +715,7 @@ namespace UserConfigParams
|
||||
&m_network_group, "Enable chatting in networking lobby, if off than "
|
||||
"no chat message will be displayed from any players."));
|
||||
PARAM_PREFIX FloatUserConfigParam m_voting_timeout
|
||||
PARAM_DEFAULT(FloatUserConfigParam(10.0f, "voting-timeout",
|
||||
PARAM_DEFAULT(FloatUserConfigParam(20.0f, "voting-timeout",
|
||||
&m_network_group, "Timeout in seconds for voting tracks in server."));
|
||||
PARAM_PREFIX IntUserConfigParam m_server_max_players
|
||||
PARAM_DEFAULT(IntUserConfigParam(12, "server_max_players",
|
||||
|
||||
@@ -421,6 +421,8 @@ void SPMeshBuffer::enableTextureMatrix(unsigned mat_id)
|
||||
assert(mat_id < m_stk_material.size());
|
||||
// Make the 31 bit in normal to be 1
|
||||
uploadGLMesh();
|
||||
if (m_vbo == 0 || m_ibo == 0)
|
||||
return;
|
||||
auto& ret = m_stk_material[mat_id];
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||
std::set<uint16_t> used_vertices;
|
||||
|
||||
@@ -444,6 +444,8 @@ bool SPTexture::threadedLoad()
|
||||
std::shared_ptr<video::IImage> image = getTextureImage();
|
||||
if (!image)
|
||||
{
|
||||
m_width.store(2);
|
||||
m_height.store(2);
|
||||
return true;
|
||||
}
|
||||
std::shared_ptr<video::IImage> mask = getMask(image->getDimension());
|
||||
@@ -642,12 +644,6 @@ void SPTexture::applyMask(video::IImage* texture, video::IImage* mask)
|
||||
}
|
||||
} // applyMask
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool SPTexture::initialized() const
|
||||
{
|
||||
return m_width.load() != 0 && m_height.load() != 0;
|
||||
} // initialized
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void SPTexture::generateQuickMipmap(std::shared_ptr<video::IImage> first_image,
|
||||
const std::vector<std::pair
|
||||
|
||||
@@ -183,7 +183,8 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
GLuint getOpenGLTextureName() const { return m_texture_name; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool initialized() const;
|
||||
bool initialized() const
|
||||
{ return m_width.load() != 0 && m_height.load() != 0; }
|
||||
// ------------------------------------------------------------------------
|
||||
unsigned getWidth() const { return m_width.load(); }
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1099,14 +1099,14 @@ bool DynamicRibbonWidget::setSelection(int item_id, const int playerID,
|
||||
int row;
|
||||
int id;
|
||||
|
||||
int iterations = 0; // a safeguard to avoid infinite loops (should not happen normally)
|
||||
unsigned int iterations = 0; // a safeguard to avoid infinite loops (should not happen normally)
|
||||
|
||||
while (!findItemInRows(name.c_str(), &row, &id))
|
||||
{
|
||||
// if we get here it means the item is scrolled out. Try to find it.
|
||||
scroll(1, evenIfDeactivated);
|
||||
|
||||
if (iterations > 50)
|
||||
if (iterations > m_items.size())
|
||||
{
|
||||
Log::error("DynamicRibbonWidget::setSelection", "Cannot find item %d (%s)", item_id, name.c_str());
|
||||
return false;
|
||||
|
||||
@@ -327,6 +327,23 @@ irr::core::stringw Binding::getAsString() const
|
||||
case irr::IRR_KEY_PA1 : s = _C("input_key", "Pa1"); break;
|
||||
//I18N: input configuration screen: keyboard key
|
||||
case irr::IRR_KEY_OEM_CLEAR : s = _C("input_key", "Oem Clear"); break;
|
||||
|
||||
// for azerty layout
|
||||
case irr::IRR_KEY_AMPERSAND : s = "&"; break;
|
||||
case irr::IRR_KEY_EACUTE : s = "é"; break;
|
||||
case irr::IRR_KEY_QUOTEDBL : s = "\""; break;
|
||||
case irr::IRR_KEY_PARENLEFT : s = "("; break;
|
||||
case irr::IRR_KEY_EGRAVE : s = "è"; break;
|
||||
case irr::IRR_KEY_CCEDILLA : s = "ç"; break;
|
||||
case irr::IRR_KEY_AGRAVE : s = "à"; break;
|
||||
case irr::IRR_KEY_PARENRIGHT : s = ")"; break;
|
||||
case irr::IRR_KEY_UGRAVE : s = "ù"; break;
|
||||
case irr::IRR_KEY_COLON : s = ":"; break;
|
||||
case irr::IRR_KEY_DOLLAR : s = "$"; break;
|
||||
case irr::IRR_KEY_EXCLAM : s = "!"; break;
|
||||
case irr::IRR_KEY_TWOSUPERIOR : s = "²"; break;
|
||||
case irr::IRR_KEY_MU : s = "µ"; break;
|
||||
case irr::IRR_KEY_SECTION : s = "§"; break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -62,7 +62,7 @@ WorldStatus::WorldStatus()
|
||||
void WorldStatus::reset()
|
||||
{
|
||||
m_time = 0.0f;
|
||||
m_adjust_time_by = 0.0f;
|
||||
m_adjust_time_by.store(0);
|
||||
m_time_ticks = 0;
|
||||
m_auxiliary_ticks = 0;
|
||||
m_count_up_ticks = 0;
|
||||
@@ -480,30 +480,55 @@ void WorldStatus::updateTime(int ticks)
|
||||
*/
|
||||
float WorldStatus::adjustDT(float dt)
|
||||
{
|
||||
int adjust_time = m_adjust_time_by.load();
|
||||
if (adjust_time == 0)
|
||||
return dt;
|
||||
|
||||
// If request, adjust world time to go ahead (adjust>0) or
|
||||
// slow down (<0). This is done in 5% of dt steps so that the
|
||||
// user will not notice this.
|
||||
const float FRACTION = 0.10f; // fraction of dt to be adjusted
|
||||
float adjust_time_by = adjust_time / 1000.0f;
|
||||
float time_adjust;
|
||||
if (m_adjust_time_by >= 0) // make it run faster
|
||||
if (adjust_time_by > 0.0f) // make it run faster
|
||||
{
|
||||
time_adjust = dt * FRACTION;
|
||||
if (time_adjust > m_adjust_time_by) time_adjust = m_adjust_time_by;
|
||||
if (m_adjust_time_by > 0)
|
||||
Log::verbose("info", "At %f %f adjusting time by %f dt %f to dt %f for %f",
|
||||
World::getWorld()->getTime(), StkTime::getRealTime(),
|
||||
time_adjust, dt, dt - time_adjust, m_adjust_time_by);
|
||||
|
||||
if (time_adjust > adjust_time_by)
|
||||
{
|
||||
m_adjust_time_by.fetch_sub(int(adjust_time_by * 1000.f));
|
||||
time_adjust = adjust_time_by;
|
||||
}
|
||||
else
|
||||
m_adjust_time_by.fetch_sub(int(time_adjust * 1000.f));
|
||||
|
||||
Log::verbose("WorldStatus",
|
||||
"At %f %f adjusting time (speed up) by %f dt %f to dt %f for %f",
|
||||
World::getWorld()->getTime(), StkTime::getRealTime(),
|
||||
time_adjust, dt, dt + time_adjust, adjust_time_by);
|
||||
}
|
||||
else // m_adjust_time negative, i.e. will go slower
|
||||
else // adjust_time_by negative, i.e. will go slower
|
||||
{
|
||||
time_adjust = -dt * FRACTION;
|
||||
if (time_adjust < m_adjust_time_by) time_adjust = m_adjust_time_by;
|
||||
Log::verbose("info", "At %f %f adjusting time by %f dt %f to dt %f for %f",
|
||||
|
||||
if (time_adjust < adjust_time_by)
|
||||
{
|
||||
m_adjust_time_by.fetch_sub(int(adjust_time_by * 1000.f));
|
||||
time_adjust = adjust_time_by;
|
||||
}
|
||||
else
|
||||
m_adjust_time_by.fetch_sub(int(time_adjust * 1000.f));
|
||||
|
||||
Log::verbose("WorldStatus",
|
||||
"At %f %f adjusting time (slow down) by %f dt %f to dt %f for %f",
|
||||
World::getWorld()->getTime(), StkTime::getRealTime(),
|
||||
time_adjust, dt, dt - time_adjust, m_adjust_time_by);
|
||||
time_adjust, dt, dt + time_adjust, adjust_time_by);
|
||||
}
|
||||
m_adjust_time_by -= time_adjust;
|
||||
dt -= time_adjust;
|
||||
dt += time_adjust;
|
||||
// No negative or tends to zero dt
|
||||
const float min_dt = stk_config->ticks2Time(1);
|
||||
if (dt < min_dt)
|
||||
dt = min_dt;
|
||||
return dt;
|
||||
} // adjustDT
|
||||
|
||||
|
||||
@@ -110,10 +110,11 @@ private:
|
||||
/** In networked game the world clock might be adjusted (without the
|
||||
* player noticing), e.g. if a client causes rewinds in the server,
|
||||
* that client needs to speed up to be further ahead of the server
|
||||
* and so reduce the number of rollbacks. This is the amount of time
|
||||
* or slow down if time in client goes too far from server time
|
||||
* to reduce the number of rollbacks. This is the amount of time
|
||||
* by which the client's clock needs to be adjusted (positive or
|
||||
* negative). */
|
||||
float m_adjust_time_by;
|
||||
std::atomic<int> m_adjust_time_by;
|
||||
|
||||
/** The clock mode: normal counting forwards, or countdown */
|
||||
ClockType m_clock_mode;
|
||||
@@ -221,7 +222,7 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets a time by which the clock should be adjusted. Used by networking
|
||||
* if too many rewinds are detected. */
|
||||
void setAdjustTime(float t) { m_adjust_time_by = t; }
|
||||
void setAdjustTime(int t) { m_adjust_time_by.fetch_add(t); }
|
||||
}; // WorldStatus
|
||||
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "utils/log.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Update and see if any player disconnects.
|
||||
@@ -139,14 +140,23 @@ void GameSetup::addServerInfo(NetworkString* ns)
|
||||
//-----------------------------------------------------------------------------
|
||||
void GameSetup::sortPlayersForGrandPrix()
|
||||
{
|
||||
if (!isGrandPrix() || m_tracks.size() == 1)
|
||||
if (!isGrandPrix())
|
||||
return;
|
||||
std::lock_guard<std::mutex> lock(m_players_mutex);
|
||||
|
||||
if (m_tracks.size() == 1)
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 g(rd());
|
||||
std::shuffle(m_players.begin(), m_players.end(), g);
|
||||
return;
|
||||
}
|
||||
|
||||
std::sort(m_players.begin(), m_players.end(),
|
||||
[](const std::weak_ptr<NetworkPlayerProfile>& a,
|
||||
const std::weak_ptr<NetworkPlayerProfile>& b)
|
||||
{
|
||||
// They should never expired
|
||||
// They should be never expired
|
||||
auto c = a.lock();
|
||||
assert(c);
|
||||
auto d = b.lock();
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
|
||||
#include "network/protocols/game_protocol.hpp"
|
||||
|
||||
#include "modes/world.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/controller/player_controller.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/event.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/game_setup.hpp"
|
||||
@@ -160,20 +160,19 @@ void GameProtocol::handleControllerAction(Event *event)
|
||||
uint8_t count = data.getUInt8();
|
||||
bool will_trigger_rewind = false;
|
||||
int rewind_delta = 0;
|
||||
int cur_ticks = 0;
|
||||
const int not_rewound = RewindManager::get()->getNotRewoundWorldTicks();
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
int ticks = data.getUInt32();
|
||||
|
||||
cur_ticks = data.getUInt32();
|
||||
// Since this is running in a thread, it might be called during
|
||||
// a rewind, i.e. with an incorrect world time. So the event
|
||||
// time needs to be compared with the World time independent
|
||||
// of any rewinding.
|
||||
if (ticks < RewindManager::get()->getNotRewoundWorldTicks() &&
|
||||
!will_trigger_rewind )
|
||||
if (cur_ticks < not_rewound && !will_trigger_rewind)
|
||||
{
|
||||
will_trigger_rewind = true;
|
||||
rewind_delta = ticks
|
||||
- RewindManager::get()->getNotRewoundWorldTicks();
|
||||
rewind_delta = not_rewound - cur_ticks;
|
||||
}
|
||||
uint8_t kart_id = data.getUInt8();
|
||||
assert(kart_id < World::getWorld()->getNumKarts());
|
||||
@@ -183,11 +182,11 @@ void GameProtocol::handleControllerAction(Event *event)
|
||||
int value_l = data.getUInt32();
|
||||
int value_r = data.getUInt32();
|
||||
Log::info("GameProtocol", "Action at %d: %d %d %d %d %d",
|
||||
ticks, kart_id, action, value, value_l, value_r);
|
||||
cur_ticks, kart_id, action, value, value_l, value_r);
|
||||
BareNetworkString *s = new BareNetworkString(3);
|
||||
s->addUInt8(kart_id).addUInt8(action).addUInt32(value)
|
||||
.addUInt32(value_l).addUInt32(value_r);
|
||||
RewindManager::get()->addNetworkEvent(this, s, ticks);
|
||||
RewindManager::get()->addNetworkEvent(this, s, cur_ticks);
|
||||
}
|
||||
|
||||
if (data.size() > 0)
|
||||
@@ -200,16 +199,37 @@ void GameProtocol::handleControllerAction(Event *event)
|
||||
// Send update to all clients except the original sender.
|
||||
STKHost::get()->sendPacketExcept(event->getPeer(),
|
||||
&data, false);
|
||||
|
||||
if (not_rewound == 0 ||
|
||||
m_initial_ticks.find(event->getPeer()) == m_initial_ticks.end())
|
||||
return;
|
||||
int cur_diff = cur_ticks - not_rewound;
|
||||
const int max_adjustment = 12;
|
||||
const int ticks_difference = m_initial_ticks.at(event->getPeer());
|
||||
if (will_trigger_rewind)
|
||||
{
|
||||
Log::info("GameProtocol",
|
||||
"At %d %f %d requesting time adjust of %d for host %d",
|
||||
if (rewind_delta > max_adjustment)
|
||||
rewind_delta = max_adjustment;
|
||||
Log::info("GameProtocol", "At %d %f %d requesting time adjust"
|
||||
" (speed up) of %d for host %d",
|
||||
World::getWorld()->getTimeTicks(), StkTime::getRealTime(),
|
||||
RewindManager::get()->getNotRewoundWorldTicks(),
|
||||
rewind_delta, event->getPeer()->getHostId());
|
||||
not_rewound, rewind_delta, event->getPeer()->getHostId());
|
||||
// This message from a client triggered a rewind in the server.
|
||||
// To avoid this, signal to the client that it should slow down.
|
||||
// To avoid this, signal to the client that it should speed up.
|
||||
adjustTimeForClient(event->getPeer(), rewind_delta);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cur_diff > 0 &&
|
||||
cur_diff - ticks_difference > max_adjustment)
|
||||
{
|
||||
// 80% slow down
|
||||
const int adjustment = -max_adjustment * 8 / 10;
|
||||
Log::info("GameProtocol", "At %d %f %d requesting time adjust"
|
||||
" (slow down) of %d for host %d",
|
||||
World::getWorld()->getTimeTicks(), StkTime::getRealTime(),
|
||||
not_rewound, adjustment, event->getPeer()->getHostId());
|
||||
adjustTimeForClient(event->getPeer(), adjustment);
|
||||
}
|
||||
} // if server
|
||||
|
||||
@@ -220,7 +240,7 @@ void GameProtocol::handleControllerAction(Event *event)
|
||||
* reduce rewinds). This function sends a a (unreliable) message to the
|
||||
* client.
|
||||
* \param peer The peer that triggered the rewind.
|
||||
* \param t Time that the peer needs to slowdown (<0) or sped up(>0).
|
||||
* \param t Time that the peer needs to slowdown (<0) or speed up(>0).
|
||||
*/
|
||||
void GameProtocol::adjustTimeForClient(STKPeer *peer, int ticks)
|
||||
{
|
||||
@@ -240,8 +260,10 @@ void GameProtocol::adjustTimeForClient(STKPeer *peer, int ticks)
|
||||
void GameProtocol::handleAdjustTime(Event *event)
|
||||
{
|
||||
int ticks = event->data().getUInt32();
|
||||
World::getWorld()->setAdjustTime(stk_config->ticks2Time(ticks));
|
||||
World::getWorld()->setAdjustTime(
|
||||
int(stk_config->ticks2Time(ticks) * 1000.0f));
|
||||
} // handleAdjustTime
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called by the server before assembling a new message containing the full
|
||||
* state of the race to be sent to a client.
|
||||
@@ -338,3 +360,11 @@ void GameProtocol::rewind(BareNetworkString *buffer)
|
||||
if (pc)
|
||||
pc->actionFromNetwork(action, value, value_l, value_r);
|
||||
} // rewind
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GameProtocol::addInitialTicks(STKPeer* p, int ticks)
|
||||
{
|
||||
Log::verbose("GameProtocol", "Host %d with ticks difference %d",
|
||||
p->getHostId(), ticks);
|
||||
m_initial_ticks[p] = ticks;
|
||||
} // addInitialTicks
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "utils/cpp2011.hpp"
|
||||
#include "utils/singleton.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class BareNetworkString;
|
||||
@@ -69,6 +70,8 @@ private:
|
||||
void handleState(Event *event);
|
||||
void handleAdjustTime(Event *event);
|
||||
static std::weak_ptr<GameProtocol> m_game_protocol;
|
||||
std::map<STKPeer*, int> m_initial_ticks;
|
||||
|
||||
public:
|
||||
GameProtocol();
|
||||
virtual ~GameProtocol();
|
||||
@@ -104,6 +107,8 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the NetworkString in which a state was saved. */
|
||||
NetworkString* getState() const { return m_data_to_send; }
|
||||
// ------------------------------------------------------------------------
|
||||
void addInitialTicks(STKPeer* p, int ticks);
|
||||
|
||||
}; // class GameProtocol
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/protocol_manager.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/servers_manager.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "online/xml_request.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
@@ -97,30 +98,40 @@ void RequestConnection::asynchronousUpdate()
|
||||
(STKHost::get()->isClientServer() ? "-localhost" :
|
||||
StringUtils::toString(m_server->getPrivatePort())));
|
||||
|
||||
TransportAddress server_addr;
|
||||
if (!NetworkConfig::m_disable_lan &&
|
||||
m_server->getAddress().getIP() ==
|
||||
STKHost::get()->getPublicAddress().getIP() &&
|
||||
!STKHost::get()->isClientServer())
|
||||
{
|
||||
// If use lan connection in wan server, send a broadcast
|
||||
server_addr.setIP(0xffffffff);
|
||||
// If use lan connection in wan server, send to all
|
||||
// broadcast address
|
||||
for (auto& addr :
|
||||
ServersManager::get()->getBroadcastAddresses())
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
STKHost::get()->sendRawPacket(message, addr);
|
||||
StkTime::sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TransportAddress server_addr;
|
||||
server_addr.setIP(m_server->getAddress().getIP());
|
||||
// Direct socket always listens on server discovery port
|
||||
server_addr.setPort(NetworkConfig::get()
|
||||
->getServerDiscoveryPort());
|
||||
// Avoid possible packet loss, the connect to peer done by
|
||||
// server will auto terminate if same peer from same port
|
||||
// has connected already
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
STKHost::get()->sendRawPacket(message, server_addr);
|
||||
StkTime::sleep(1);
|
||||
}
|
||||
}
|
||||
// Direct socket always listens on server discovery port
|
||||
server_addr.setPort(NetworkConfig::get()
|
||||
->getServerDiscoveryPort());
|
||||
// Avoid possible packet loss, the connect to peer done by
|
||||
// server will auto terminate if same peer from same port
|
||||
// has connected already
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
STKHost::get()->sendRawPacket(message, server_addr);
|
||||
StkTime::sleep(1);
|
||||
}
|
||||
|
||||
m_state = DONE;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -330,10 +330,16 @@ void ServerLobby::asynchronousUpdate()
|
||||
}
|
||||
break;
|
||||
case SELECTING:
|
||||
if (m_timeout.load() < (float)StkTime::getRealTime())
|
||||
{
|
||||
auto result = handleVote();
|
||||
if (m_timeout.load() < (float)StkTime::getRealTime() ||
|
||||
(std::get<3>(result) &&
|
||||
m_timeout.load() - (UserConfigParams::m_voting_timeout / 2.0f) <
|
||||
(float)StkTime::getRealTime()))
|
||||
{
|
||||
m_game_setup->setRace(std::get<0>(result), std::get<1>(result),
|
||||
std::get<2>(result));
|
||||
std::lock_guard<std::mutex> lock(m_connection_mutex);
|
||||
auto result = handleVote();
|
||||
// Remove disconnected player (if any) one last time
|
||||
m_game_setup->update(true);
|
||||
m_game_setup->sortPlayersForGrandPrix();
|
||||
@@ -370,6 +376,7 @@ void ServerLobby::asynchronousUpdate()
|
||||
delete load_world;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1017,7 +1024,7 @@ void ServerLobby::connectionRequested(Event* event)
|
||||
peer->sendPacket(server_info);
|
||||
delete server_info;
|
||||
|
||||
m_peers_ready[peer] = false;
|
||||
m_peers_ready[peer] = std::make_pair(false, 0.0);
|
||||
for (std::shared_ptr<NetworkPlayerProfile> npp : peer->getPlayerProfiles())
|
||||
{
|
||||
m_game_setup->addPlayer(npp);
|
||||
@@ -1183,7 +1190,7 @@ void ServerLobby::playerVote(Event* event)
|
||||
} // playerVote
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
std::tuple<std::string, uint8_t, bool> ServerLobby::handleVote()
|
||||
std::tuple<std::string, uint8_t, bool, bool> ServerLobby::handleVote()
|
||||
{
|
||||
// Default settings if no votes at all
|
||||
RandomGenerator rg;
|
||||
@@ -1196,6 +1203,20 @@ std::tuple<std::string, uint8_t, bool> ServerLobby::handleVote()
|
||||
std::map<std::string, unsigned> tracks;
|
||||
std::map<unsigned, unsigned> laps;
|
||||
std::map<bool, unsigned> reverses;
|
||||
|
||||
float cur_players = 0.0f;
|
||||
auto peers = STKHost::get()->getPeers();
|
||||
for (auto peer : peers)
|
||||
{
|
||||
if (peer->hasPlayerProfiles())
|
||||
cur_players += 1.0f;
|
||||
}
|
||||
if (cur_players == 0.0f)
|
||||
return std::make_tuple(final_track, final_laps, final_reverse, false);
|
||||
float tracks_rate = 0.0f;
|
||||
float laps_rate = 0.0f;
|
||||
float reverses_rate = 0.0f;
|
||||
|
||||
for (auto p : m_peers_votes)
|
||||
{
|
||||
if (p.first.expired())
|
||||
@@ -1228,7 +1249,10 @@ std::tuple<std::string, uint8_t, bool> ServerLobby::handleVote()
|
||||
}
|
||||
}
|
||||
if (track_vote != tracks.end())
|
||||
{
|
||||
final_track = track_vote->first;
|
||||
tracks_rate = float(track_vote->second) / cur_players;
|
||||
}
|
||||
|
||||
vote = 0;
|
||||
auto lap_vote = laps.begin();
|
||||
@@ -1241,7 +1265,10 @@ std::tuple<std::string, uint8_t, bool> ServerLobby::handleVote()
|
||||
}
|
||||
}
|
||||
if (lap_vote != laps.end())
|
||||
{
|
||||
final_laps = lap_vote->first;
|
||||
laps_rate = float(lap_vote->second) / cur_players;
|
||||
}
|
||||
|
||||
vote = 0;
|
||||
auto reverse_vote = reverses.begin();
|
||||
@@ -1254,10 +1281,14 @@ std::tuple<std::string, uint8_t, bool> ServerLobby::handleVote()
|
||||
}
|
||||
}
|
||||
if (reverse_vote != reverses.end())
|
||||
{
|
||||
final_reverse = reverse_vote->first;
|
||||
reverses_rate = float(reverse_vote->second) / cur_players;
|
||||
}
|
||||
|
||||
m_game_setup->setRace(final_track, final_laps, final_reverse);
|
||||
return std::make_tuple(final_track, final_laps, final_reverse);
|
||||
return std::make_tuple(final_track, final_laps, final_reverse,
|
||||
tracks_rate > 0.5f && laps_rate > 0.5f && reverses_rate > 0.5f ?
|
||||
true : false);
|
||||
} // handleVote
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -1276,7 +1307,7 @@ void ServerLobby::finishedLoadingWorld()
|
||||
void ServerLobby::finishedLoadingWorldClient(Event *event)
|
||||
{
|
||||
std::shared_ptr<STKPeer> peer = event->getPeerSP();
|
||||
m_peers_ready.at(peer) = true;
|
||||
m_peers_ready.at(peer) = std::make_pair(true, StkTime::getRealTime());
|
||||
Log::info("ServerLobby", "Peer %d has finished loading world at %lf",
|
||||
peer->getHostId(), StkTime::getRealTime());
|
||||
} // finishedLoadingWorldClient
|
||||
@@ -1293,12 +1324,40 @@ void ServerLobby::finishedLoadingWorldClient(Event *event)
|
||||
void ServerLobby::startedRaceOnClient(Event *event)
|
||||
{
|
||||
std::shared_ptr<STKPeer> peer = event->getPeerSP();
|
||||
m_peers_ready.at(peer) = true;
|
||||
m_peers_ready.at(peer) = std::make_pair(true, StkTime::getRealTime());
|
||||
Log::info("ServerLobby", "Peer %d has started race at %lf",
|
||||
peer->getHostId(), StkTime::getRealTime());
|
||||
|
||||
if (checkPeersReady())
|
||||
{
|
||||
std::vector<std::pair<STKPeer*, double> > mapping;
|
||||
for (auto p : m_peers_ready)
|
||||
{
|
||||
auto peer = p.first.lock();
|
||||
if (!peer)
|
||||
continue;
|
||||
mapping.emplace_back(peer.get(), p.second.second);
|
||||
}
|
||||
std::sort(mapping.begin(), mapping.end(),
|
||||
[](const std::pair<STKPeer*, double>& a,
|
||||
const std::pair<STKPeer*, double>& b)->bool
|
||||
{
|
||||
return a.second > b.second;
|
||||
});
|
||||
for (unsigned i = 0; i < mapping.size(); i++)
|
||||
{
|
||||
// Server delay is 0.1, so it's around 12 ticks
|
||||
// (0.1 * 120 (physics fps)) for the highest ping client
|
||||
if (i == 0)
|
||||
GameProtocol::lock()->addInitialTicks(mapping[0].first, 12);
|
||||
else
|
||||
{
|
||||
const double diff = mapping[0].second - mapping[i].second;
|
||||
assert(diff >= 0.0);
|
||||
GameProtocol::lock()->addInitialTicks(mapping[i].first,
|
||||
12 + stk_config->time2Ticks((float)diff));
|
||||
}
|
||||
}
|
||||
m_state = DELAY_SERVER;
|
||||
m_server_delay = StkTime::getRealTime() + 0.1;
|
||||
Log::verbose("ServerLobby", "Started delay at %lf set delay to %lf",
|
||||
@@ -1315,7 +1374,7 @@ void ServerLobby::playerFinishedResult(Event *event)
|
||||
if (m_state.load() != RESULT_DISPLAY)
|
||||
return;
|
||||
std::shared_ptr<STKPeer> peer = event->getPeerSP();
|
||||
m_peers_ready.at(peer) = true;
|
||||
m_peers_ready.at(peer) = std::make_pair(true, StkTime::getRealTime());
|
||||
} // playerFinishedResult
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -48,7 +48,7 @@ private:
|
||||
std::atomic_bool m_server_has_loaded_world;
|
||||
|
||||
/** Counts how many peers have finished loading the world. */
|
||||
std::map<std::weak_ptr<STKPeer>, bool,
|
||||
std::map<std::weak_ptr<STKPeer>, std::pair<bool, double>,
|
||||
std::owner_less<std::weak_ptr<STKPeer> > > m_peers_ready;
|
||||
|
||||
/** Vote from each peer. */
|
||||
@@ -102,7 +102,7 @@ private:
|
||||
{
|
||||
if (p.first.expired())
|
||||
continue;
|
||||
all_ready = all_ready && p.second;
|
||||
all_ready = all_ready && p.second.first;
|
||||
if (!all_ready)
|
||||
return false;
|
||||
}
|
||||
@@ -118,12 +118,13 @@ private:
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second = false;
|
||||
it->second.first = false;
|
||||
it->second.second = 0.0;
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::tuple<std::string, uint8_t, bool> handleVote();
|
||||
std::tuple<std::string, uint8_t, bool, bool> handleVote();
|
||||
void stopCurrentRace();
|
||||
|
||||
public:
|
||||
|
||||
@@ -74,7 +74,7 @@ RewindManager::~RewindManager()
|
||||
void RewindManager::reset()
|
||||
{
|
||||
m_is_rewinding = false;
|
||||
m_not_rewound_ticks = 0;
|
||||
m_not_rewound_ticks.store(0);
|
||||
m_overall_state_size = 0;
|
||||
m_last_saved_state = -1; // forces initial state save
|
||||
m_state_frequency =
|
||||
@@ -249,7 +249,7 @@ void RewindManager::update(int ticks_not_used)
|
||||
float time = World::getWorld()->getTime();
|
||||
int ticks = World::getWorld()->getTimeTicks();
|
||||
|
||||
m_not_rewound_ticks = ticks;
|
||||
m_not_rewound_ticks.store(ticks, std::memory_order_relaxed);
|
||||
|
||||
// Clients don't save state, so they just exit.
|
||||
if (NetworkConfig::get()->isClient() ||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "utils/synchronised.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <atomic>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
@@ -109,7 +110,7 @@ private:
|
||||
/** This stores the original World time in ticks during a rewind. It is
|
||||
* used to detect if a client's local time need adjustment to reduce
|
||||
* rewinds. */
|
||||
int m_not_rewound_ticks;
|
||||
std::atomic<int> m_not_rewound_ticks;
|
||||
|
||||
RewindManager();
|
||||
~RewindManager();
|
||||
@@ -163,7 +164,8 @@ public:
|
||||
/** Returns true if currently a rewind is happening. */
|
||||
bool isRewinding() const { return m_is_rewinding; }
|
||||
// ------------------------------------------------------------------------
|
||||
int getNotRewoundWorldTicks() const { return m_not_rewound_ticks; }
|
||||
int getNotRewoundWorldTicks() const
|
||||
{ return m_not_rewound_ticks.load(std::memory_order_relaxed); }
|
||||
}; // RewindManager
|
||||
|
||||
|
||||
|
||||
@@ -315,6 +315,8 @@ void ServersManager::setDefaultBroadcastAddresses()
|
||||
m_broadcast_address.emplace_back(std::string("255.255.255.255"));
|
||||
m_broadcast_address.emplace_back(std::string("127.0.0.255") );
|
||||
m_broadcast_address.emplace_back(std::string("127.0.0.1") );
|
||||
for (auto& addr : m_broadcast_address)
|
||||
addr.setPort(NetworkConfig::get()->getServerDiscoveryPort());
|
||||
} // setDefaultBroadcastAddresses
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -381,7 +383,7 @@ void ServersManager::updateBroadcastAddresses()
|
||||
|
||||
if (return_code == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
Log::warn("NetworkConfig", "Can not get broadcast addresses.");
|
||||
Log::warn("ServerManager", "Can not get broadcast addresses.");
|
||||
setDefaultBroadcastAddresses();
|
||||
return;
|
||||
}
|
||||
@@ -418,7 +420,8 @@ void ServersManager::updateBroadcastAddresses()
|
||||
u = (u & 0x33333333) + ((u >> 2) & 0x33333333);
|
||||
u = (((u + (u >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
|
||||
|
||||
printf("Interface: %s\tAddress: %s\tmask: %x\n", p->ifa_name,
|
||||
Log::debug("ServerManager",
|
||||
"Interface: %s\tAddress: %s\tmask: %x\n", p->ifa_name,
|
||||
ta.toString().c_str(), u);
|
||||
addAllBroadcastAddresses(ta, u);
|
||||
}
|
||||
|
||||
@@ -82,9 +82,29 @@ RaceGUI::RaceGUI()
|
||||
else
|
||||
m_lap_width = font->getDimension(L"9/9").Width;
|
||||
|
||||
float map_size_splitscreen = 1.0f;
|
||||
|
||||
// If there are four players or more in splitscreen
|
||||
// and the map is in a player view, scale down the map
|
||||
if (race_manager->getNumLocalPlayers() >= 4 && !race_manager->getIfEmptyScreenSpaceExists())
|
||||
{
|
||||
// If the resolution is wider than 4:3, we don't have to scaledown the minimap as much
|
||||
// Uses some margin, in case the game's screen is not exactly 4:3
|
||||
if ( ((float) irr_driver->getFrameSize().Width / (float) irr_driver->getFrameSize().Height) >
|
||||
(4.1f/3.0f))
|
||||
{
|
||||
if (race_manager->getNumLocalPlayers() == 4)
|
||||
map_size_splitscreen = 0.75f;
|
||||
else
|
||||
map_size_splitscreen = 0.5f;
|
||||
}
|
||||
else
|
||||
map_size_splitscreen = 0.5f;
|
||||
}
|
||||
|
||||
// Originally m_map_height was 100, and we take 480 as minimum res
|
||||
float scaling = irr_driver->getFrameSize().Height / 480.0f;
|
||||
const float map_size = 100.0f;
|
||||
const float map_size = stk_config->m_minimap_size * map_size_splitscreen;
|
||||
const float top_margin = 3.5f * m_font_height;
|
||||
|
||||
if (UserConfigParams::m_multitouch_enabled &&
|
||||
@@ -107,8 +127,8 @@ RaceGUI::RaceGUI()
|
||||
|
||||
// Marker texture has to be power-of-two for (old) OpenGL compliance
|
||||
//m_marker_rendered_size = 2 << ((int) ceil(1.0 + log(32.0 * scaling)));
|
||||
m_minimap_ai_size = (int)( 14.0f * scaling);
|
||||
m_minimap_player_size = (int)( 16.0f * scaling);
|
||||
m_minimap_ai_size = (int)( stk_config->m_minimap_ai_icon * scaling);
|
||||
m_minimap_player_size = (int)( stk_config->m_minimap_player_icon * scaling);
|
||||
m_map_width = (int)(map_size * scaling);
|
||||
m_map_height = (int)(map_size * scaling);
|
||||
m_map_left = (int)( 10.0f * scaling);
|
||||
@@ -209,6 +229,9 @@ void RaceGUI::renderGlobal(float dt)
|
||||
if(world->getPhase() == World::GOAL_PHASE)
|
||||
drawGlobalGoal();
|
||||
|
||||
// MiniMap is drawn when the players wait for the start countdown to end
|
||||
drawGlobalMiniMap();
|
||||
|
||||
// Timer etc. are not displayed unless the game is actually started.
|
||||
if(!world->isRacePhase()) return;
|
||||
if (!m_enabled) return;
|
||||
@@ -227,8 +250,6 @@ void RaceGUI::renderGlobal(float dt)
|
||||
}
|
||||
}
|
||||
|
||||
drawGlobalMiniMap();
|
||||
|
||||
if (!m_is_tutorial) drawGlobalPlayerIcons(m_map_height);
|
||||
if(Track::getCurrentTrack()->isSoccer()) drawScores();
|
||||
#endif
|
||||
@@ -253,7 +274,7 @@ void RaceGUI::renderPlayerView(const Camera *camera, float dt)
|
||||
|
||||
drawPlungerInFace(camera, dt);
|
||||
|
||||
if (viewport.getWidth() != irr_driver->getActualScreenSize().Width)
|
||||
if (viewport.getWidth() != (int)irr_driver->getActualScreenSize().Width)
|
||||
{
|
||||
scaling *= float(viewport.getWidth()) / float(irr_driver->getActualScreenSize().Width); // scale race GUI along screen size
|
||||
}
|
||||
@@ -437,7 +458,23 @@ void RaceGUI::drawGlobalMiniMap()
|
||||
lower_y -(int)(draw_at.getY()+marker_half_size),
|
||||
m_map_left+(int)(draw_at.getX()+marker_half_size),
|
||||
lower_y -(int)(draw_at.getY()-marker_half_size));
|
||||
|
||||
// Highlight the player icons with some backgorund image.
|
||||
if (kart->getController()->isLocalPlayerController())
|
||||
{
|
||||
video::SColor colors[4];
|
||||
for (unsigned int i=0;i<4;i++)
|
||||
{
|
||||
colors[i]=kart->getKartProperties()->getColor();
|
||||
}
|
||||
const core::rect<s32> rect(core::position2d<s32>(0,0),
|
||||
m_icons_frame->getSize());
|
||||
|
||||
draw2DImage(m_icons_frame, position, rect, NULL, colors, true);
|
||||
} // if isPlayerController
|
||||
|
||||
draw2DImage(icon, position, source, NULL, NULL, true);
|
||||
|
||||
} // for i<getNumKarts
|
||||
|
||||
SoccerWorld *sw = dynamic_cast<SoccerWorld*>(World::getWorld());
|
||||
|
||||
@@ -1118,10 +1118,9 @@ void Track::loadMinimap()
|
||||
|
||||
//Create the minimap resizing it as necessary.
|
||||
m_mini_map_size = World::getWorld()->getRaceGUI()->getMiniMapSize();
|
||||
core::dimension2du size = m_mini_map_size
|
||||
.getOptimalSize(!nonpower,!nonsquare);
|
||||
|
||||
m_render_target = Graph::get()->makeMiniMap(size, "minimap::" + m_ident, video::SColor(127, 255, 255, 255));
|
||||
//Use twice the size of the rendered minimap to reduce significantly aliasing
|
||||
m_render_target = Graph::get()->makeMiniMap(m_mini_map_size*2, "minimap::" + m_ident, video::SColor(127, 255, 255, 255));
|
||||
if (!m_render_target) return;
|
||||
|
||||
core::dimension2du mini_map_texture_size = m_render_target->getTextureSize();
|
||||
|
||||
Reference in New Issue
Block a user