diff --git a/src/items/item_event_info.cpp b/src/items/item_event_info.cpp index f9d97ea49..a0a2861bb 100644 --- a/src/items/item_event_info.cpp +++ b/src/items/item_event_info.cpp @@ -33,15 +33,23 @@ ItemEventInfo::ItemEventInfo(BareNetworkString *buffer, int *count) { m_type = (EventType)buffer->getUInt8(); m_ticks = buffer->getTime(); - m_kart_id = buffer->getInt8(); - m_index = buffer->getUInt16(); - *count -= 8; - if (m_type == IEI_NEW) + *count -= 5; + if (m_type != IEI_SWITCH) { - m_xyz = buffer->getVec3(); - *count -= 12; - } + m_kart_id = buffer->getInt8(); + m_index = buffer->getUInt16(); + *count -= 3; + if (m_type == IEI_NEW) + { + m_xyz = buffer->getVec3(); + *count -= 12; + } + } // is not switch + else // switch + { + m_kart_id = -1; + } } // ItemEventInfo(BareNetworkString, int *count) //----------------------------------------------------------------------------- @@ -51,10 +59,14 @@ ItemEventInfo::ItemEventInfo(BareNetworkString *buffer, int *count) void ItemEventInfo::saveState(BareNetworkString *buffer) { assert(NetworkConfig::get()->isServer()); - buffer->addUInt8(m_type).addTime(m_ticks).addUInt8(m_kart_id) - .addUInt16(m_index); - if(m_type == IEI_NEW) - buffer->add(m_xyz); + buffer->addUInt8(m_type).addTime(m_ticks); + if (m_type != IEI_SWITCH) + { + // Only new item and collecting items need the index and kart id: + buffer->addUInt8(m_kart_id).addUInt16(m_index); + if (m_type == IEI_NEW) + buffer->add(m_xyz); + } } // saveState diff --git a/src/items/network_item_manager.cpp b/src/items/network_item_manager.cpp old mode 100644 new mode 100755 index a6ed824e3..dcb5b5b8a --- a/src/items/network_item_manager.cpp +++ b/src/items/network_item_manager.cpp @@ -42,6 +42,7 @@ void NetworkItemManager::create() NetworkItemManager::NetworkItemManager() : Rewinder("N"), ItemManager() { + m_confirmed_switch_ticks = -1; m_last_confirmed_item_ticks.clear(); if (NetworkConfig::get()->isServer()) @@ -71,6 +72,7 @@ NetworkItemManager::~NetworkItemManager() //----------------------------------------------------------------------------- void NetworkItemManager::reset() { + m_confirmed_switch_ticks = -1; ItemManager::reset(); } // reset @@ -114,6 +116,25 @@ void NetworkItemManager::collectedItem(ItemState *item, AbstractKart *kart) } } // collectedItem +// ---------------------------------------------------------------------------- +/** Called when a switch is activated. On the server adds this information to + * the item state so it can be sent to all clients. + */ +void NetworkItemManager::switchItems() +{ + if (NetworkConfig::get()->isServer()) + { + // The server saves the collected item as item event info + m_item_events.lock(); + // Create a switch event - the constructor called determines + // the type of the event automatically. + m_item_events.getData() + .emplace_back(World::getWorld()->getTicksSinceStart()); + m_item_events.unlock(); + } + ItemManager::switchItems(); +} // switchItems + // ---------------------------------------------------------------------------- /** Called when a new item is created, e.g. bubble gum. * \param type Type of the item. @@ -233,6 +254,13 @@ void NetworkItemManager::forwardTime(int ticks) { if (i) i->update(ticks); } // for m_all_items + if(m_switch_ticks>ticks) + m_switch_ticks -= ticks; + else if (m_switch_ticks >= 0) + { + switchItemsInternal(m_confirmed_state); + m_switch_ticks = -1; + } } // forwardTime //----------------------------------------------------------------------------- @@ -245,6 +273,7 @@ void NetworkItemManager::forwardTime(int ticks) */ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) { + assert(NetworkConfig::get()->isClient()); // The state at World::getTicksSinceStart() needs to be restored. The confirmed // state in this instance was taken at m_confirmed_state_time. First @@ -270,18 +299,34 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) // -------------------------- for (unsigned int i=0; iisPredicted()) { deleteItem(item); } } // for i in m_all_items + // Reset a predicted switch time: if the items are currently + // predicted to be switched, but not switched at the confirmed + // state time or vice versa, we need to switch them back. This + // is tested by seeing if the signs of the switch_ticks and + // confirmed switch_ticks are opposite: + if(m_switch_ticks * m_confirmed_switch_ticks < 0) + { + switchItemsInternal(m_all_items); + } + m_switch_ticks = m_confirmed_switch_ticks; + + // 2) Apply all events to current confirmed state: // ----------------------------------------------- World *world = World::getWorld(); int current_time = m_confirmed_state_time; bool has_state = count > 0; + + // Note that the actual ItemManager states must NOT be changed here, only + // the confirmed states in the Network manager are allowed to be modified. + // They will all be copied to the ItemManager states after the loop. while(count > 0) { // 2.1) Decode the event in the message @@ -292,16 +337,14 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) // 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 + // Skip an event that is 'in the past' (i.e. have been sent again by // the server because it has not yet received confirmation from all - // clients. + // clients). if(dt<0) continue; // Forward the saved state: if (dt>0) forwardTime(dt); - // TODO: apply the various events types, atm only collection - // and new items are supported. if(iei.isItemCollection()) { int index = iei.getIndex(); @@ -348,6 +391,19 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) } } } + else if(iei.isSwitch()) + { + // Reset current switch ticks + m_switch_ticks = -1; + ItemManager::switchItemsInternal(m_confirmed_state); + m_confirmed_switch_ticks = m_switch_ticks; + } + else + { + Log::error("NetworkItemManager", + "Received unknown event type at %d", + iei.getTicks()); + } current_time = iei.getTicks(); } // while count >0 @@ -360,6 +416,8 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) gp->sendItemEventConfirmation(world->getTicksSinceStart()); } + m_switch_ticks = m_confirmed_switch_ticks; + // Forward the confirmed item state to the world time: int dt = world->getTicksSinceStart() - current_time; if(dt>0) forwardTime(dt); @@ -369,7 +427,7 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) for(unsigned int i=0; igetItemId()); if(m_all_items[i]) deleteItem(m_all_items[i]); m_all_items[item_new->getItemId()] = NULL; @@ -397,14 +453,12 @@ 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->getTicksSinceStart(); + m_confirmed_state_time = world->getTicksSinceStart(); + m_confirmed_switch_ticks = m_switch_ticks; } // restoreState diff --git a/src/items/network_item_manager.hpp b/src/items/network_item_manager.hpp index 4b2befbc0..af46ea7cf 100644 --- a/src/items/network_item_manager.hpp +++ b/src/items/network_item_manager.hpp @@ -48,6 +48,9 @@ private: * server data. This is used in case of rewind. */ std::vector m_confirmed_state; + /** The switch ticks value at the lime of the last confirmed state. */ + int m_confirmed_switch_ticks; + /** Time at which m_confirmed_state was taken. */ int m_confirmed_state_time; @@ -66,14 +69,14 @@ public: static void create(); virtual ~NetworkItemManager(); - void setSwitchItems(const std::vector &switch_items); void sendItemUpdate(); void initClientConfirmState(); virtual void reset() OVERRIDE; virtual void setItemConfirmationTime(std::weak_ptr peer, int ticks) OVERRIDE; - virtual void collectedItem(ItemState *item, AbstractKart *kart) OVERRIDE; + virtual void collectedItem(ItemState *item, AbstractKart *kart) OVERRIDE; + virtual void switchItems() OVERRIDE; virtual Item* dropNewItem(ItemState::ItemType type, const AbstractKart *kart, const Vec3 *xyz=NULL) OVERRIDE; virtual BareNetworkString* saveState(std::vector* ru)