Fix crash in case of multiple item collection and different

item ids on client and server.
This commit is contained in:
hiker 2018-09-13 11:29:40 +10:00
parent 9211b26251
commit 1291d2c0d3
7 changed files with 42 additions and 23 deletions

View File

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

View File

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

View File

@ -95,7 +95,7 @@ void NetworkItemManager::initClientConfirmState()
* \param item The item that was collected. * \param item The item that was collected.
* \param kart The kart that collected the item. * \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()) if(NetworkConfig::get()->isServer())
{ {
@ -142,7 +142,7 @@ Item* NetworkItemManager::dropNewItem(ItemState::ItemType type,
kart->getXYZ() ); kart->getXYZ() );
m_item_events.unlock(); m_item_events.unlock();
return item; return item;
} // newItem } // dropNewItem
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Called by the GameProtocol when a confirmation for an item event is /** Called by the GameProtocol when a confirmation for an item event is
@ -237,9 +237,9 @@ void NetworkItemManager::forwardTime(int ticks)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Restores the state of the items to the current world time. It takes the /** Restores the state of the items to the current world time. It takes the
* last saved * last saved confirmed state, applies any updates from the server, and
* then syncs up the confirmed state to the in-race items.
* using exactly 'count' bytes of the message. * It uses exactly 'count' bytes of the message.
* \param buffer the state content. * \param buffer the state content.
* \param count Number of bytes used for this state. * \param count Number of bytes used for this state.
*/ */
@ -299,13 +299,14 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
// Forward the saved state: // Forward the saved state:
if (dt>0) forwardTime(dt); 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()) if(iei.isItemCollection())
{ {
int index = iei.getIndex(); int index = iei.getIndex();
// An item on the track was collected: // An item on the track was collected:
AbstractKart *kart = World::getWorld()->getKart(iei.getKartId()); AbstractKart *kart = World::getWorld()->getKart(iei.getKartId());
m_confirmed_state[index]->collected(kart); collectedItem(m_confirmed_state[index], kart);
if (m_confirmed_state[index]->isUsedUp()) if (m_confirmed_state[index]->isUsedUp())
{ {
delete m_confirmed_state[index]; delete m_confirmed_state[index];
@ -327,7 +328,10 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
if (m_confirmed_state[is->getItemId()] == NULL) if (m_confirmed_state[is->getItemId()] == NULL)
m_confirmed_state[is->getItemId()] = is; m_confirmed_state[is->getItemId()] = is;
else else
{
*m_confirmed_state[is->getItemId()] = *is; *m_confirmed_state[is->getItemId()] = *is;
delete is;
}
} }
} }
current_time = iei.getTicks(); current_time = iei.getTicks();
@ -351,7 +355,7 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
for(unsigned int i=0; i<m_confirmed_state.size(); i++) 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]; const ItemState *is = m_confirmed_state[i];
if (is && item) if (is && item)
*(ItemState*)item = *is; *(ItemState*)item = *is;
@ -360,10 +364,21 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
Vec3 xyz = is->getXYZ(); Vec3 xyz = is->getXYZ();
Item *item_new = dropNewItem(is->getType(), is->getPreviousOwner(), Item *item_new = dropNewItem(is->getType(), is->getPreviousOwner(),
&xyz); &xyz);
item_new->setPredicted(false); if (i != item_new->getItemId())
item_new->setItemId(i); {
item_new->setDeactivatedTicks(is->getDeactivatedTicks()); // 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; m_all_items[i] = item_new;
item_new->setItemId(i);
}
item_new->setPredicted(false);
item_new->setDeactivatedTicks(is->getDeactivatedTicks());
*((ItemState*)m_all_items[i]) = *is; *((ItemState*)m_all_items[i]) = *is;
} }
else if (!is && item) else if (!is && item)

View File

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

View File

@ -159,7 +159,8 @@ const std::string& EasterEggHunt::getIdent() const
/** Called when a kart has collected an egg. /** Called when a kart has collected an egg.
* \param kart The kart that collected an egg. * \param kart The kart that collected an egg.
*/ */
void EasterEggHunt::collectedItem(const AbstractKart *kart, const Item *item) void EasterEggHunt::collectedItem(const AbstractKart *kart,
const ItemState *item )
{ {
if(item->getType() != ItemState::ITEM_EASTER_EGG) return; if(item->getType() != ItemState::ITEM_EASTER_EGG) return;

View File

@ -66,7 +66,7 @@ public:
virtual void getKartsDisplayInfo( virtual void getKartsDisplayInfo(
std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE; std::vector<RaceGUIBase::KartIconDisplayInfo> *info) OVERRIDE;
virtual void collectedItem(const AbstractKart *kart, virtual void collectedItem(const AbstractKart *kart,
const Item *item ) OVERRIDE; const ItemState *item ) OVERRIDE;
void collectedEasterEggGhost(int world_id); void collectedEasterEggGhost(int world_id);
const int numberOfEggsFound() { return m_eggs_found; } const int numberOfEggsFound() { return m_eggs_found; }

View File

@ -42,7 +42,7 @@
class AbstractKart; class AbstractKart;
class btRigidBody; class btRigidBody;
class Controller; class Controller;
class Item; class ItemState;
class PhysicalObject; class PhysicalObject;
namespace Scripting namespace Scripting
@ -263,7 +263,8 @@ public:
int *amount ); int *amount );
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Receives notification if an item is collected. Used for easter eggs. */ /** Receives notification if an item is collected. Used for easter eggs. */
virtual void collectedItem(const AbstractKart *kart, const Item *item) {} virtual void collectedItem(const AbstractKart *kart,
const ItemState *item ) {}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual void endRaceEarly() { return; } virtual void endRaceEarly() { return; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------