Merge with latest master

This commit is contained in:
Alayan 2018-10-05 17:55:02 +02:00
commit fc969982da
81 changed files with 2396 additions and 1786 deletions

View File

@ -27,7 +27,7 @@
<label proportion="1" align="center" text_align="right" I18N="In the multitouch settings screen" text="Buttons scale"/>
<div proportion="1" align="center" height="fit" layout="horizontal-row" >
<spacer width="40" height="10" />
<gauge id="scale" proportion="1" min_value="50" max_value="150"/>
<gauge id="scale" proportion="1" min_value="80" max_value="160"/>
</div>
</div>

View File

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<stkgui>
<div y="2%" width="100%" height="96%" layout="vertical-row">
<div x="1%" y="2%" width="98%" height="96%" layout="vertical-row">
<div width="100%" height="40%" layout="vertical-row">
<div width="100%" height="25%" layout="vertical-row" >
<label id="name" width="100%" text_align="center"/>
</div>
<!-- This is filled in programmatically -->
<box width="98%" height="75%" align="center" layout="vertical-row" padding="1">
<box width="100%" height="75%" align="center" layout="vertical-row" padding="1">
<list id="current_replay_info" x="0" y="0" width="100%" height="100%"/>
</box>
</div>
@ -18,8 +18,8 @@
</div>
<div width="64%" height="100%" layout="vertical-row">
<div width="95%" align="center" layout="vertical-row" height="fit">
<div width="100%" height="40" layout="horizontal-row" >
<div width="95%" align="center" layout="vertical-row" height="50%">
<div width="100%" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="record-race" I18N="Ghost replay info action" text_align="left"/>
<spacer width="10"/>
<label proportion="1" id="record-race-text" height="100%" text_align="left" I18N="Ghost replay info action" text="Record the race for ghost replay"/>
@ -36,7 +36,7 @@
</div>
</div>
<div width="95%" height="50%" align="center">
<div width="95%" height="40%" align="center">
<buttonbar id="actions" x="0" y="0" height="100%" width="100%" align="center">
<icon-button id="start" width="128" height="128"
icon="gui/icons/green_check.png"

View File

@ -13,50 +13,55 @@
<list id="replay_list" x="0" y="0" width="100%" height="100%"/>
</box>
<tabs id="race_mode" height="6%" max_height="110" x="2%" width="98%" align="center">
<tabs id="race_mode" height="6%" max_height="110" x="1%" width="98%" align="center">
<icon-button id="tab_time_trial" width="128" height="128" icon="gui/icons/mode_tt.png"
I18N="In the ghost replay selection screen" text="Time trial"/>
<icon-button id="tab_egg_hunt" width="128" height="128" icon="gui/icons/mode_easter.png"
I18N="In the ghost replay selection screen" text="Egg hunt"/>
</tabs>
<spacer width="100%" height="1.5%" />
<spacer width="100%" height="2%" />
<div width="99%" align="center" layout="horizontal-row" height="fit">
<div proportion="1" height="fit" layout="horizontal-row" >
<div width="98%" align="center" layout="horizontal-row" height="fit">
<div width="60%" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="best_times_toggle" text_align="left"/>
<spacer width="2%" height="fit"/>
<label height="100%" text_align="left" I18N="In the ghost replay selection screen" text="Only show the best times"/>
</div>
<div proportion="1" height="fit" layout="horizontal-row" >
<div width="40%" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="compare_toggle" text_align="left"/>
<spacer width="2%" height="fit"/>
<label height="100%" id="compare-toggle-text" text_align="left" I18N="In the ghost replay selection screen" text="Compare replay"/>
</div>
</div>
<div width="99%" align="center" layout="horizontal-row" height="fit">
<div proportion="2" height="fit" layout="horizontal-row" >
<div width="98%" align="center" layout="horizontal-row" height="fit">
<div width="60%" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="replay_difficulty_toggle" text_align="left"/>
<spacer width="2%" height="fit"/>
<label height="100%" text_align="left" I18N="In the ghost replay selection screen" text="Only show replays matching the current difficulty"/>
</div>
<div proportion="1" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="replay_multiplayer_toggle" text_align="left"/>
<spacer width="2%" height="fit"/>
<label height="100%" text_align="left" I18N="In the ghost replay selection screen" text="Hide multiplayer replays"/>
</div>
</div>
<div width="99%" align="center" layout="horizontal-row" height="fit">
<div proportion="1" height="fit" layout="horizontal-row" >
<div width="98%" align="center" layout="horizontal-row" height="fit">
<div width="60%" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="replay_version_toggle" text_align="left"/>
<spacer width="1%" height="fit" />
<spacer width="2%" height="fit" />
<label height="100%" text_align="left" I18N="In the ghost replay selection screen" text="Only show replays matching the current version"/>
</div>
</div>
<button x="1%" id="record-ghost" I18N="In the ghost replay selection screen" text="Record a ghost replay"/>
<div width="98%" align="center" layout="horizontal-row" height="fit">
<div width="60%" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="replay_multiplayer_toggle" text_align="left"/>
<spacer width="2%" height="fit"/>
<label height="100%" text_align="left" I18N="In the ghost replay selection screen" text="Hide multiplayer replays"/>
</div>
<div width="40%" height="fit" layout="horizontal-row" >
<spacer proportion="1" height="5"/>
<button width="fit" id="record-ghost" I18N="In the ghost replay selection screen" text="Record a ghost replay"/>
</div>
</div>
</div>
</stkgui>

View File

@ -17,7 +17,7 @@
<checkbox width="fit" id="private_server" text_align="left"/>
<spacer width="10"/>
<label proportion="1" height="100%" text_align="left"
I18N="In the server selection screen" text="Show only private server(s)"/>
I18N="In the server selection screen" text="Show private server(s)"/>
<checkbox width="fit" id="game_started" text_align="left"/>
<spacer width="10"/>
<label proportion="1" height="100%" text_align="left"

View File

@ -67,7 +67,7 @@
The actual turn radius is piece-wise linearly interpolated. This
allows for tighter turning at lower speeds, and also avoids that
the kart becomes too hard to control at high speed (speeds of
higher than 23 can only be reached with powerups).
higher than 25 can only be reached with powerups).
time-full-steer: This is the amount of change in steering depending
on current steering. So if the steering is between 0 and 0.5,
the time-for-steering-change is 0.15. If the current steering is

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@
<!-- Minimum and maxium server versions that be be read by this binary.
Older versions will be ignored. -->
<server-version min="1" max="1"/>
<server-version min="2" max="2"/>
<!-- 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
@ -114,7 +114,7 @@
that the bit is to be set to 0, otherwise the bit will be set.
This field takes two
values: the first value is 'and'ed with bullet's default values
values: the first value is 'and'ed with bullet's default values
(i.e. it can be used to unset bullet defaults), the second value
is 'or'ed (i.e. is used to set a bit). A value of -1 for 'and'
means to keep all bits. The valid names are listed in stk_config.cpp
@ -125,7 +125,7 @@
smooth-angle-limit="0.65"
fps="120"
default-track-friction="0.5"
default-moveable-friction="0.5"
default-moveable-friction="0.5"
solver-iterations="4"
solver-split-impulse="true"
solver-split-impulse-threshold="-0.00001"
@ -149,14 +149,14 @@
<replay max-frames="12000" delta-t="0.200" delta-speed="0.6"
delta-steering="0.35" />
<!-- Determines the minimap related values.
<!-- 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"/>
<urls donate="https://supertuxkart.net/Donate"
<urls donate="https://supertuxkart.net/Donate"
password-reset="http://addons.supertuxkart.net/password-reset.php" />
<!-- Skidmark data: maximum number of skid marks, and
@ -201,7 +201,7 @@
away if there is an explosion. -->
<explosion impulse-objects="500.0" />
<!-- Networking
<!-- Networking
state-frequency: how many states the server will send per second.
steering-reduction: Reduce a remote kart's steering by this factor
each frame. This helps reduces oversteering by high latency

View File

@ -133,6 +133,20 @@ namespace scene
}
}
virtual void recursiveUpdateAbsolutePosition()
{
if (IsVisible)
{
// update absolute position
updateAbsolutePosition();
// perform the post render process on all children
ISceneNodeList::Iterator it = Children.begin();
for (; it != Children.end(); ++it)
(*it)->recursiveUpdateAbsolutePosition();
}
}
//! Renders the node.
virtual void render() = 0;

View File

@ -249,6 +249,10 @@ void CAnimatedMeshSceneNode::OnAnimate(u32 timeMs)
LastTimeMs = timeMs;
IAnimatedMeshSceneNode::OnAnimate(timeMs);
// For up-to-date current frame bone-child attachment
for (u32 n=0;n<JointChildSceneNodes.size();++n)
JointChildSceneNodes[n]->recursiveUpdateAbsolutePosition();
}

View File

@ -186,6 +186,9 @@ void CIrrDeviceAndroid::createVideoModeList()
int width = ANativeWindow_getWidth(Android->window);
int height = ANativeWindow_getHeight(Android->window);
os::Printer::log("Window width:", core::stringc(width).c_str(), ELL_DEBUG);
os::Printer::log("Window height:", core::stringc(height).c_str(), ELL_DEBUG);
if (width > 0 && height > 0)
{

View File

@ -762,7 +762,7 @@ namespace UserConfigParams
&m_network_group, "Use random port for server connection "
"(check stk_config.xml for default value)"));
PARAM_PREFIX BoolUserConfigParam m_lobby_chat
PARAM_DEFAULT(BoolUserConfigParam(false, "lobby-chat",
PARAM_DEFAULT(BoolUserConfigParam(true, "lobby-chat",
&m_network_group, "Enable chatting in networking lobby, if off than "
"no chat message will be displayed from any players."));
PARAM_PREFIX IntUserConfigParam m_max_players

View File

@ -23,6 +23,7 @@
#include <sstream>
#include "config/user_config.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/material.hpp"
#include "graphics/particle_kind_manager.hpp"
#include "graphics/sp/sp_texture_manager.hpp"
@ -57,9 +58,10 @@ MaterialManager::MaterialManager()
MaterialManager::~MaterialManager()
{
#ifndef SERVER_ONLY
SP::SPTextureManager::get()->stopThreads();
if (CVS->isGLSL())
SP::SPTextureManager::get()->stopThreads();
#endif
for(unsigned int i=0; i<m_materials.size(); i++)
{
delete m_materials[i];

View File

@ -272,7 +272,9 @@ PlayerKartWidget::~PlayerKartWidget()
if (m_kart_name->getIrrlichtElement() != NULL)
m_kart_name->getIrrlichtElement()->remove();
getCurrentScreen()->manualRemoveWidget(this);
if (getCurrentScreen() != NULL)
getCurrentScreen()->manualRemoveWidget(this);
#ifdef DEBUG
m_magic_number = 0xDEADBEEF;

View File

@ -631,3 +631,26 @@ std::string AssetsAndroid::getDataPath()
return "";
}
//-----------------------------------------------------------------------------
/** Get a path for internal lib directory
* \return Path for internal lib directory or empty string when failed
*/
std::string AssetsAndroid::getLibPath()
{
#ifdef ANDROID
AndroidApplicationInfo application_info =
CIrrDeviceAndroid::getApplicationInfo(global_android_app->activity);
std::string lib_path = application_info.native_lib_dir;
if (access(lib_path.c_str(), R_OK) != 0)
{
lib_path = "";
}
return lib_path;
#endif
return "";
}

View File

@ -43,6 +43,7 @@ public:
void init();
static std::string getDataPath();
static std::string getLibPath();
};

View File

@ -110,7 +110,8 @@ Attachment::~Attachment()
*/
void Attachment::set(AttachmentType type, int ticks,
AbstractKart *current_kart,
bool disable_swatter_animation)
bool disable_swatter_animation,
bool set_by_rewind_parachute)
{
// Don't override currently player swatter removing bomb animation
Swatter* s = dynamic_cast<Swatter*>(m_plugin);
@ -179,7 +180,8 @@ void Attachment::set(AttachmentType type, int ticks,
// A parachute can be attached as result of the usage of an item. In this
// case we have to save the current kart speed so that it can be detached
// by slowing down.
if(m_type==ATTACH_PARACHUTE)
// if set by rewind the parachute ticks is already correct
if (m_type == ATTACH_PARACHUTE && !set_by_rewind_parachute)
{
const KartProperties *kp = m_kart->getKartProperties();
float speed_mult;
@ -306,19 +308,16 @@ void Attachment::rewindTo(BareNetworkString *buffer)
// Attaching an object can be expensive (loading new models, ...)
// so avoid doing this if there is no change in attachment type
// Don't use set to reset a model on local player if it's already cleared
// (or m_initial_speed is redone / model is re-shown again when rewinding)
if (m_type == new_type || m_type == ATTACH_NOTHING)
if (m_type == new_type)
{
setTicksLeft(ticks_left);
if (m_type != new_type && new_type != ATTACH_SWATTER)
m_type = new_type;
return;
}
set(new_type, ticks_left, m_previous_owner,
new_type == ATTACH_SWATTER && !is_removing_bomb
/*disable_swatter_animation*/);
/*disable_swatter_animation*/,
new_type == ATTACH_PARACHUTE);
} // rewindTo
// -----------------------------------------------------------------------------
@ -353,6 +352,12 @@ void Attachment::hitBanana(ItemState *item_state)
return;
}
// Make it consistent with attachment rewind when eating banana with bomb
// see if (m_type == ATTACH_BOMB && m_kart->getKartAnimation() != NULL)
// in 515
if (m_kart->getKartAnimation())
return;
AttachmentType new_attachment = ATTACH_NOTHING;
const KartProperties *kp = m_kart->getKartProperties();
// Use this as a basic random number to make sync with server easier.
@ -529,13 +534,19 @@ void Attachment::update(int ticks)
m_node->setVisible((division & 0x1) == 0);
}
if(m_plugin)
if (m_plugin)
{
bool discard = m_plugin->updateAndTestFinished(ticks);
if(discard)
int discard_ticks = m_plugin->updateAndTestFinished(ticks);
if (discard_ticks != -1)
{
clear(); // also removes the plugin
return;
// Save it for rewinding
m_ticks_left =
discard_ticks - World::getWorld()->getTicksSinceStart();
if (m_ticks_left <= 0)
{
clear(); // also removes the plugin
return;
}
}
}

View File

@ -116,7 +116,8 @@ public:
void handleCollisionWithKart(AbstractKart *other);
void set (AttachmentType type, int ticks,
AbstractKart *previous_kart=NULL,
bool disable_swatter_animation = false);
bool disable_swatter_animation = false,
bool set_by_rewind_parachute = false);
void rewindTo(BareNetworkString *buffer);
void saveState(BareNetworkString *buffer) const;

View File

@ -53,8 +53,9 @@ public:
// ------------------------------------------------------------------------
/** Updates a plugin. This is called once each time frame. If the
* function returns true, the attachment is discarded. */
virtual bool updateAndTestFinished(int ticks) = 0;
* function returns a non-negative number, the attachment is discarded
* when world ticks >= that number. */
virtual int updateAndTestFinished(int ticks) = 0;
// ------------------------------------------------------------------------
/** Called when the animation of the Attachment's node is done. */

View File

@ -224,6 +224,10 @@ public:
// ------------------------------------------------------------------------
/** Returns the type of flyable. */
PowerupManager::PowerupType getType() const {return m_type;}
// ------------------------------------------------------------------------
/** Returns the owner's kart */
AbstractKart *getOwner() const { return m_owner;}
// ------------------------------------------------------------------------
/** Returns the owner's kart */
AbstractKart *getOwner() const { return m_owner;}

View File

@ -37,6 +37,25 @@
#include <ISceneManager.h>
// ----------------------------------------------------------------------------
/** Constructor.
* \param type Type of the item.
* \param owner If not NULL it is the kart that dropped this item; NULL
* indicates an item that's part of the track.
* \param id Index of this item in the array of all items.
*/
ItemState::ItemState(ItemType type, const AbstractKart *owner, int id)
{
setType(type);
m_item_id = id;
m_previous_owner = owner;
m_used_up_counter = -1;
if (owner)
setDeactivatedTicks(stk_config->time2Ticks(1.5f));
else
setDeactivatedTicks(0);
} // ItemState(ItemType)
// ------------------------------------------------------------------------
/** Sets the disappear counter depending on type. */
void ItemState::setDisappearCounter()
@ -52,9 +71,23 @@ void ItemState::setDisappearCounter()
} // switch
} // setDisappearCounter
// -----------------------------------------------------------------------
/** Initialises an item.
* \param type Type for this item.
*/
void ItemState::initItem(ItemType type, const Vec3& xyz)
{
m_xyz = xyz;
m_original_type = ITEM_NONE;
m_ticks_till_return = 0;
setDisappearCounter();
} // initItem
// ----------------------------------------------------------------------------
/** Update the state of the item, called once per physics frame.
* \param ticks Number of ticks to simulate (typically 1).
* \param ticks Number of ticks to simulate. While this value is 1 when
* called during the normal game loop, during a rewind this value
* can be (much) larger than 1.
*/
void ItemState::update(int ticks)
{
@ -107,12 +140,17 @@ void ItemState::collected(const AbstractKart *kart)
* \param normal The normal upon which the item is placed (so that it can
* be aligned properly with the ground).
* \param mesh The mesh to be used for this item.
* \param owner 'Owner' of this item, i.e. the kart that drops it. This is
* used to deactivate this item for the owner, i.e. avoid that a kart
* 'collects' its own bubble gum. NULL means no owner, and the item
* can be collected immediatley by any kart.
* \param is_predicted True if the creation of the item is predicted by
* a client. Only used in networking.
*/
Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal,
scene::IMesh* mesh, scene::IMesh* lowres_mesh, bool is_predicted)
: ItemState(type)
scene::IMesh* mesh, scene::IMesh* lowres_mesh,
const AbstractKart *owner, bool is_predicted)
: ItemState(type, owner)
{
assert(type != ITEM_TRIGGER); // use other constructor for that
@ -190,7 +228,6 @@ Item::Item(const Vec3& xyz, float distance, TriggerItemListener* trigger)
void Item::initItem(ItemType type, const Vec3 &xyz)
{
ItemState::initItem(type, xyz);
m_previous_owner = NULL;
m_rotate = (getType()!=ITEM_BUBBLEGUM) &&
(getType()!=ITEM_TRIGGER );
// Now determine in which quad this item is, and its distance
@ -334,17 +371,6 @@ void Item::reset()
}
} // reset
//-----------------------------------------------------------------------------
/** Sets which karts dropped an item. This is used to avoid that a kart is
* affected by its own items.
* \param parent Kart that dropped the item.
*/
void Item::setParent(const AbstractKart* parent)
{
m_previous_owner = parent;
ItemState::setDeactivatedTicks(stk_config->time2Ticks(1.5f));
} // setParent
// ----------------------------------------------------------------------------
/** Updated the item - rotates it, takes care of items coming back into
* the game after it has been collected.

View File

@ -122,35 +122,25 @@ private:
* and then converting this value to a Vec3. */
Vec3 m_xyz;
protected:
/** The 'owner' of the item, i.e. the kart that dropped this item.
* Is NULL if the item is part of the track. */
* Is NULL if the item is part of the track. */
const AbstractKart *m_previous_owner;
protected:
friend class ItemManager;
friend class NetworkItemManager;
// ------------------------------------------------------------------------
virtual void setType(ItemType type) { m_type = type; }
public:
/** Constructor.
* \param type Type of the item.
* \param id Index of this item in the array of all items.
* \param kart_id If !=-1 the kart that dropped this item; -1
* indicates an item that's part of the track. */
ItemState(ItemType type, int id=-1, AbstractKart *kart=NULL)
{
setType(type);
m_item_id = id;
m_previous_owner = kart;
} // ItemState(ItemType)
ItemState(ItemType type, const AbstractKart *owner=NULL, int id = -1);
void initItem(ItemType type, const Vec3& xyz);
void update(int ticks);
void setDisappearCounter();
virtual void collected(const AbstractKart *kart);
// ------------------------------------------------------------------------
virtual ~ItemState() {}
void setDisappearCounter();
void update(int ticks);
virtual void collected(const AbstractKart *kart);
// -----------------------------------------------------------------------
void reset()
@ -166,19 +156,6 @@ public:
}
} // reset
// -----------------------------------------------------------------------
/** Initialises an item.
* \param type Type for this item.
*/
void initItem(ItemType type, const Vec3& xyz)
{
m_xyz = xyz;
m_original_type = ITEM_NONE;
m_deactive_ticks = 0;
m_ticks_till_return = 0;
setDisappearCounter();
} // initItem
// ------------------------------------------------------------------------
/** Switches an item to be of a different type. Used for the switch
* powerup.
@ -329,20 +306,19 @@ private:
public:
Item(ItemType type, const Vec3& xyz, const Vec3& normal,
scene::IMesh* mesh, scene::IMesh* lowres_mesh,
const AbstractKart *owner,
bool is_predicted=false);
Item(const Vec3& xyz, float distance,
TriggerItemListener* trigger);
virtual ~Item ();
void updateGraphics(float dt);
virtual void collected(const AbstractKart *kart) OVERRIDE;
void setParent(const AbstractKart* parent);
void reset();
void switchTo(ItemType type, scene::IMesh *mesh, scene::IMesh *lowmesh);
void switchTo(ItemType type, scene::IMesh *mesh,
scene::IMesh *lowmesh);
void switchBack();
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
/** Returns true if the Kart is close enough to hit this item, the item is
* not deactivated anymore, and it wasn't placed by this kart (this is
* e.g. used to avoid that a kart hits a bubble gum it just dropped).
@ -352,7 +328,7 @@ public:
*/
bool hitKart(const Vec3 &xyz, const AbstractKart *kart=NULL) const
{
if (m_previous_owner == kart && getDeactivatedTicks() > 0)
if (getPreviousOwner() == kart && getDeactivatedTicks() > 0)
return false;
Vec3 lc = quatRotate(m_original_rotation, xyz - getXYZ());
// Don't be too strict if the kart is a bit above the item
@ -373,7 +349,8 @@ protected:
bool hitLine(const core::line3df &line,
const AbstractKart *kart=NULL) const
{
if (m_previous_owner == kart && getDeactivatedTicks() >0) return false;
if (getPreviousOwner() == kart && getDeactivatedTicks() > 0)
return false;
Vec3 closest = line.getClosestPoint(getXYZ().toIrrVector());
return hitKart(closest, kart);

View File

@ -31,6 +31,7 @@
*/
ItemEventInfo::ItemEventInfo(BareNetworkString *buffer, int *count)
{
m_ticks_till_return = 0;
m_type = (EventType)buffer->getUInt8();
m_ticks = buffer->getTime();
m_kart_id = buffer->getInt8();
@ -41,7 +42,11 @@ ItemEventInfo::ItemEventInfo(BareNetworkString *buffer, int *count)
m_xyz = buffer->getVec3();
*count -= 12;
}
else if (m_type == IEI_COLLECT)
{
m_ticks_till_return = buffer->getUInt16();
*count -= 2;
}
} // ItemEventInfo(BareNetworkString, int *count)
//-----------------------------------------------------------------------------
@ -55,7 +60,6 @@ void ItemEventInfo::saveState(BareNetworkString *buffer)
.addUInt16(m_index);
if(m_type == IEI_NEW)
buffer->add(m_xyz);
else if (m_type == IEI_COLLECT)
buffer->addUInt16(m_ticks_till_return);
} // saveState

View File

@ -21,6 +21,7 @@
#include "items/item.hpp"
#include "utils/vec3.hpp"
#include "utils/types.hpp"
#include <assert.h>
@ -51,13 +52,20 @@ private:
/** In case of new items the position of the new item. */
Vec3 m_xyz;
/** Ticks for the item to return, atm used by collecting banana
* with bomb to delay the return for banana. */
int16_t m_ticks_till_return;
public:
/** Constructor for collecting an existing item.
* \param ticks Time of the event.
* \param item_id The index of the item that was collected.
* \param kart_id the kart that collected the item. */
ItemEventInfo(int ticks, int index, int kart_id)
: m_ticks(ticks), m_index(index), m_kart_id(kart_id)
* \param kart_id the kart that collected the item.
* \param ttr Ticks till return after being collected. */
ItemEventInfo(int ticks, int index, int kart_id, int16_t ttr)
: m_ticks(ticks), m_index(index), m_kart_id(kart_id),
m_ticks_till_return(ttr)
{
m_type = IEI_COLLECT;
} // ItemEventInfo(collected existing item)
@ -69,14 +77,15 @@ public:
*/
ItemEventInfo(int ticks, ItemState::ItemType type, int index,
int kart_id, const Vec3 &xyz)
: m_ticks(ticks), m_index(index), m_kart_id(kart_id), m_xyz(xyz)
: m_ticks(ticks), m_index(index), m_kart_id(kart_id), m_xyz(xyz),
m_ticks_till_return(0)
{
m_type = IEI_NEW;
} // ItemEventInfo(new item)
// --------------------------------------------------------------------
/** Constructor for switching items. */
ItemEventInfo(int ticks) : m_ticks(ticks)
ItemEventInfo(int ticks) : m_ticks(ticks), m_ticks_till_return(0)
{
m_type = IEI_SWITCH;
} // ItemEventInfo(switch)
@ -116,6 +125,9 @@ public:
return m_xyz;
} // getXYZ
// --------------------------------------------------------------------
/** Returns the ticks till return, used only by collection events. */
int getTicksTillReturn() const { return m_ticks_till_return; }
// --------------------------------------------------------------------
/** Returns the type of this item. Note at this stage only bubble gums
* can be created during a race. */
ItemState::ItemType getNewItemType() const

View File

@ -226,13 +226,15 @@ unsigned int ItemManager::insertItem(Item *item)
// previously deleted entry, otherwise at the end.
int index = -1;
for(index=(int)m_all_items.size()-1; index>=0 && m_all_items[index]; index--) {}
if(index==-1) index = (int)m_all_items.size();
if(index<(int)m_all_items.size())
m_all_items[index] = item;
else
if (index == -1)
{
index = (int)m_all_items.size();
m_all_items.push_back(item);
}
else
{
m_all_items[index] = item;
}
item->setItemId(index);
// Now insert into the appropriate quad list, if there is a quad list
@ -286,9 +288,7 @@ Item* ItemManager::dropNewItem(ItemState::ItemType type,
}
Item* item = new Item(type, pos, normal, m_item_mesh[mesh_type],
m_item_lowres_mesh[mesh_type]);
if(kart != NULL) item->setParent(kart);
m_item_lowres_mesh[mesh_type], /*prev_owner*/kart);
insertItem(item);
if(m_switch_ticks>=0)
{
@ -318,7 +318,7 @@ Item* ItemManager::placeItem(ItemState::ItemType type, const Vec3& xyz,
ItemState::ItemType mesh_type = type;
Item* item = new Item(type, xyz, normal, m_item_mesh[mesh_type],
m_item_lowres_mesh[mesh_type]);
m_item_lowres_mesh[mesh_type], /*prev_owner*/NULL);
insertItem(item);
if (m_switch_ticks >= 0)
@ -354,7 +354,7 @@ Item* ItemManager::placeTrigger(const Vec3& xyz, float distance,
* \param item The item that was collected.
* \param kart The kart that collected the item.
*/
void ItemManager::collectedItem(Item *item, AbstractKart *kart)
void ItemManager::collectedItem(ItemState *item, AbstractKart *kart)
{
assert(item);
// Spare tire karts don't collect items

View File

@ -133,7 +133,7 @@ public:
void updateGraphics (float dt);
void checkItemHit (AbstractKart* kart);
void reset ();
virtual void collectedItem (Item *item, AbstractKart *kart);
virtual void collectedItem (ItemState *item, AbstractKart *kart);
void switchItems ();
bool areItemSwitched() { return (m_switch_ticks > 0); }
bool randomItemsForArena(const AlignedArray<btTransform>& pos);

View File

@ -95,17 +95,18 @@ void NetworkItemManager::initClientConfirmState()
* \param item The item that was collected.
* \param kart The kart that collected the item.
*/
void NetworkItemManager::collectedItem(Item *item, AbstractKart *kart)
void NetworkItemManager::collectedItem(ItemState *item, AbstractKart *kart)
{
if(NetworkConfig::get()->isServer())
{
ItemManager::collectedItem(item, kart);
// The server saves the collected item as item event info
m_item_events.lock();
m_item_events.getData().emplace_back(World::getWorld()->getTicksSinceStart(),
item->getItemId(),
kart->getWorldKartId());
item->getItemId(),
kart->getWorldKartId(),
item->getTicksTillReturn());
m_item_events.unlock();
ItemManager::collectedItem(item, kart);
}
else
{
@ -142,7 +143,7 @@ Item* NetworkItemManager::dropNewItem(ItemState::ItemType type,
kart->getXYZ() );
m_item_events.unlock();
return item;
} // newItem
} // dropNewItem
// ----------------------------------------------------------------------------
/** Called by the GameProtocol when a confirmation for an item event is
@ -237,9 +238,9 @@ void NetworkItemManager::forwardTime(int ticks)
//-----------------------------------------------------------------------------
/** Restores the state of the items to the current world time. It takes the
* last saved
* using exactly 'count' bytes of the message.
* last saved confirmed state, applies any updates from the server, and
* then syncs up the confirmed state to the in-race items.
* It uses exactly 'count' bytes of the message.
* \param buffer the state content.
* \param count Number of bytes used for this state.
*/
@ -267,6 +268,7 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
// From here the replay can happen.
// 1) Remove predicted items:
// --------------------------
for (unsigned int i=0; i<m_all_items.size(); i++)
{
Item *item = m_all_items[i];
@ -274,20 +276,22 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
{
deleteItem(item);
}
}
} // for i in m_all_items
// 2) Apply all events to current confirmed state:
// -----------------------------------------------
World *world = World::getWorld();
int current_time = m_confirmed_state_time;
bool has_state = count > 0;
while(count > 0)
{
// 1) Decode the event in the message
// ----------------------------------
// 2.1) Decode the event in the message
// ------------------------------------
ItemEventInfo iei(buffer, &count);
// 2) If the event needs to be applied, forward
// the time to the time of this event:
// --------------------------------------------
// 2.2) If the event needs to be applied, forward
// the time to the time of this event:
// ----------------------------------------------
int dt = iei.getTicks() - current_time;
// Skip an event that are 'in the past' (i.e. have been sent again by
// the server because it has not yet received confirmation from all
@ -297,13 +301,35 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
// Forward the saved state:
if (dt>0) forwardTime(dt);
// TODO: apply the various events types, atm only collection is supported:
// TODO: apply the various events types, atm only collection
// and new items are supported.
if(iei.isItemCollection())
{
int index = iei.getIndex();
// An item on the track was collected:
AbstractKart *kart = World::getWorld()->getKart(iei.getKartId());
m_confirmed_state[index]->collected(kart);
AbstractKart *kart = world->getKart(iei.getKartId());
// The world clock was set by the RewindManager to be the time
// of the state we are rewinding to. But this confirmed collection
// event happened in the past (we are replaying item events since
// the last confirmed state in order to get a new confirmed state).
// So we need to reset the clock to the time at which this event
// happened so that (e.g.) kart can use the right time (for
// example, bubble gum torque depends on time, and would be wrong
// otherwise resulting in stuttering).
int old_time = world->getTicksSinceStart(); // Save time we rewind to
world->setTicksForRewind(iei.getTicks()); // Set time of event
if (m_confirmed_state[index] != NULL)
{
m_confirmed_state[index]->collected(kart);// Collect item
// Reset till ticks return from state (required for eating banana with bomb)
int ttr = iei.getTicksTillReturn();
m_confirmed_state[index]->setTicksTillReturn(ttr);
}
world->setTicksForRewind(old_time); // Set time to rewind-to
if (m_confirmed_state[index]->isUsedUp())
{
delete m_confirmed_state[index];
@ -312,9 +338,9 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
}
else if(iei.isNewItem())
{
AbstractKart *kart = World::getWorld()->getKart(iei.getKartId());
ItemState *is = new ItemState(iei.getNewItemType(), iei.getIndex(),
kart);
AbstractKart *kart = world->getKart(iei.getKartId());
ItemState *is = new ItemState(iei.getNewItemType(), kart,
iei.getIndex() );
is->initItem(iei.getNewItemType(), iei.getXYZ());
if (m_confirmed_state.size() <= is->getItemId())
{
@ -325,29 +351,34 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
if (m_confirmed_state[is->getItemId()] == NULL)
m_confirmed_state[is->getItemId()] = is;
else
{
*m_confirmed_state[is->getItemId()] = *is;
delete is;
}
}
}
current_time = iei.getTicks();
} // while count >0
// Inform the server which events have been received.
// Inform the server which events have been received (if there has
// been any updates - no need to send messages if nothing has changed)
if (has_state)
{
if (auto gp = GameProtocol::lock())
gp->sendItemEventConfirmation(World::getWorld()->getTicksSinceStart());
gp->sendItemEventConfirmation(world->getTicksSinceStart());
}
// Forward the confirmed item state to the world time:
int dt = World::getWorld()->getTicksSinceStart() - current_time;
int dt = world->getTicksSinceStart() - current_time;
if(dt>0) forwardTime(dt);
// Restore the state to the current world time:
// ============================================
// 3. Restore the state to the current world time:
// ===============================================
for(unsigned int i=0; i<m_confirmed_state.size(); i++)
{
Item *item = m_all_items[i];
Item *item = i < m_all_items.size() ? m_all_items[i] : NULL;
const ItemState *is = m_confirmed_state[i];
if (is && item)
*(ItemState*)item = *is;
@ -356,18 +387,33 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
Vec3 xyz = is->getXYZ();
Item *item_new = dropNewItem(is->getType(), is->getPreviousOwner(),
&xyz);
if (i != item_new->getItemId())
{
// The server has this item at a different index in the list
// of all items, which means the client has an incorrect
// item at the index given by the server - delete that item
Log::info("nim", "about to delete item with not matching index i %d item %d",
i, item_new->getItemId());
if(m_all_items[i])
deleteItem(m_all_items[i]);
m_all_items[item_new->getItemId()] = NULL;
m_all_items[i] = item_new;
item_new->setItemId(i);
}
item_new->setPredicted(false);
item_new->setItemId(i);
m_all_items[i] = item_new;
item_new->setDeactivatedTicks(is->getDeactivatedTicks());
*((ItemState*)m_all_items[i]) = *is;
}
else if (!is && item)
{
Log::info("nim", "About to delete item index %d i %d",
item->getItemId(), i);
deleteItem(m_all_items[i]);
}
}
// Now we save the current local
m_confirmed_state_time = World::getWorld()->getTicksSinceStart();
m_confirmed_state_time = world->getTicksSinceStart();
} // restoreState

View File

@ -73,7 +73,7 @@ public:
virtual void reset() OVERRIDE;
virtual void setItemConfirmationTime(std::weak_ptr<STKPeer> peer,
int ticks) OVERRIDE;
virtual void collectedItem(Item *item, AbstractKart *kart) OVERRIDE;
virtual void collectedItem(ItemState *item, AbstractKart *kart) OVERRIDE;
virtual Item* dropNewItem(ItemState::ItemType type, const AbstractKart *kart,
const Vec3 *xyz=NULL) OVERRIDE;
virtual BareNetworkString* saveState(std::vector<std::string>* ru)

View File

@ -256,7 +256,7 @@ BareNetworkString* Plunger::saveState(std::vector<std::string>* ru)
BareNetworkString* buffer = Flyable::saveState(ru);
buffer->addUInt16(m_keep_alive).addUInt8(m_moved_to_infinity ? 1 : 0);
if (m_rubber_band)
buffer->addUInt8(m_rubber_band->getRubberBandTo());
buffer->addUInt8(m_rubber_band->get8BitState());
else
buffer->addUInt8(255);
return buffer;
@ -268,7 +268,20 @@ void Plunger::restoreState(BareNetworkString *buffer, int count)
Flyable::restoreState(buffer, count);
m_keep_alive = buffer->getUInt16();
m_moved_to_infinity = buffer->getUInt8() == 1;
int8_t rbt = buffer->getUInt8();
if (rbt != -1 && m_rubber_band)
m_rubber_band->setRubberBandTo((RubberBand::RubberBandTo)rbt);
uint8_t bit_state = buffer->getUInt8();
if (bit_state == 255 && m_rubber_band)
{
delete m_rubber_band;
m_rubber_band = NULL;
if (!m_reverse_mode)
m_reverse_mode = true;
}
else if (bit_state != 255 && !m_rubber_band)
{
m_rubber_band = new RubberBand(this, m_owner);
if (m_reverse_mode)
m_reverse_mode = false;
}
if (bit_state != 255)
m_rubber_band->set8BitState(bit_state);
} // restoreState

View File

@ -563,7 +563,7 @@ void Powerup::hitBonusBox(const ItemState &item_state)
random_number);
// FIXME Disable switch and bubblegum for now in network
if (NetworkConfig::get()->isNetworking() &&
(new_powerup == PowerupManager::POWERUP_BUBBLEGUM ||
(new_powerup == PowerupManager::POWERUP_BUBBLEGUM ||
new_powerup == PowerupManager::POWERUP_SWITCH))
new_powerup = PowerupManager::POWERUP_BOWLING;

View File

@ -314,3 +314,4 @@ std::shared_ptr<Rewinder>
return nullptr;
}
} // addProjectileFromNetworkState

View File

@ -101,3 +101,4 @@ extern ProjectileManager *projectile_manager;
#endif
/* EOF */

View File

@ -45,6 +45,7 @@
RubberBand::RubberBand(Plunger *plunger, AbstractKart *kart)
: m_plunger(plunger), m_owner(kart)
{
m_hit_kart = NULL;
m_attached_state = RB_TO_PLUNGER;
updatePosition();
@ -276,6 +277,7 @@ void RubberBand::hit(AbstractKart *kart_hit, const Vec3 *track_xyz)
// =================
m_hit_position = *track_xyz;
m_attached_state = RB_TO_TRACK;
m_hit_kart = NULL;
} // hit
// ----------------------------------------------------------------------------
@ -289,3 +291,24 @@ void RubberBand::remove()
}
#endif
} // remove
// ----------------------------------------------------------------------------
uint8_t RubberBand::get8BitState() const
{
uint8_t state = (uint8_t)(m_attached_state & 3);
state |= m_attached_state == RB_TO_KART && m_hit_kart ?
(m_hit_kart->getWorldKartId() << 3) : 0;
return state;
} // get8BitState
// ----------------------------------------------------------------------------
void RubberBand::set8BitState(uint8_t bit_state)
{
m_hit_kart = NULL;
m_attached_state = (RubberBandTo)(bit_state & 3);
if (m_attached_state == RB_TO_KART)
{
unsigned kart = bit_state >> 3;
m_hit_kart = World::getWorld()->getKart(kart);
}
} // set8BitState

View File

@ -73,8 +73,8 @@ public:
void updateGraphics(float dt);
void update(int ticks);
void hit(AbstractKart *kart_hit, const Vec3 *track_xyz=NULL);
RubberBandTo getRubberBandTo() const { return m_attached_state; }
void setRubberBandTo(RubberBandTo rbt) { m_attached_state = rbt; }
uint8_t get8BitState() const;
void set8BitState(uint8_t bit_state);
void remove();
}; // RubberBand
#endif

View File

@ -161,20 +161,20 @@ void Swatter::updateGrahpics(float dt)
/** Updates an armed swatter: it checks for any karts that are close enough
* and not invulnerable, it swats the kart.
* \param dt Time step size.
* \return True if the attachment should be discarded.
* \return World ticks to discard the swatter.
*/
bool Swatter::updateAndTestFinished(int ticks)
int Swatter::updateAndTestFinished(int ticks)
{
const int ticks_start = World::getWorld()->getTicksSinceStart();
if (m_removed_bomb_ticks != std::numeric_limits<int>::max())
{
if (ticks_start >= m_removed_bomb_ticks)
return true;
return false;
return m_removed_bomb_ticks;
return -1;
} // if removing bomb
if (RewindManager::get()->isRewinding())
return false;
return -1;
if (!m_discard_now)
{
@ -186,7 +186,7 @@ bool Swatter::updateAndTestFinished(int ticks)
// to make sure all clients know the existence of swatter each other
if (ticks_start - m_swatter_start_ticks < 60 ||
m_swatter_end_ticks - ticks_start < 60)
return false;
return -1;
chooseTarget();
poi