Hopefully fixed switch in networking mode.

This commit is contained in:
hiker 2018-10-03 08:51:19 +10:00
parent c2d0ac4a61
commit 76dc8c8763
3 changed files with 94 additions and 25 deletions

View File

@ -33,15 +33,23 @@ ItemEventInfo::ItemEventInfo(BareNetworkString *buffer, int *count)
{ {
m_type = (EventType)buffer->getUInt8(); m_type = (EventType)buffer->getUInt8();
m_ticks = buffer->getTime(); m_ticks = buffer->getTime();
*count -= 5;
if (m_type != IEI_SWITCH)
{
m_kart_id = buffer->getInt8(); m_kart_id = buffer->getInt8();
m_index = buffer->getUInt16(); m_index = buffer->getUInt16();
*count -= 8; *count -= 3;
if (m_type == IEI_NEW) if (m_type == IEI_NEW)
{ {
m_xyz = buffer->getVec3(); m_xyz = buffer->getVec3();
*count -= 12; *count -= 12;
} }
} // is not switch
else // switch
{
m_kart_id = -1;
}
} // ItemEventInfo(BareNetworkString, int *count) } // ItemEventInfo(BareNetworkString, int *count)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -51,10 +59,14 @@ ItemEventInfo::ItemEventInfo(BareNetworkString *buffer, int *count)
void ItemEventInfo::saveState(BareNetworkString *buffer) void ItemEventInfo::saveState(BareNetworkString *buffer)
{ {
assert(NetworkConfig::get()->isServer()); assert(NetworkConfig::get()->isServer());
buffer->addUInt8(m_type).addTime(m_ticks).addUInt8(m_kart_id) buffer->addUInt8(m_type).addTime(m_ticks);
.addUInt16(m_index); 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) if (m_type == IEI_NEW)
buffer->add(m_xyz); buffer->add(m_xyz);
}
} // saveState } // saveState

76
src/items/network_item_manager.cpp Normal file → Executable file
View File

@ -42,6 +42,7 @@ void NetworkItemManager::create()
NetworkItemManager::NetworkItemManager() NetworkItemManager::NetworkItemManager()
: Rewinder("N"), ItemManager() : Rewinder("N"), ItemManager()
{ {
m_confirmed_switch_ticks = -1;
m_last_confirmed_item_ticks.clear(); m_last_confirmed_item_ticks.clear();
if (NetworkConfig::get()->isServer()) if (NetworkConfig::get()->isServer())
@ -71,6 +72,7 @@ NetworkItemManager::~NetworkItemManager()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void NetworkItemManager::reset() void NetworkItemManager::reset()
{ {
m_confirmed_switch_ticks = -1;
ItemManager::reset(); ItemManager::reset();
} // reset } // reset
@ -114,6 +116,25 @@ void NetworkItemManager::collectedItem(ItemState *item, AbstractKart *kart)
} }
} // collectedItem } // 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. /** Called when a new item is created, e.g. bubble gum.
* \param type Type of the item. * \param type Type of the item.
@ -233,6 +254,13 @@ void NetworkItemManager::forwardTime(int ticks)
{ {
if (i) i->update(ticks); if (i) i->update(ticks);
} // for m_all_items } // 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 } // forwardTime
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -245,6 +273,7 @@ void NetworkItemManager::forwardTime(int ticks)
*/ */
void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
{ {
assert(NetworkConfig::get()->isClient()); assert(NetworkConfig::get()->isClient());
// The state at World::getTicksSinceStart() needs to be restored. The confirmed // The state at World::getTicksSinceStart() needs to be restored. The confirmed
// state in this instance was taken at m_confirmed_state_time. First // 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; i<m_all_items.size(); i++) for (unsigned int i=0; i<m_all_items.size(); i++)
{ {
Item *item = m_all_items[i]; ItemState *item = m_all_items[i];
if(item && item->isPredicted()) if(item && item->isPredicted())
{ {
deleteItem(item); deleteItem(item);
} }
} // for i in m_all_items } // 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: // 2) Apply all events to current confirmed state:
// ----------------------------------------------- // -----------------------------------------------
World *world = World::getWorld(); World *world = World::getWorld();
int current_time = m_confirmed_state_time; int current_time = m_confirmed_state_time;
bool has_state = count > 0; 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) while(count > 0)
{ {
// 2.1) Decode the event in the message // 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: // the time to the time of this event:
// ---------------------------------------------- // ----------------------------------------------
int dt = iei.getTicks() - current_time; 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 // the server because it has not yet received confirmation from all
// clients. // clients).
if(dt<0) continue; if(dt<0) continue;
// 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
// and new items are supported.
if(iei.isItemCollection()) if(iei.isItemCollection())
{ {
int index = iei.getIndex(); 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(); current_time = iei.getTicks();
} // while count >0 } // while count >0
@ -360,6 +416,8 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
gp->sendItemEventConfirmation(world->getTicksSinceStart()); gp->sendItemEventConfirmation(world->getTicksSinceStart());
} }
m_switch_ticks = m_confirmed_switch_ticks;
// Forward the confirmed item state to the world time: // Forward the confirmed item state to the world time:
int dt = world->getTicksSinceStart() - current_time; int dt = world->getTicksSinceStart() - current_time;
if(dt>0) forwardTime(dt); if(dt>0) forwardTime(dt);
@ -369,7 +427,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 = i < m_all_items.size() ? m_all_items[i] : NULL; ItemState *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;
@ -383,8 +441,6 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
// The server has this item at a different index in the list // The server has this item at a different index in the list
// of all items, which means the client has an incorrect // of all items, which means the client has an incorrect
// item at the index given by the server - delete that item // 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]) if(m_all_items[i])
deleteItem(m_all_items[i]); deleteItem(m_all_items[i]);
m_all_items[item_new->getItemId()] = NULL; m_all_items[item_new->getItemId()] = NULL;
@ -397,14 +453,12 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
} }
else if (!is && item) else if (!is && item)
{ {
Log::info("nim", "About to delete item index %d i %d",
item->getItemId(), i);
deleteItem(m_all_items[i]); deleteItem(m_all_items[i]);
} }
} }
// Now we save the current local // 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 } // restoreState

View File

@ -48,6 +48,9 @@ private:
* server data. This is used in case of rewind. */ * server data. This is used in case of rewind. */
std::vector<ItemState*> m_confirmed_state; std::vector<ItemState*> 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. */ /** Time at which m_confirmed_state was taken. */
int m_confirmed_state_time; int m_confirmed_state_time;
@ -66,7 +69,6 @@ public:
static void create(); static void create();
virtual ~NetworkItemManager(); virtual ~NetworkItemManager();
void setSwitchItems(const std::vector<int> &switch_items);
void sendItemUpdate(); void sendItemUpdate();
void initClientConfirmState(); void initClientConfirmState();
@ -74,6 +76,7 @@ public:
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(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, 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)