Started to implement proper item handling: the server now sends
updates of all collected items to the clients as part of a state. A client confirms the received states. Once all clients have confirmed a certain event, that event is deleted on the server and not sent anymore. WIP, item collection kind of works, but only because of kart state updates which include attachment (but not e.g. nitro).
This commit is contained in:
parent
356680b182
commit
9d60112e65
@ -1,5 +1,5 @@
|
||||
# Modify this file to change the last-modified date when you add/remove a file.
|
||||
# This will then trigger a new cmake run automatically.
|
||||
# This will then trigger a new cmake run automatically.
|
||||
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
|
||||
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
|
||||
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
|
||||
|
@ -19,11 +19,11 @@
|
||||
|
||||
#include "items/item.hpp"
|
||||
|
||||
#include "items/item_manager.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "graphics/lod_node.hpp"
|
||||
#include "graphics/sp/sp_mesh.hpp"
|
||||
#include "graphics/sp/sp_mesh_node.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "modes/three_strikes_battle.hpp"
|
||||
#include "modes/world.hpp"
|
||||
|
@ -20,11 +20,9 @@
|
||||
#ifndef HEADER_ITEM_HPP
|
||||
#define HEADER_ITEM_HPP
|
||||
|
||||
/**
|
||||
* \defgroup items
|
||||
* Defines the various collectibles and weapons of STK.
|
||||
*/
|
||||
|
||||
/** \defgroup items
|
||||
* Defines the various collectibles and weapons of STK.
|
||||
*/
|
||||
|
||||
#include "utils/leak_check.hpp"
|
||||
#include "utils/no_copy.hpp"
|
||||
@ -62,7 +60,7 @@ public:
|
||||
* and therefore not stored here). This class is used as a base class for
|
||||
* item and for networking to save item states.
|
||||
*/
|
||||
class ItemState : public NoCopy
|
||||
class ItemState
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@ -104,8 +102,9 @@ private:
|
||||
* > 0 it means that the item is not available. */
|
||||
int m_ticks_till_return;
|
||||
|
||||
/** Index in item_manager field. */
|
||||
unsigned int m_item_id;
|
||||
/** Index in item_manager field. This field can also take on a negative
|
||||
* value when used in the NetworkItemManager. */
|
||||
int m_item_id;
|
||||
|
||||
/** Optionally if item was placed by a kart, a timer can be used to
|
||||
* temporarly deactivate collision so a kart is not hit by its own item */
|
||||
@ -119,16 +118,20 @@ private:
|
||||
int m_used_up_counter;
|
||||
|
||||
protected:
|
||||
friend class ItemManager;
|
||||
friend class NetworkItemManager;
|
||||
// ------------------------------------------------------------------------
|
||||
void setType(ItemType type) { m_type = type; }
|
||||
|
||||
public:
|
||||
/** Constructor. */
|
||||
ItemState(ItemType type)
|
||||
ItemState(ItemType type, int id=-1)
|
||||
{
|
||||
m_item_id = -1;
|
||||
m_item_id = id;
|
||||
setType(type);
|
||||
}
|
||||
} // ItemState(ItemType)
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
void setDisappearCounter();
|
||||
void update(int ticks);
|
||||
void collected(int ticks);
|
||||
@ -243,7 +246,7 @@ public:
|
||||
/**
|
||||
* \ingroup items
|
||||
*/
|
||||
class Item : public ItemState
|
||||
class Item : public ItemState, public NoCopy
|
||||
{
|
||||
|
||||
private:
|
||||
|
@ -337,17 +337,7 @@ void ItemManager::checkItemHit(AbstractKart* kart)
|
||||
// we pass the kart and the position separately.
|
||||
if((*i)->hitKart(kart->getXYZ(), kart))
|
||||
{
|
||||
// if we're not playing online, pick the item.
|
||||
if (!NetworkConfig::get()->isNetworking())
|
||||
collectedItem(*i, kart);
|
||||
else if (NetworkConfig::get()->isServer())
|
||||
{
|
||||
// Only the server side detects item being collected
|
||||
// A client does the collection upon receiving the
|
||||
// event from the server!
|
||||
collectedItem(*i, kart);
|
||||
RaceEventManager::getInstance()->collectedItem(*i, kart);
|
||||
}
|
||||
collectedItem(*i, kart);
|
||||
} // if hit
|
||||
} // for m_all_items
|
||||
} // checkItemHit
|
||||
|
@ -50,6 +50,7 @@ private:
|
||||
/** Stores all low-resolution item models. */
|
||||
static std::vector<scene::IMesh *> m_item_lowres_mesh;
|
||||
|
||||
protected:
|
||||
/** The instance of ItemManager while a race is on. */
|
||||
static ItemManager *m_item_manager;
|
||||
public:
|
||||
@ -75,11 +76,12 @@ public:
|
||||
} // get
|
||||
|
||||
// ========================================================================
|
||||
private:
|
||||
protected:
|
||||
/** The vector of all items of the current track. */
|
||||
typedef std::vector<Item*> AllItemTypes;
|
||||
AllItemTypes m_all_items;
|
||||
|
||||
private:
|
||||
/** Stores which items are on which quad. m_items_in_quads[#quads]
|
||||
* contains all items that are not on a quad. Note that this
|
||||
* field is undefined if no Graph exist, e.g. arena without navmesh. */
|
||||
@ -95,9 +97,10 @@ private:
|
||||
void insertItem(Item *item);
|
||||
void deleteItem(Item *item);
|
||||
|
||||
public:
|
||||
// Make those private so only create/destroy functions can call them.
|
||||
ItemManager();
|
||||
~ItemManager();
|
||||
virtual ~ItemManager();
|
||||
void setSwitchItems(const std::vector<int> &switch_items);
|
||||
|
||||
public:
|
||||
@ -110,14 +113,22 @@ public:
|
||||
void updateGraphics (float dt);
|
||||
void checkItemHit (AbstractKart* kart);
|
||||
void reset ();
|
||||
void collectedItem (Item *item, AbstractKart *kart,
|
||||
virtual void collectedItem (Item *item, AbstractKart *kart,
|
||||
int add_info=-1);
|
||||
void switchItems ();
|
||||
// ------------------------------------------------------------------------
|
||||
bool randomItemsForArena(const AlignedArray<btTransform>& pos);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Only used in the NetworkItemManager. */
|
||||
virtual void setItemConfirmationTime(int host_id, int ticks)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of items. */
|
||||
unsigned int getNumberOfItems() const { return (unsigned int) m_all_items.size(); }
|
||||
unsigned int getNumberOfItems() const
|
||||
{
|
||||
return (unsigned int) m_all_items.size();
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a pointer to the n-th item. */
|
||||
const Item* getItem(unsigned int n) const { return m_all_items[n]; };
|
||||
|
214
src/items/network_item_manager.cpp
Normal file
214
src/items/network_item_manager.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2018 Joerg Henrichs
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "items/network_item_manager.hpp"
|
||||
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/protocols/game_protocol.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Creates one instance of the item manager. */
|
||||
void NetworkItemManager::create()
|
||||
{
|
||||
assert(!m_item_manager);
|
||||
m_item_manager = new NetworkItemManager();
|
||||
} // create
|
||||
|
||||
|
||||
// ============================================================================
|
||||
/** Creates a new instance of the item manager. This is done at startup
|
||||
* of each race. */
|
||||
NetworkItemManager::NetworkItemManager()
|
||||
: ItemManager()
|
||||
, Rewinder(/*can be deleted*/false)
|
||||
{
|
||||
m_last_confirmed_item_ticks.lock();
|
||||
m_last_confirmed_item_ticks.getData().clear();
|
||||
|
||||
if (NetworkConfig::get()->isServer())
|
||||
m_last_confirmed_item_ticks.getData().resize(STKHost::get()->getPeerCount(), 0);
|
||||
|
||||
m_last_confirmed_item_ticks.unlock();
|
||||
} // NetworkItemManager
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Destructor. Cleans up all items and meshes stored.
|
||||
*/
|
||||
NetworkItemManager::~NetworkItemManager()
|
||||
{
|
||||
} // ~NetworkItemManager
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void NetworkItemManager::reset()
|
||||
{
|
||||
m_last_confirmed_event = 0;
|
||||
ItemManager::reset();
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Copies the initial state at the start of a race as confirmed state.
|
||||
*/
|
||||
void NetworkItemManager::saveInitialState()
|
||||
{
|
||||
m_confirmed_state_time = 0;
|
||||
m_last_confirmed_event = 0;
|
||||
|
||||
m_confirmed_state.clear();
|
||||
for(auto i : m_all_items)
|
||||
{
|
||||
m_confirmed_state.emplace_back(*i);
|
||||
}
|
||||
} // saveInitialState
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called when a kart collects an item. In network games only the server
|
||||
* acts on this event.
|
||||
* \param item The item that was collected.
|
||||
* \param kart The kart that collected the item.
|
||||
* \param add_info
|
||||
*/
|
||||
void NetworkItemManager::collectedItem(Item *item, AbstractKart *kart,
|
||||
int add_info)
|
||||
{
|
||||
if(NetworkConfig::get()->isServer())
|
||||
{
|
||||
m_item_events.emplace_back(item->getType(), item->getItemId(),
|
||||
World::getWorld()->getTimeTicks(),
|
||||
kart->getWorldKartId() );
|
||||
ItemManager::collectedItem(item, kart, add_info);
|
||||
}
|
||||
} // collectedItem
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void NetworkItemManager::setItemConfirmationTime(int host_id, int ticks)
|
||||
{
|
||||
m_last_confirmed_item_ticks.lock();
|
||||
if (ticks > m_last_confirmed_item_ticks.getData()[host_id])
|
||||
m_last_confirmed_item_ticks.getData()[host_id] = ticks;
|
||||
m_last_confirmed_item_ticks.unlock();
|
||||
} // setItemConfirmationTime
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
BareNetworkString* NetworkItemManager::saveState()
|
||||
{
|
||||
if(NetworkConfig::get()->isClient())
|
||||
{
|
||||
saveInitialState();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// On the server:
|
||||
// ==============
|
||||
// First discard unneeded events, i.e. all events that have
|
||||
// been confirmed by all clients:
|
||||
int min_time = World::getWorld()->getTimeTicks() + 1;
|
||||
m_last_confirmed_item_ticks.lock();
|
||||
for (auto i : m_last_confirmed_item_ticks.getData())
|
||||
if (i < min_time) min_time = i;
|
||||
m_last_confirmed_item_ticks.unlock();
|
||||
|
||||
auto p = m_item_events.begin();
|
||||
while (p != m_item_events.end() && p->m_ticks < min_time)
|
||||
p++;
|
||||
m_item_events.erase(m_item_events.begin(), p);
|
||||
|
||||
uint16_t n = (uint16_t)m_item_events.size();
|
||||
if(n==0)
|
||||
{
|
||||
BareNetworkString *s =
|
||||
new BareNetworkString();
|
||||
return s;
|
||||
}
|
||||
|
||||
BareNetworkString *s =
|
||||
new BareNetworkString(n * (sizeof(int) + sizeof(uint16_t) +
|
||||
+ sizeof(uint8_t) ) );
|
||||
for (auto p : m_item_events)
|
||||
{
|
||||
s->addTime(p.m_ticks).addUInt16(p.m_item_id);
|
||||
if (p.m_item_id > -1) s->addUInt8(p.m_kart_id);
|
||||
}
|
||||
Log::verbose("NIM", "Including %d item update at %d",
|
||||
n, World::getWorld()->getTimeTicks());
|
||||
return s;
|
||||
} // saveState
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Restores a state, using exactly 'count' bytes of the message.
|
||||
* \param buffer the state content.
|
||||
* \param count Number of bytes used for this state.
|
||||
*/
|
||||
void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
|
||||
{
|
||||
while(count > 0)
|
||||
{
|
||||
int ticks = buffer->getTime();
|
||||
int item_id = buffer->getUInt16();
|
||||
int kart_id = -1;
|
||||
count -= 6;
|
||||
if(item_id>-1)
|
||||
{
|
||||
// Not a global event, so we have a kart id
|
||||
kart_id = buffer->getUInt8();
|
||||
count --;
|
||||
} // item_id>-1
|
||||
// This event has already been received, and can be ignored now.
|
||||
if(ticks <= m_last_confirmed_event) continue;
|
||||
|
||||
// Now we certainly have a new event that needs to be added:
|
||||
m_item_events.emplace_back(m_all_items[item_id]->getType(), item_id,
|
||||
ticks, kart_id );
|
||||
Log::info("NIM", "Received new event at %d", ticks);
|
||||
} // while count >0
|
||||
|
||||
// At le
|
||||
if(!m_item_events.empty())
|
||||
m_last_confirmed_event = m_item_events.back().m_ticks;
|
||||
m_last_confirmed_event = std::max(World::getWorld()->getTimeTicks(),
|
||||
m_last_confirmed_event );
|
||||
GameProtocol::lock()->sendItemEventConfirmation(m_last_confirmed_event);
|
||||
} // undoState
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void NetworkItemManager::rewindToEvent(BareNetworkString *bns)
|
||||
{
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void NetworkItemManager::restoreStateAt(int ticks)
|
||||
{
|
||||
if (ticks < m_confirmed_state_time)
|
||||
{
|
||||
Log::error("ItemManager",
|
||||
"Trying to restore state at t %d, but confirmed state is from %d.",
|
||||
ticks, m_confirmed_state_time);
|
||||
// Nothing much we can do about this - it should never happeb
|
||||
m_confirmed_state_time = ticks;
|
||||
}
|
||||
|
||||
|
||||
for(auto i : m_confirmed_state)
|
||||
{
|
||||
|
||||
Item *it = m_all_items[i.m_item_id];
|
||||
}
|
||||
|
||||
} // restoreStateAt
|
108
src/items/network_item_manager.hpp
Normal file
108
src/items/network_item_manager.hpp
Normal file
@ -0,0 +1,108 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2018 Joerg Henrichs
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_NETWORK_ITEM_MANAGER_HPP
|
||||
#define HEADER_NETWORK_ITEM_MANAGER_HPP
|
||||
|
||||
#include "items/item_manager.hpp"
|
||||
#include "network/rewinder.hpp"
|
||||
#include "utils/cpp2011.hpp"
|
||||
#include "utils/synchronised.hpp"
|
||||
|
||||
/** \ingroup items
|
||||
* The network item manager is responsible for handling all network related
|
||||
* item manager tasks - synchronisation between clients and servers. It
|
||||
* maintains one 'confirmed' state on the clients, based on the latest
|
||||
* server update. The server sends updates that only contains the delta
|
||||
* between the last confirmed and the current server state. Eash client
|
||||
* confirms to the server which deltas it has received. Once all clients
|
||||
* have received a delta, the server will remove it from the list of
|
||||
* deltas.
|
||||
*/
|
||||
class NetworkItemManager : public Rewinder, public ItemManager
|
||||
{
|
||||
private:
|
||||
|
||||
/** A client stores a 'confirmed' item event state, which is based on the
|
||||
* server data. This is used in case of rewind. */
|
||||
std::vector<ItemState> m_confirmed_state;
|
||||
|
||||
/** Time at which m_confirmed_state was taken. */
|
||||
int m_confirmed_state_time;
|
||||
|
||||
/** Stores on the server the latest confirmed tick from each client. */
|
||||
Synchronised< std::vector<int> > m_last_confirmed_item_ticks;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** This class stores a delta, i.e. an item event (either collection of
|
||||
* an item, or an item switch being activated). All those deltas
|
||||
* will be applied to the confirmed state to get a new state. */
|
||||
class ItemEventInfo : public ItemState
|
||||
{
|
||||
public:
|
||||
/** The kart id that collected an item (if m_item_id>-1),
|
||||
* otherwise undefined. */
|
||||
int m_kart_id;
|
||||
|
||||
/** Time at which this event happens. */
|
||||
int m_ticks;
|
||||
|
||||
ItemEventInfo(ItemState::ItemType type, int item_id,
|
||||
int ticks, int kart_id)
|
||||
: ItemState(type, item_id)
|
||||
, m_kart_id(kart_id), m_ticks(ticks)
|
||||
{ }
|
||||
|
||||
}; // class ItemEventInfo
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** List of all items events. */
|
||||
std::vector<ItemEventInfo> m_item_events;
|
||||
|
||||
/** Time of the last confirmed event. */
|
||||
int m_last_confirmed_event;
|
||||
|
||||
NetworkItemManager();
|
||||
virtual ~NetworkItemManager();
|
||||
|
||||
public:
|
||||
static void create();
|
||||
|
||||
void setSwitchItems(const std::vector<int> &switch_items);
|
||||
void sendItemUpdate();
|
||||
void saveInitialState();
|
||||
void restoreStateAt(int ticks);
|
||||
|
||||
virtual void reset();
|
||||
virtual void setItemConfirmationTime(int host_id, int ticks);
|
||||
virtual void collectedItem(Item *item, AbstractKart *kart,
|
||||
int add_info = -1);
|
||||
virtual void rewindToEvent(BareNetworkString *bns) OVERRIDE;
|
||||
virtual BareNetworkString* saveState() OVERRIDE;
|
||||
virtual void restoreState(BareNetworkString *buffer, int count) OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void saveTransform() OVERRIDE {};
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void computeError() OVERRIDE {};
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void undoState(BareNetworkString *buffer) OVERRIDE {};
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void undoEvent(BareNetworkString*) OVERRIDE {};
|
||||
}; // NetworkItemManager
|
||||
|
||||
#endif
|
@ -79,7 +79,7 @@ void KartRewinder::computeError()
|
||||
* \param[out] buffer Address of the memory buffer.
|
||||
* \returns Size of allocated memory, or -1 in case of an error.
|
||||
*/
|
||||
BareNetworkString* KartRewinder::saveState() const
|
||||
BareNetworkString* KartRewinder::saveState()
|
||||
{
|
||||
const int MEMSIZE = 17*sizeof(float) + 9+3;
|
||||
|
||||
@ -124,8 +124,12 @@ BareNetworkString* KartRewinder::saveState() const
|
||||
} // saveState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Actually rewind to the specified state. */
|
||||
void KartRewinder::rewindToState(BareNetworkString *buffer)
|
||||
/** Actually rewind to the specified state.
|
||||
* \param buffer The buffer with the state info.
|
||||
* \param count Number of bytes that must be used up in this function (not
|
||||
* used).
|
||||
*/
|
||||
void KartRewinder::restoreState(BareNetworkString *buffer, int count)
|
||||
{
|
||||
// 1) Physics values: transform and velocities
|
||||
// -------------------------------------------
|
||||
@ -170,7 +174,7 @@ void KartRewinder::rewindToState(BareNetworkString *buffer)
|
||||
// -----------
|
||||
m_skidding->rewindTo(buffer);
|
||||
return;
|
||||
} // rewindToState
|
||||
} // restoreState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called once a frame. It will add a new kart control event to the rewind
|
||||
|
@ -45,9 +45,9 @@ public:
|
||||
virtual ~KartRewinder() {};
|
||||
virtual void saveTransform() OVERRIDE;
|
||||
virtual void computeError() OVERRIDE;
|
||||
virtual BareNetworkString* saveState() const;
|
||||
virtual BareNetworkString* saveState();
|
||||
void reset();
|
||||
virtual void rewindToState(BareNetworkString *p) OVERRIDE;
|
||||
virtual void restoreState(BareNetworkString *p, int count) OVERRIDE;
|
||||
virtual void rewindToEvent(BareNetworkString *p) OVERRIDE;
|
||||
virtual void update(int ticks) OVERRIDE;
|
||||
|
||||
|
@ -21,6 +21,10 @@
|
||||
|
||||
class BareNetworkString;
|
||||
|
||||
/** A simple class that defines an interface to event rewinding: an undo()
|
||||
* function when going back in time, and a replay() function when going
|
||||
* forward, replaying the event.
|
||||
*/
|
||||
class EventRewinder
|
||||
{
|
||||
public:
|
||||
|
@ -263,21 +263,41 @@ public:
|
||||
return addFloat(quat.getX()).addFloat(quat.getY())
|
||||
.addFloat(quat.getZ()).addFloat(quat.getW());
|
||||
} // add
|
||||
// ------------------------------------------------------------------------
|
||||
/** Adds a function to add a time ticks value. Use this function instead
|
||||
* of addUInt32 because we might decide later to compress time values
|
||||
* (e.g. sending 16 bytes for as long as possible).
|
||||
*/
|
||||
BareNetworkString& addTime(int ticks)
|
||||
{
|
||||
return addUInt32(ticks);
|
||||
} // addTime
|
||||
|
||||
// Functions related to getting data from a network string
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a unsigned 32 bit integer. */
|
||||
inline uint32_t getUInt32() const { return get<uint32_t, 4>(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a unsigned 32 bit integer. */
|
||||
inline uint32_t getTime() const { return get<uint32_t, 4>(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns an unsigned 16 bit integer. */
|
||||
inline uint16_t getUInt16() const { return get<uint16_t, 2>(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns an unsigned 16 bit integer. */
|
||||
inline int16_t getInt16() const { return get<int16_t, 2>(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns an unsigned 8-bit integer. */
|
||||
inline uint8_t getUInt8() const
|
||||
{
|
||||
return m_buffer[m_current_offset++];
|
||||
} // getUInt8
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns an unsigned 8-bit integer. */
|
||||
inline uint8_t getInt8() const
|
||||
{
|
||||
return m_buffer[m_current_offset++];
|
||||
} // getUInt8
|
||||
// ------------------------------------------------------------------------
|
||||
/** Gets a 4 byte floating point value. */
|
||||
float getFloat() const
|
||||
|
@ -1,10 +1,6 @@
|
||||
#include "network/protocols/game_events_protocol.hpp"
|
||||
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "items/attachment.hpp"
|
||||
#include "items/item.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "items/powerup.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "network/event.hpp"
|
||||
#include "network/game_setup.hpp"
|
||||
@ -14,7 +10,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** This class handles all 'major' game events. E.g. collecting an item,
|
||||
/** This class handles all 'major' game events. E.g.
|
||||
* finishing a race etc. The game events manager is notified from the
|
||||
* game code, and it calls the corresponding function in this class.
|
||||
* The server then notifies all clients. Clients receive the message
|
||||
@ -49,8 +45,6 @@ bool GameEventsProtocol::notifyEvent(Event* event)
|
||||
uint8_t type = data.getUInt8();
|
||||
switch (type)
|
||||
{
|
||||
case GE_ITEM_COLLECTED:
|
||||
collectedItem(data); break;
|
||||
case GE_KART_FINISHED_RACE:
|
||||
kartFinishedRace(data); break;
|
||||
case GE_PLAYER_DISCONNECT:
|
||||
@ -62,30 +56,6 @@ bool GameEventsProtocol::notifyEvent(Event* event)
|
||||
return true;
|
||||
} // notifyEvent
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called on the server when an item is collected.
|
||||
*/
|
||||
void GameEventsProtocol::collectedItem(Item* item, AbstractKart* kart)
|
||||
{
|
||||
NetworkString *ns = getNetworkString(7);
|
||||
ns->setSynchronous(true);
|
||||
// Item picked : send item id, powerup type and kart race id
|
||||
uint8_t powerup = 0;
|
||||
if (item->getType() == Item::ITEM_BANANA)
|
||||
powerup = (int)(kart->getAttachment()->getType());
|
||||
else if (item->getType() == Item::ITEM_BONUS_BOX)
|
||||
powerup = (((int)(kart->getPowerup()->getType()) << 4) & 0xf0)
|
||||
+ (kart->getPowerup()->getNum() & 0x0f);
|
||||
|
||||
ns->addUInt8(GE_ITEM_COLLECTED).addUInt32(item->getItemId())
|
||||
.addUInt8(powerup).addUInt8(kart->getWorldKartId());
|
||||
Log::info("GameEventsProtocol",
|
||||
"Notified a peer that a kart collected item %d index %d",
|
||||
(int)(kart->getPowerup()->getType()), item->getItemId());
|
||||
STKHost::get()->sendPacketToAllPeers(ns, /*reliable*/true);
|
||||
delete ns;
|
||||
} // collectedItem
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GameEventsProtocol::eliminatePlayer(const NetworkString &data)
|
||||
{
|
||||
@ -102,26 +72,6 @@ void GameEventsProtocol::eliminatePlayer(const NetworkString &data)
|
||||
World::getWorld()->getTime());
|
||||
} // eliminatePlayer
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called on the client when an itemCollected message is received.
|
||||
*/
|
||||
void GameEventsProtocol::collectedItem(const NetworkString &data)
|
||||
{
|
||||
if (data.size() < 6)
|
||||
{
|
||||
Log::warn("GameEventsProtocol", "collectedItem: Too short message.");
|
||||
}
|
||||
uint32_t item_id = data.getUInt32();
|
||||
uint8_t powerup_type = data.getUInt8();
|
||||
uint8_t kart_id = data.getUInt8();
|
||||
// now set the kart powerup
|
||||
AbstractKart* kart = World::getWorld()->getKart(kart_id);
|
||||
Log::info("GameEventsProtocol", "Item %d of index %d picked by a player.",
|
||||
powerup_type, item_id);
|
||||
ItemManager::get()->collectedItem(ItemManager::get()->getItem(item_id),
|
||||
kart, powerup_type);
|
||||
} // collectedItem
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This function is called from the server when a kart finishes a race. It
|
||||
* sends a notification to all clients about this event.
|
||||
|
@ -5,16 +5,14 @@
|
||||
#include "utils/cpp2011.hpp"
|
||||
|
||||
class AbstractKart;
|
||||
class Item;
|
||||
|
||||
class GameEventsProtocol : public Protocol
|
||||
{
|
||||
public:
|
||||
enum GameEventType : uint8_t
|
||||
{
|
||||
GE_ITEM_COLLECTED = 1,
|
||||
GE_KART_FINISHED_RACE = 2,
|
||||
GE_PLAYER_DISCONNECT = 3
|
||||
GE_KART_FINISHED_RACE = 1,
|
||||
GE_PLAYER_DISCONNECT = 2
|
||||
}; // GameEventType
|
||||
private:
|
||||
void eliminatePlayer(const NetworkString &ns);
|
||||
@ -24,8 +22,6 @@ public:
|
||||
virtual ~GameEventsProtocol();
|
||||
|
||||
virtual bool notifyEvent(Event* event) OVERRIDE;
|
||||
void collectedItem(Item* item, AbstractKart* kart);
|
||||
void collectedItem(const NetworkString &ns);
|
||||
void kartFinishedRace(AbstractKart *kart, float time);
|
||||
void kartFinishedRace(const NetworkString &ns);
|
||||
virtual void setup() OVERRIDE {}
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#include "network/protocols/game_protocol.hpp"
|
||||
|
||||
#include "items/item_manager.hpp"
|
||||
#include "items/network_item_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/controller/player_controller.hpp"
|
||||
@ -53,6 +55,7 @@ GameProtocol::GameProtocol()
|
||||
: Protocol( PROTOCOL_CONTROLLER_EVENTS)
|
||||
{
|
||||
m_data_to_send = getNetworkString();
|
||||
|
||||
} // GameProtocol
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -98,11 +101,16 @@ bool GameProtocol::notifyEventAsynchronous(Event* event)
|
||||
|
||||
NetworkString &data = event->data();
|
||||
uint8_t message_type = data.getUInt8();
|
||||
if (message_type != GP_CONTROLLER_ACTION &&
|
||||
message_type != GP_STATE)
|
||||
printf("");
|
||||
switch (message_type)
|
||||
{
|
||||
case GP_CONTROLLER_ACTION: handleControllerAction(event); break;
|
||||
case GP_STATE: handleState(event); break;
|
||||
case GP_ADJUST_TIME: handleAdjustTime(event); break;
|
||||
//case GP_ITEM_UPDATE: handleItemUpdate(event); break;
|
||||
case GP_ITEM_CONFIRMATION: handleItemEventConfirmation(event); break;
|
||||
default: Log::error("GameProtocol",
|
||||
"Received unknown message type %d - ignored.",
|
||||
message_type); break;
|
||||
@ -242,6 +250,38 @@ void GameProtocol::handleAdjustTime(Event *event)
|
||||
int ticks = event->data().getUInt32();
|
||||
World::getWorld()->setAdjustTime(stk_config->ticks2Time(ticks));
|
||||
} // handleAdjustTime
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sends a confirmation to the server that all item events up to 'ticks'
|
||||
* have been received.
|
||||
* \param ticks Up to which time in ticks the item events have been received.
|
||||
*/
|
||||
void GameProtocol::sendItemEventConfirmation(int ticks)
|
||||
{
|
||||
assert(NetworkConfig::get()->isClient());
|
||||
NetworkString *ns = getNetworkString(5);
|
||||
ns->addUInt8(GP_ITEM_CONFIRMATION).addUInt32(ticks);
|
||||
// This message can be sent unreliable, it's not critical if it doesn't
|
||||
// get delivered, a future update will come through
|
||||
sendToServer(ns, /*reliable*/false);
|
||||
delete ns;
|
||||
} // sendItemEventConfirmation
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Handles an item even confirmation from a client. Once it has been confirmed
|
||||
* that all clients have received certain events, those can be deleted and
|
||||
* do not need to be sent again.
|
||||
* \param event The data from the client.
|
||||
*/
|
||||
void GameProtocol::handleItemEventConfirmation(Event *event)
|
||||
{
|
||||
assert(NetworkConfig::get()->isServer());
|
||||
int host_id = event->getPeer()->getHostId();
|
||||
int ticks = event->data().getTime();
|
||||
NetworkItemManager::get()->setItemConfirmationTime(host_id, ticks);
|
||||
|
||||
} // handleItemEventConfirmation
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called by the server before assembling a new message containing the full
|
||||
* state of the race to be sent to a client.
|
||||
@ -335,3 +375,78 @@ void GameProtocol::rewind(BareNetworkString *buffer)
|
||||
if (pc)
|
||||
pc->actionFromNetwork(action, value, value_l, value_r);
|
||||
} // rewind
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Adds an event like collection of an item or usage of a switch.
|
||||
* \param ticks Time at which the event happened.
|
||||
* \param item_id The index of the item that was affected. -1 indicates
|
||||
* a global event (e.g. switch).
|
||||
* \param kart_id The index of the kart that collected the item (unless
|
||||
* item_id == -1, in which case this value is -1).
|
||||
*/
|
||||
void GameProtocol::addItemEvent(int ticks, int item_id, int kart_id)
|
||||
{
|
||||
// assert(m_item_events.empty() || m_item_events.back().m_ticks <= ticks);
|
||||
if (NetworkConfig::get()->isServer())
|
||||
{
|
||||
// m_item_events.emplace_back(ticks, item_id, kart_id);
|
||||
}
|
||||
// sendItemUpdate();
|
||||
} // addItemEvent
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called when a client receives an item update.
|
||||
* \param event The message with the event data.
|
||||
*/
|
||||
#ifdef XX
|
||||
void GameProtocol::handleItemUpdate(Event *event)
|
||||
{
|
||||
Log::verbose("GameProtocol", "Received item update at %d",
|
||||
World::getWorld()->getTimeTicks());
|
||||
assert(NetworkConfig::get()->isClient());
|
||||
const NetworkString &data = event->data();
|
||||
uint16_t n = data.getUInt16();
|
||||
int time_of_last_event = 0;
|
||||
|
||||
for (unsigned int i = 0; i < n; i++)
|
||||
{
|
||||
int ticks = data.getTime();
|
||||
int16_t item_id = data.getInt16();
|
||||
int8_t kart_id = -1;
|
||||
if (item_id > -1) kart_id = data.getInt8();
|
||||
|
||||
if (ticks > time_of_last_event) time_of_last_event = ticks;
|
||||
|
||||
// Any event that has been received earlier can be igonred:
|
||||
if (ticks < m_last_confirmed_event) continue;
|
||||
|
||||
// m_item_events.emplace_back(ticks, item_id, kart_id);
|
||||
|
||||
} // for i < n
|
||||
Log::verbose("GameProtocol", "Received item update at %d n %d tola %d",
|
||||
World::getWorld()->getTimeTicks(),
|
||||
n, time_of_last_event);
|
||||
|
||||
// Send a confirmation to the server about which events where received:
|
||||
NetworkString *s = getNetworkString(1+sizeof(int));
|
||||
s->addUInt8(GP_ITEM_CONFIRMATION).addTime(time_of_last_event);
|
||||
sendToServer(s, true);
|
||||
Log::verbose("GameProtocol", "Item confirmation with t %d sent to server",
|
||||
time_of_last_event);
|
||||
} // handleItemUpdate
|
||||
#endif
|
||||
// ----------------------------------------------------------------------------
|
||||
#ifdef XX
|
||||
void GameProtocol::addEventToItemState(int ticks, uint16_t item_id,
|
||||
uint8_t kart_id)
|
||||
{
|
||||
//
|
||||
|
||||
NetworkString *s = getNetworkString(sizeof(uint8_t));
|
||||
|
||||
|
||||
} // addEventToItemState
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#endif
|
@ -40,6 +40,8 @@ private:
|
||||
/** The type of game events to be forwarded to the server. */
|
||||
enum { GP_CONTROLLER_ACTION,
|
||||
GP_STATE,
|
||||
GP_ITEM_UPDATE,
|
||||
GP_ITEM_CONFIRMATION,
|
||||
GP_ADJUST_TIME
|
||||
};
|
||||
|
||||
@ -68,6 +70,7 @@ private:
|
||||
void handleControllerAction(Event *event);
|
||||
void handleState(Event *event);
|
||||
void handleAdjustTime(Event *event);
|
||||
void handleItemEventConfirmation(Event *event);
|
||||
static std::weak_ptr<GameProtocol> m_game_protocol;
|
||||
public:
|
||||
GameProtocol();
|
||||
@ -82,9 +85,12 @@ public:
|
||||
void addState(BareNetworkString *buffer);
|
||||
void sendState();
|
||||
void adjustTimeForClient(STKPeer *peer, int ticks);
|
||||
void addItemEvent(int ticks, int item_id, int kart_id = -1);
|
||||
void sendItemEventConfirmation(int ticks);
|
||||
|
||||
virtual void undo(BareNetworkString *buffer) OVERRIDE;
|
||||
virtual void rewind(BareNetworkString *buffer) OVERRIDE;
|
||||
void GameProtocol::sendUpdate();
|
||||
// ------------------------------------------------------------------------
|
||||
virtual void setup() OVERRIDE {};
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -59,18 +59,3 @@ void RaceEventManager::kartFinishedRace(AbstractKart *kart, float time)
|
||||
if (auto game_events_protocol = m_game_events_protocol.lock())
|
||||
game_events_protocol->kartFinishedRace(kart, time);
|
||||
} // kartFinishedRace
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Called from the item manager on a server. It triggers a notification to
|
||||
* all clients in the GameEventsProtocol.
|
||||
* \param item The item that was collected.
|
||||
* \param kart The kart that collected the item.
|
||||
*/
|
||||
void RaceEventManager::collectedItem(Item *item, AbstractKart *kart)
|
||||
{
|
||||
// this is only called in the server
|
||||
assert(NetworkConfig::get()->isServer());
|
||||
if (auto game_events_protocol = m_game_events_protocol.lock())
|
||||
game_events_protocol->collectedItem(item, kart);
|
||||
} // collectedItem
|
||||
|
||||
|
@ -69,8 +69,6 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
bool isRaceOver();
|
||||
// ------------------------------------------------------------------------
|
||||
void collectedItem(Item *item, AbstractKart *kart);
|
||||
// ------------------------------------------------------------------------
|
||||
void kartFinishedRace(AbstractKart *kart, float time);
|
||||
|
||||
};
|
||||
|
@ -57,7 +57,7 @@ RewindInfoState::RewindInfoState(int ticks, BareNetworkString *buffer,
|
||||
* again to reach current time. It will call rewindToState().
|
||||
* if the state is a confirmed state.
|
||||
*/
|
||||
void RewindInfoState::rewind()
|
||||
void RewindInfoState::restore()
|
||||
{
|
||||
RewindManager::get()->restoreState(m_buffer);
|
||||
} // rewind
|
||||
|
@ -56,13 +56,15 @@ private:
|
||||
public:
|
||||
RewindInfo(int ticks, bool is_confirmed);
|
||||
|
||||
void setTicks(int ticks);
|
||||
|
||||
/** Called when going back in time to undo any rewind information. */
|
||||
virtual void undo() = 0;
|
||||
|
||||
/** This is called to restore a state before replaying the events. */
|
||||
virtual void restore() = 0;
|
||||
/** This is called while going forwards in time again to reach current
|
||||
* time. */
|
||||
virtual void rewind() = 0;
|
||||
void setTicks(int ticks);
|
||||
* time. */
|
||||
virtual void replay() = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual ~RewindInfo() { }
|
||||
// ------------------------------------------------------------------------
|
||||
@ -95,7 +97,7 @@ public:
|
||||
RewindInfoState(int ticks, BareNetworkString *buffer,
|
||||
bool is_confirmed);
|
||||
virtual ~RewindInfoState() { delete m_buffer; };
|
||||
virtual void rewind();
|
||||
virtual void restore();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a pointer to the state buffer. */
|
||||
@ -109,6 +111,13 @@ public:
|
||||
{
|
||||
// Nothing being done in case of an undo that goes further back
|
||||
} // undo
|
||||
// ------------------------------------------------------------------------
|
||||
/** Called when rewinding from a past state to 'now'. This should never
|
||||
* be called for a state (a state calles restore()). */
|
||||
virtual void replay()
|
||||
{
|
||||
assert(false);
|
||||
} // replay
|
||||
}; // class RewindInfoState
|
||||
|
||||
// ============================================================================
|
||||
@ -128,6 +137,9 @@ public:
|
||||
delete m_buffer;
|
||||
} // ~RewindInfoEvent
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** An event is never 'restored', it is only rewound. */
|
||||
void restore() {}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isEvent() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
@ -142,7 +154,7 @@ public:
|
||||
/** This is called while going forwards in time again to reach current
|
||||
* time. Calls rewind() in the event rewinder.
|
||||
*/
|
||||
virtual void rewind()
|
||||
virtual void replay()
|
||||
{
|
||||
// Make sure to reset the buffer so we read from the beginning
|
||||
m_buffer->reset();
|
||||
|
@ -207,14 +207,13 @@ void RewindManager::restoreState(BareNetworkString *data)
|
||||
{
|
||||
data->reset();
|
||||
int index = 0;
|
||||
//AllRewinder::const_iterator rewinder;
|
||||
for (auto rewinder = m_all_rewinder.begin(); rewinder != m_all_rewinder.end();
|
||||
++rewinder)
|
||||
{
|
||||
uint16_t count = data->getUInt16();
|
||||
|
||||
for (auto rewinder = m_all_rewinder.begin();
|
||||
rewinder != m_all_rewinder.end(); ++rewinder)
|
||||
{ uint16_t count = data->getUInt16();
|
||||
if (count > 0)
|
||||
{
|
||||
(*rewinder)->rewindToState(data);
|
||||
(*rewinder)->restoreState(data, count);
|
||||
}
|
||||
} // for all rewinder
|
||||
} // restoreState
|
||||
@ -339,9 +338,9 @@ void RewindManager::rewindTo(int rewind_ticks, int now_ticks)
|
||||
// -----------------------------------------
|
||||
// A loop in case that we should split states into several smaller ones:
|
||||
while (current && current->getTicks() == exact_rewind_ticks &&
|
||||
current->isState() )
|
||||
current->isState() )
|
||||
{
|
||||
current->rewind();
|
||||
current->restore();
|
||||
m_rewind_queue.next();
|
||||
current = m_rewind_queue.getCurrent();
|
||||
}
|
||||
|
@ -163,6 +163,13 @@ public:
|
||||
bool isRewinding() const { return m_is_rewinding; }
|
||||
// ------------------------------------------------------------------------
|
||||
int getNotRewoundWorldTicks() const { return m_not_rewound_ticks; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time of the latest confirmed state. */
|
||||
int getLatestConfirmedState() const
|
||||
{
|
||||
return m_rewind_queue.getLatestConfirmedState();
|
||||
}
|
||||
|
||||
}; // RewindManager
|
||||
|
||||
|
||||
|
@ -356,7 +356,7 @@ void RewindQueue::replayAllEvents(int ticks)
|
||||
while ( hasMoreRewindInfo() && (*m_current)->getTicks() == ticks )
|
||||
{
|
||||
if ((*m_current)->isEvent())
|
||||
(*m_current)->rewind();
|
||||
(*m_current)->replay();
|
||||
m_current++;
|
||||
} // while current->getTIcks == ticks
|
||||
|
||||
@ -380,10 +380,10 @@ void RewindQueue::unitTesting()
|
||||
class DummyRewinder : public Rewinder, public EventRewinder
|
||||
{
|
||||
public:
|
||||
BareNetworkString* saveState() const { return NULL; }
|
||||
BareNetworkString* saveState() { return NULL; }
|
||||
virtual void undoEvent(BareNetworkString *s) {}
|
||||
virtual void rewindToEvent(BareNetworkString *s) {}
|
||||
virtual void rewindToState(BareNetworkString *s) {}
|
||||
virtual void restoreState(BareNetworkString *s, int count) {}
|
||||
virtual void undoState(BareNetworkString *s) {}
|
||||
virtual void undo(BareNetworkString *s) {}
|
||||
virtual void rewind(BareNetworkString *s) {}
|
||||
|
@ -79,6 +79,12 @@ public:
|
||||
bool hasMoreRewindInfo() const;
|
||||
int undoUntil(int undo_ticks);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the time of the latest confirmed state. */
|
||||
int getLatestConfirmedState() const
|
||||
{
|
||||
return m_latest_confirmed_state_time;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Sets the current element to be the next one and returns the next
|
||||
* RewindInfo element. */
|
||||
|
@ -49,7 +49,7 @@ public:
|
||||
* \param[out] buffer The address of the memory buffer with the state.
|
||||
* \return Size of the buffer, or -1 in case of an error.
|
||||
*/
|
||||
virtual BareNetworkString* saveState() const = 0;
|
||||
virtual BareNetworkString* saveState() = 0;
|
||||
|
||||
/** Called when an event needs to be undone. This is called while going
|
||||
* backwards for rewinding - all stored events will get an 'undo' call.
|
||||
@ -65,7 +65,7 @@ public:
|
||||
* rewind, i.e. when going forward in time again, and only for confirmed
|
||||
* states.
|
||||
*/
|
||||
virtual void rewindToState(BareNetworkString *buffer) = 0;
|
||||
virtual void restoreState(BareNetworkString *buffer, int count) = 0;
|
||||
|
||||
/** Undo the effects of the given state, but do not rewind to that
|
||||
* state (which is done by rewindTo). This is called while going
|
||||
|
@ -52,11 +52,13 @@
|
||||
#include "io/xml_node.hpp"
|
||||
#include "items/item.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "items/network_item_manager.hpp"
|
||||
#include "karts/abstract_kart.hpp"
|
||||
#include "karts/kart_properties.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "modes/easter_egg_hunt.hpp"
|
||||
#include "modes/profile_world.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "physics/physical_object.hpp"
|
||||
#include "physics/physics.hpp"
|
||||
#include "physics/triangle_mesh.hpp"
|
||||
@ -1805,7 +1807,10 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
|
||||
else if ((m_is_arena || m_is_soccer) && !m_is_cutscene && m_has_navmesh)
|
||||
loadArenaGraph(*root);
|
||||
|
||||
ItemManager::create();
|
||||
if (NetworkConfig::get()->isNetworking())
|
||||
NetworkItemManager::create();
|
||||
else
|
||||
ItemManager::create();
|
||||
|
||||
// Set the default start positions. Node that later the default
|
||||
// positions can still be overwritten.
|
||||
|
Loading…
Reference in New Issue
Block a user