From 5955166931e819f7b77b913ce337701e03657766 Mon Sep 17 00:00:00 2001 From: hiker Date: Mon, 3 Sep 2018 18:21:03 +1000 Subject: [PATCH 1/9] Try to fix that a client collects its own bubble gum in case of a rewind. --- src/items/item.cpp | 23 +++++++++++------------ src/items/item.hpp | 5 ++--- src/items/item_manager.cpp | 6 ++---- src/items/network_item_manager.cpp | 23 ++++++++++++++--------- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/items/item.cpp b/src/items/item.cpp index c7fc73ebe..615de4778 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -107,11 +107,16 @@ 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) + scene::IMesh* mesh, scene::IMesh* lowres_mesh, + const AbstractKart *owner, bool is_predicted) : ItemState(type) { assert(type != ITEM_TRIGGER); // use other constructor for that @@ -158,6 +163,11 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal, hpr.setHPR(m_original_rotation); m_node->setRotation(hpr.toIrrHPR()); m_node->grab(); + if (owner) + { + m_previous_owner = owner; + ItemState::setDeactivatedTicks(stk_config->time2Ticks(1.5f)); + } } // Item(type, xyz, normal, mesh, lowres_mesh) //----------------------------------------------------------------------------- @@ -320,17 +330,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. diff --git a/src/items/item.hpp b/src/items/item.hpp index 326a831c8..93899e6d1 100644 --- a/src/items/item.hpp +++ b/src/items/item.hpp @@ -138,7 +138,7 @@ public: * \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) + ItemState(ItemType type, int id=-1, const AbstractKart *kart=NULL) { setType(type); m_item_id = id; @@ -150,7 +150,6 @@ public: void setDisappearCounter(); void update(int ticks); virtual void collected(const AbstractKart *kart); - // ----------------------------------------------------------------------- void reset() @@ -326,13 +325,13 @@ 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 switchBack(); diff --git a/src/items/item_manager.cpp b/src/items/item_manager.cpp index 14e675e90..3ecccca20 100644 --- a/src/items/item_manager.cpp +++ b/src/items/item_manager.cpp @@ -286,9 +286,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 +316,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) diff --git a/src/items/network_item_manager.cpp b/src/items/network_item_manager.cpp index 383a2a73c..b6e00a6a7 100644 --- a/src/items/network_item_manager.cpp +++ b/src/items/network_item_manager.cpp @@ -267,6 +267,7 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) // From here the replay can happen. // 1) Remove predicted items: + // -------------------------- for (unsigned int i=0; i 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 @@ -331,7 +333,9 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) 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()) @@ -342,8 +346,8 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) int dt = World::getWorld()->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; isetPredicted(false); item_new->setItemId(i); + item_new->setDeactivatedTicks(is->getDeactivatedTicks()); m_all_items[i] = item_new; *((ItemState*)m_all_items[i]) = *is; } From 9211b262510328946e72c5d941e2375357182044 Mon Sep 17 00:00:00 2001 From: hiker Date: Tue, 4 Sep 2018 18:32:10 +1000 Subject: [PATCH 2/9] Fixed bubble gum collection in networking (at least the problem that you would on the client collect the gum you just dropped). --- src/items/item.cpp | 40 +++++++++++++++++++----- src/items/item.hpp | 50 +++++++++--------------------- src/items/network_item_manager.cpp | 8 ++--- src/items/powerup.cpp | 5 --- 4 files changed, 50 insertions(+), 53 deletions(-) diff --git a/src/items/item.cpp b/src/items/item.cpp index 615de4778..21558bc05 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -37,6 +37,22 @@ #include +// ---------------------------------------------------------------------------- +/** 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; + if (owner) + setDeactivatedTicks(stk_config->time2Ticks(1.5f)); +} // ItemState(ItemType) + // ------------------------------------------------------------------------ /** Sets the disappear counter depending on type. */ void ItemState::setDisappearCounter() @@ -52,9 +68,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) { @@ -117,7 +147,7 @@ void ItemState::collected(const AbstractKart *kart) Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal, scene::IMesh* mesh, scene::IMesh* lowres_mesh, const AbstractKart *owner, bool is_predicted) - : ItemState(type) + : ItemState(type, owner) { assert(type != ITEM_TRIGGER); // use other constructor for that @@ -163,11 +193,6 @@ Item::Item(ItemType type, const Vec3& xyz, const Vec3& normal, hpr.setHPR(m_original_rotation); m_node->setRotation(hpr.toIrrHPR()); m_node->grab(); - if (owner) - { - m_previous_owner = owner; - ItemState::setDeactivatedTicks(stk_config->time2Ticks(1.5f)); - } } // Item(type, xyz, normal, mesh, lowres_mesh) //----------------------------------------------------------------------------- @@ -198,7 +223,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 diff --git a/src/items/item.hpp b/src/items/item.hpp index 93899e6d1..4678eca44 100644 --- a/src/items/item.hpp +++ b/src/items/item.hpp @@ -122,34 +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; // ------------------------------------------------------------------------ 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, const 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() @@ -165,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. @@ -333,12 +311,11 @@ public: void updateGraphics(float dt); virtual void collected(const AbstractKart *kart) OVERRIDE; 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). @@ -348,7 +325,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 @@ -369,7 +346,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); diff --git a/src/items/network_item_manager.cpp b/src/items/network_item_manager.cpp index b6e00a6a7..cc643818d 100644 --- a/src/items/network_item_manager.cpp +++ b/src/items/network_item_manager.cpp @@ -102,8 +102,8 @@ void NetworkItemManager::collectedItem(Item *item, AbstractKart *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() ); m_item_events.unlock(); ItemManager::collectedItem(item, kart); } @@ -315,8 +315,8 @@ 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); + ItemState *is = new ItemState(iei.getNewItemType(), kart, + iei.getIndex() ); is->initItem(iei.getNewItemType(), iei.getXYZ()); if (m_confirmed_state.size() <= is->getItemId()) { diff --git a/src/items/powerup.cpp b/src/items/powerup.cpp index 48d47e7c6..4c72bccfd 100644 --- a/src/items/powerup.cpp +++ b/src/items/powerup.cpp @@ -560,11 +560,6 @@ void Powerup::hitBonusBox(const ItemState &item_state) new_powerup = powerup_manager->getRandomPowerup(position, &n, random_number); - // FIXME Disable switch and bubblegum for now in network - if (NetworkConfig::get()->isNetworking() && - (new_powerup == PowerupManager::POWERUP_BUBBLEGUM || - new_powerup == PowerupManager::POWERUP_SWITCH)) - new_powerup = PowerupManager::POWERUP_BOWLING; // Always add a new powerup in ITEM_MODE_NEW (or if the kart // doesn't have a powerup atm). From 1291d2c0d31ff429eedb793301932173c703fdfb Mon Sep 17 00:00:00 2001 From: hiker Date: Thu, 13 Sep 2018 11:29:40 +1000 Subject: [PATCH 3/9] Fix crash in case of multiple item collection and different item ids on client and server. --- src/items/item_manager.cpp | 16 ++++++++------ src/items/item_manager.hpp | 2 +- src/items/network_item_manager.cpp | 35 +++++++++++++++++++++--------- src/items/network_item_manager.hpp | 2 +- src/modes/easter_egg_hunt.cpp | 3 ++- src/modes/easter_egg_hunt.hpp | 2 +- src/modes/world.hpp | 5 +++-- 7 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/items/item_manager.cpp b/src/items/item_manager.cpp index 3ecccca20..0e25687a6 100644 --- a/src/items/item_manager.cpp +++ b/src/items/item_manager.cpp @@ -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 @@ -352,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 diff --git a/src/items/item_manager.hpp b/src/items/item_manager.hpp index 83f5f9a9e..26614eebf 100644 --- a/src/items/item_manager.hpp +++ b/src/items/item_manager.hpp @@ -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 randomItemsForArena(const AlignedArray& pos); // ------------------------------------------------------------------------ diff --git a/src/items/network_item_manager.cpp b/src/items/network_item_manager.cpp index cc643818d..abb4cd480 100644 --- a/src/items/network_item_manager.cpp +++ b/src/items/network_item_manager.cpp @@ -95,7 +95,7 @@ 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()) { @@ -142,7 +142,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 +237,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. */ @@ -299,13 +299,14 @@ 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); + collectedItem(m_confirmed_state[index], kart); if (m_confirmed_state[index]->isUsedUp()) { delete m_confirmed_state[index]; @@ -327,7 +328,10 @@ 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(); @@ -351,7 +355,7 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) for(unsigned int i=0; igetXYZ(); 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); item_new->setDeactivatedTicks(is->getDeactivatedTicks()); - m_all_items[i] = item_new; *((ItemState*)m_all_items[i]) = *is; } else if (!is && item) diff --git a/src/items/network_item_manager.hpp b/src/items/network_item_manager.hpp index 1e1d93ff9..4b2befbc0 100644 --- a/src/items/network_item_manager.hpp +++ b/src/items/network_item_manager.hpp @@ -73,7 +73,7 @@ public: virtual void reset() OVERRIDE; virtual void setItemConfirmationTime(std::weak_ptr 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* ru) diff --git a/src/modes/easter_egg_hunt.cpp b/src/modes/easter_egg_hunt.cpp index ec74d98ca..d578164c3 100644 --- a/src/modes/easter_egg_hunt.cpp +++ b/src/modes/easter_egg_hunt.cpp @@ -159,7 +159,8 @@ const std::string& EasterEggHunt::getIdent() const /** Called when a kart has 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; diff --git a/src/modes/easter_egg_hunt.hpp b/src/modes/easter_egg_hunt.hpp index ba5e5eaf9..9a16275ee 100644 --- a/src/modes/easter_egg_hunt.hpp +++ b/src/modes/easter_egg_hunt.hpp @@ -66,7 +66,7 @@ public: virtual void getKartsDisplayInfo( std::vector *info) OVERRIDE; virtual void collectedItem(const AbstractKart *kart, - const Item *item ) OVERRIDE; + const ItemState *item ) OVERRIDE; void collectedEasterEggGhost(int world_id); const int numberOfEggsFound() { return m_eggs_found; } diff --git a/src/modes/world.hpp b/src/modes/world.hpp index 2737d541b..1a25567eb 100644 --- a/src/modes/world.hpp +++ b/src/modes/world.hpp @@ -42,7 +42,7 @@ class AbstractKart; class btRigidBody; class Controller; -class Item; +class ItemState; class PhysicalObject; namespace Scripting @@ -263,7 +263,8 @@ public: int *amount ); // ------------------------------------------------------------------------ /** 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; } // ------------------------------------------------------------------------ From 23acbf526003a43609153f9a9119f64bb7df8bdb Mon Sep 17 00:00:00 2001 From: hiker Date: Mon, 17 Sep 2018 18:19:23 +1000 Subject: [PATCH 4/9] Fixed shaking after collecting bubble gum (caused by restoring item state after restorint kart state - during item state restoration items can be 'collected', which overwrites kart states values that just had been restored). --- src/karts/kart.cpp | 6 +++--- src/network/rewind_manager.cpp | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index cacdbbe84..47bf3bc8e 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -1488,7 +1488,7 @@ void Kart::update(int ticks) "v(16-18) %f %f %f steerf(20) %f maxangle(22) %f speed(24) %f " "steering(26-27) %f %f clock(29) %lf skidstate(31) %d factor(33) %f " "maxspeed(35) %f engf(37) %f braketick(39) %d brakes(41) %d heading(43) %f " - "noderot(45) %f suslen %f", + "bubticks(45) %d bubtor(47) %f", getIdent().c_str(), World::getWorld()->getTime(), World::getWorld()->getTicksSinceStart(), getXYZ().getX(), getXYZ().getY(), getXYZ().getZ(), @@ -1509,8 +1509,8 @@ void Kart::update(int ticks) m_brake_ticks, //39 m_controls.getButtonsCompressed(), //41 getHeading(), //43 - m_node->getAbsoluteTransformation().getRotationDegrees().Y, //45 - m_vehicle->getWheelInfo(0).m_raycastInfo.m_suspensionLength + m_bubblegum_ticks, // 45 + m_bubblegum_torque // 47 ); #endif // After the physics step was done, the position of the wheels (as stored diff --git a/src/network/rewind_manager.cpp b/src/network/rewind_manager.cpp index 087345cc1..d88dd0e08 100644 --- a/src/network/rewind_manager.cpp +++ b/src/network/rewind_manager.cpp @@ -154,8 +154,27 @@ void RewindManager::saveState() m_overall_state_size = 0; std::vector rewinder_using; + + // We must save the item state first (so that it is restored first), + // otherwise state updates for a kart could be overwritten by + // e.g. simulating the item collection later (which resets bubblegum + // counter). + BareNetworkString* buffer = NULL; + if(auto r = m_all_rewinder["N"].lock()) + buffer = r->saveState(&rewinder_using); + if (buffer) + { + m_overall_state_size += buffer->size(); + gp->addState(buffer); + } + delete buffer; // buffer can be freed + for (auto& p : m_all_rewinder) { + // The Network ItemManager was saved first before this loop, + // so skip it here. + if(p.first=="N") continue; + // TODO: check if it's worth passing in a sufficiently large buffer from // GameProtocol - this would save the copy operation. BareNetworkString* buffer = NULL; From 7cabefc8e9033eb8406ee34520eb4dd9a257dfc5 Mon Sep 17 00:00:00 2001 From: hiker Date: Thu, 20 Sep 2018 19:30:52 +1000 Subject: [PATCH 5/9] Fixed incorrect bubble gum rotation prediction (because wrong time was used when rewinding). --- src/items/network_item_manager.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/items/network_item_manager.cpp b/src/items/network_item_manager.cpp index cefbb1ef3..a6ed824e3 100644 --- a/src/items/network_item_manager.cpp +++ b/src/items/network_item_manager.cpp @@ -279,6 +279,7 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) // 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) @@ -305,8 +306,21 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) { int index = iei.getIndex(); // An item on the track was collected: - AbstractKart *kart = World::getWorld()->getKart(iei.getKartId()); - collectedItem(m_confirmed_state[index], 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->setTicks(iei.getTicks()); // Set time of event + collectedItem(m_confirmed_state[index], kart);// Collect item + world->setTicks(old_time); // Set time to rewind-to + if (m_confirmed_state[index]->isUsedUp()) { delete m_confirmed_state[index]; @@ -315,7 +329,7 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) } else if(iei.isNewItem()) { - AbstractKart *kart = World::getWorld()->getKart(iei.getKartId()); + AbstractKart *kart = world->getKart(iei.getKartId()); ItemState *is = new ItemState(iei.getNewItemType(), kart, iei.getIndex() ); is->initItem(iei.getNewItemType(), iei.getXYZ()); @@ -343,11 +357,11 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) 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); // 3. Restore the state to the current world time: @@ -383,11 +397,14 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) } 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 From 2f2a128e06716327c7483333b59c347509413eff Mon Sep 17 00:00:00 2001 From: Benau Date: Fri, 21 Sep 2018 16:12:04 +0800 Subject: [PATCH 6/9] Fix missing initialized values --- src/items/item.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/items/item.cpp b/src/items/item.cpp index c0b375d53..ad68f7bbb 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -49,8 +49,11 @@ ItemState::ItemState(ItemType type, const AbstractKart *owner, int id) setType(type); m_item_id = id; m_previous_owner = owner; - if (owner) - setDeactivatedTicks(stk_config->time2Ticks(1.5f)); + m_used_up_counter = -1; + if (owner) + setDeactivatedTicks(stk_config->time2Ticks(1.5f)); + else + setDeactivatedTicks(0); } // ItemState(ItemType) // ------------------------------------------------------------------------ From aa2d94481322847ba62b6b77b8bb463bd303d86c Mon Sep 17 00:00:00 2001 From: Benau Date: Fri, 21 Sep 2018 16:13:19 +0800 Subject: [PATCH 7/9] Use setTicksForRewind for count down game timer --- src/items/network_item_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/items/network_item_manager.cpp b/src/items/network_item_manager.cpp index a6ed824e3..76eb030ba 100644 --- a/src/items/network_item_manager.cpp +++ b/src/items/network_item_manager.cpp @@ -317,9 +317,9 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) // 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->setTicks(iei.getTicks()); // Set time of event + world->setTicksForRewind(iei.getTicks()); // Set time of event collectedItem(m_confirmed_state[index], kart);// Collect item - world->setTicks(old_time); // Set time to rewind-to + world->setTicksForRewind(old_time); // Set time to rewind-to if (m_confirmed_state[index]->isUsedUp()) { From b1a535b21ffdcdda7b38498fb2e2075bb21da9c5 Mon Sep 17 00:00:00 2001 From: Benau Date: Fri, 21 Sep 2018 20:06:47 +0800 Subject: [PATCH 8/9] Save ticks till return for eating banana with bomb --- src/items/item_event_info.cpp | 12 ++++++++---- src/items/item_event_info.hpp | 21 ++++++++++++++++----- src/items/network_item_manager.cpp | 10 ++++++++-- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/items/item_event_info.cpp b/src/items/item_event_info.cpp index f9d97ea49..6acb38d5b 100644 --- a/src/items/item_event_info.cpp +++ b/src/items/item_event_info.cpp @@ -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 - - - \ No newline at end of file diff --git a/src/items/item_event_info.hpp b/src/items/item_event_info.hpp index 35499baf2..ddb246922 100644 --- a/src/items/item_event_info.hpp +++ b/src/items/item_event_info.hpp @@ -51,13 +51,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 +76,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 +124,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 diff --git a/src/items/network_item_manager.cpp b/src/items/network_item_manager.cpp index 76eb030ba..b77cce037 100644 --- a/src/items/network_item_manager.cpp +++ b/src/items/network_item_manager.cpp @@ -99,13 +99,14 @@ 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() ); + kart->getWorldKartId(), + item->getTicksTillReturn()); m_item_events.unlock(); - ItemManager::collectedItem(item, kart); } else { @@ -319,6 +320,11 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) int old_time = world->getTicksSinceStart(); // Save time we rewind to world->setTicksForRewind(iei.getTicks()); // Set time of event collectedItem(m_confirmed_state[index], 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()) From 553747237e052ff0b9c968ae8a8538b3423f0261 Mon Sep 17 00:00:00 2001 From: Benau Date: Sat, 22 Sep 2018 00:54:37 +0800 Subject: [PATCH 9/9] Check for possible null m_confirmed_state --- src/items/network_item_manager.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/items/network_item_manager.cpp b/src/items/network_item_manager.cpp index b77cce037..5882b0f87 100644 --- a/src/items/network_item_manager.cpp +++ b/src/items/network_item_manager.cpp @@ -319,11 +319,14 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) // otherwise resulting in stuttering). int old_time = world->getTicksSinceStart(); // Save time we rewind to world->setTicksForRewind(iei.getTicks()); // Set time of event - collectedItem(m_confirmed_state[index], 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); + 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