stk-code_catmod/src/items/network_item_manager.cpp

214 lines
7.3 KiB
C++
Raw Normal View History

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