Use client prediction for item collection.

This commit is contained in:
hiker 2018-05-13 01:04:45 +10:00
parent d88ce3b3b6
commit af0495848a
4 changed files with 21 additions and 10 deletions

View File

@ -99,7 +99,7 @@ void NetworkItemManager::collectedItem(Item *item, AbstractKart *kart,
m_item_events.unlock();
ItemManager::collectedItem(item, kart, add_info);
}
else if (!RewindManager::get()->isRewinding())
else
{
// If we are predicting (i.e. not rewinding), the client
// predicts item collection:
@ -269,7 +269,6 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count)
{
Item *item = m_all_items[i];
const ItemState *is = m_confirmed_state[i];
item->setTicksTillReturn(is->getTicksTillReturn());
*(ItemState*)item = *is;
}

View File

@ -480,16 +480,25 @@ void Powerup::hitBonusBox(const Item &item, int add_info)
if(m_type == PowerupManager::POWERUP_RUBBERBALL)
powerup_manager->setBallCollectTicks(0);
World *world = World::getWorld();
// Check if two bouncing balls are collected less than getRubberBallTimer()
//seconds apart. If yes, then call getRandomPowerup again. If no, then break.
if (add_info<0)
{
for(int i=0; i<20; i++)
{
new_powerup = powerup_manager->getRandomPowerup(position, &n);
// Determine the item based on index and time - random enough for
// the player, and reduces network synchronisation overhead.
// Dividing the time by 10 does not really allow exploiting the
// non-random selection (e.g. by displaying which item is collecte
// where), since it's only around 83 ms - but it is bit more
// relaxed when client prediction should be a frame or so earlier.
int random_number = item.getItemId() + world->getTimeTicks()/10;
new_powerup =
powerup_manager->getRandomPowerup(position, &n, random_number);
if(new_powerup != PowerupManager::POWERUP_RUBBERBALL ||
( World::getWorld()->getTicksSinceStart() - powerup_manager->getBallCollectTicks()) >
RubberBall::getTicksBetweenRubberBalls() )
( world->getTicksSinceStart() - powerup_manager->getBallCollectTicks())
> RubberBall::getTicksBetweenRubberBalls() )
break;
}
}
@ -500,7 +509,7 @@ void Powerup::hitBonusBox(const Item &item, int add_info)
}
if(new_powerup == PowerupManager::POWERUP_RUBBERBALL)
powerup_manager->setBallCollectTicks(World::getWorld()->getTimeTicks());
powerup_manager->setBallCollectTicks(world->getTimeTicks());
// Always add a new powerup in ITEM_MODE_NEW (or if the kart
// doesn't have a powerup atm).

View File

@ -354,10 +354,13 @@ PowerupManager::PositionClass
* items depending on the weights defined. See updateWeightsForRace()
* \param pos Position of the kart (1<=pos<=number of karts) - ignored in
* case of a battle mode.
* \param n Number of times this item is given to the kart
* \param n Number of times this item is given to the kart.
* \param random_number A random number used to select the item. Important
* for networking to be able to reproduce item selection.
*/
PowerupManager::PowerupType PowerupManager::getRandomPowerup(unsigned int pos,
unsigned int *n)
unsigned int *n,
int random_number)
{
// Positions start with 1, while the index starts with 0 - so subtract 1
PositionClass pos_class =
@ -366,7 +369,7 @@ PowerupManager::PowerupType PowerupManager::getRandomPowerup(unsigned int pos,
(race_manager->isTutorialMode() ? POSITION_TUTORIAL_MODE :
m_position_to_class[pos-1]));
int random = rand()%m_powerups_for_position[pos_class].size();
int random = random_number%m_powerups_for_position[pos_class].size();
int i=m_powerups_for_position[pos_class][random];
if(i>=POWERUP_MAX)
{

View File

@ -139,7 +139,7 @@ public:
void LoadPowerup (PowerupType type, const XMLNode &node);
void updateWeightsForRace(unsigned int num_karts);
PowerupManager::PowerupType
getRandomPowerup(unsigned int pos, unsigned int *n);
getRandomPowerup(unsigned int pos, unsigned int *n, int random_number);
// ------------------------------------------------------------------------
/** Returns the icon(material) for a powerup. */
Material* getIcon(int type) const {return m_all_icons [type];}