Merge remote-tracking branch 'origin/network-item-debugging'

This commit is contained in:
Benau 2018-09-28 23:39:04 +08:00
commit abd3a79526
14 changed files with 196 additions and 116 deletions

View File

@ -37,6 +37,25 @@
#include <ISceneManager.h>
// ----------------------------------------------------------------------------
/** 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;
m_used_up_counter = -1;
if (owner)
setDeactivatedTicks(stk_config->time2Ticks(1.5f));
else
setDeactivatedTicks(0);
} // ItemState(ItemType)
// ------------------------------------------------------------------------
/** Sets the disappear counter depending on type. */
void ItemState::setDisappearCounter()
@ -52,9 +71,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)
{
@ -107,12 +140,17 @@ 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)
: ItemState(type)
scene::IMesh* mesh, scene::IMesh* lowres_mesh,
const AbstractKart *owner, bool is_predicted)
: ItemState(type, owner)
{
assert(type != ITEM_TRIGGER); // use other constructor for that
@ -190,7 +228,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
@ -334,17 +371,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.

View File

@ -122,35 +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. */
const AbstractKart *m_previous_owner;
protected:
friend class ItemManager;
friend class NetworkItemManager;
// ------------------------------------------------------------------------
virtual 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, 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()
@ -166,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.
@ -329,19 +306,18 @@ 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 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
@ -352,7 +328,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
@ -373,7 +349,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);

View File

@ -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

View File

@ -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

View File

@ -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
@ -286,9 +288,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 +318,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)
@ -354,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

View File

@ -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 areItemSwitched() { return (m_switch_ticks > 0); }
bool randomItemsForArena(const AlignedArray<btTransform>& pos);

View File

@ -95,17 +95,18 @@ 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())
{
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
{
@ -142,7 +143,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 +238,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.
*/
@ -267,6 +268,7 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
// From here the replay can happen.
// 1) Remove predicted items:
// --------------------------
for (unsigned int i=0; i<m_all_items.size(); i++)
{
Item *item = m_all_items[i];
@ -274,20 +276,22 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
{
deleteItem(item);
}
}
} // for i in m_all_items
// 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)
{
// 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
// 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
@ -297,13 +301,35 @@ 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);
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->setTicksForRewind(iei.getTicks()); // Set time of event
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
if (m_confirmed_state[index]->isUsedUp())
{
delete m_confirmed_state[index];
@ -312,9 +338,9 @@ 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);
AbstractKart *kart = world->getKart(iei.getKartId());
ItemState *is = new ItemState(iei.getNewItemType(), kart,
iei.getIndex() );
is->initItem(iei.getNewItemType(), iei.getXYZ());
if (m_confirmed_state.size() <= is->getItemId())
{
@ -325,29 +351,34 @@ 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();
} // 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())
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);
// Restore the state to the current world time:
// ============================================
// 3. Restore the state to the current world time:
// ===============================================
for(unsigned int i=0; i<m_confirmed_state.size(); i++)
{
Item *item = m_all_items[i];
Item *item = i < m_all_items.size() ? m_all_items[i] : NULL;
const ItemState *is = m_confirmed_state[i];
if (is && item)
*(ItemState*)item = *is;
@ -356,18 +387,33 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
Vec3 xyz = is->getXYZ();
Item *item_new = dropNewItem(is->getType(), is->getPreviousOwner(),
&xyz);
item_new->setPredicted(false);
item_new->setItemId(i);
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->setDeactivatedTicks(is->getDeactivatedTicks());
*((ItemState*)m_all_items[i]) = *is;
}
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

View File

@ -73,7 +73,7 @@ public:
virtual void reset() OVERRIDE;
virtual void setItemConfirmationTime(std::weak_ptr<STKPeer> 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<std::string>* ru)

View File

@ -561,11 +561,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).

View File

@ -1554,7 +1554,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(),
@ -1575,8 +1575,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

View File

@ -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;

View File

@ -66,7 +66,7 @@ public:
virtual void getKartsDisplayInfo(
std::vector<RaceGUIBase::KartIconDisplayInfo> *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; }

View File

@ -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; }
// ------------------------------------------------------------------------

View File

@ -154,8 +154,27 @@ void RewindManager::saveState()
m_overall_state_size = 0;
std::vector<std::string> 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;