diff --git a/src/items/flyable.cpp b/src/items/flyable.cpp index f0c4fbfa6..ed8cff4b9 100644 --- a/src/items/flyable.cpp +++ b/src/items/flyable.cpp @@ -721,6 +721,7 @@ void Flyable::handleUndoDestruction() hideNodeWhenUndoDestruction(); std::shared_ptr f = getShared(); std::string uid = f->getUniqueIdentity(); + projectile_manager->addDeletedUID(uid); RewindManager::get()->addRewindInfoEventFunction(new RewindInfoEventFunction(World::getWorld()->getTicksSinceStart(), /*undo_function*/[f, uid]() diff --git a/src/items/projectile_manager.cpp b/src/items/projectile_manager.cpp index b72724cd2..6b5ca3909 100644 --- a/src/items/projectile_manager.cpp +++ b/src/items/projectile_manager.cpp @@ -28,6 +28,7 @@ #include "items/rubber_ball.hpp" #include "karts/abstract_kart.hpp" #include "modes/world.hpp" +#include "network/dummy_rewinder.hpp" #include "network/rewind_manager.hpp" ProjectileManager *projectile_manager=0; @@ -48,6 +49,7 @@ void ProjectileManager::removeTextures() void ProjectileManager::cleanup() { m_active_projectiles.clear(); + m_deleted_projectiles.clear(); for(HitEffects::iterator i = m_active_hit_effects.begin(); i != m_active_hit_effects.end(); ++i) { @@ -262,8 +264,17 @@ std::shared_ptr return nullptr; AbstractKart* kart = World::getWorld()->getKart(world_id); char first_id = id[0][0]; - Log::debug("ProjectileManager", "Missed a firing event or locally deleted," - " add the flyable %s manually", uid.c_str()); + + auto it = m_deleted_projectiles.find(uid); + if (it != m_deleted_projectiles.end()) + { + Log::debug("ProjectileManager", "Flyable %s locally (early) deleted," + " use a dummy rewinder to skip.", uid.c_str()); + return std::make_shared(); + } + + Log::debug("ProjectileManager", + "Missed a firing event, add the flyable %s manually.", uid.c_str()); switch (first_id) { case 'B': diff --git a/src/items/projectile_manager.hpp b/src/items/projectile_manager.hpp index bfae1cdd6..b96bd0a87 100644 --- a/src/items/projectile_manager.hpp +++ b/src/items/projectile_manager.hpp @@ -21,6 +21,7 @@ #include #include +#include #include namespace irr @@ -50,6 +51,8 @@ private: * currently moving on the track. */ std::map > m_active_projectiles; + std::unordered_set m_deleted_projectiles; + /** All active hit effects, i.e. hit effects which are currently * being shown or have a sfx playing. */ HitEffects m_active_hit_effects; @@ -87,7 +90,9 @@ public: // ------------------------------------------------------------------------ void removeByUID(const std::string& uid) { m_active_projectiles.erase(uid); } - + // ------------------------------------------------------------------------ + void addDeletedUID(const std::string& uid) + { m_deleted_projectiles.insert(uid); } }; extern ProjectileManager *projectile_manager; diff --git a/src/network/dummy_rewinder.hpp b/src/network/dummy_rewinder.hpp new file mode 100644 index 000000000..34b374246 --- /dev/null +++ b/src/network/dummy_rewinder.hpp @@ -0,0 +1,53 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2018 SuperTuxKart-Team +// +// 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_DUMMY_REWINDER_HPP +#define HEADER_DUMMY_REWINDER_HPP + +#include "network/event_rewinder.hpp" +#include "network/network_string.hpp" +#include "network/rewinder.hpp" + +/** A dummy Rewinder and EventRewinder class for unit testing and handle undo + * destruction of projectiles. */ +class DummyRewinder : public Rewinder, public EventRewinder +{ +public: + // ------------------------------------------------------------------------- + BareNetworkString* saveState(std::vector* ru) { return NULL; } + // ------------------------------------------------------------------------- + virtual void undoEvent(BareNetworkString* s) {} + // ------------------------------------------------------------------------- + virtual void rewindToEvent(BareNetworkString* s) {} + // ------------------------------------------------------------------------- + virtual void restoreState(BareNetworkString* s, int count) + { s->skip(count); } + // ------------------------------------------------------------------------- + virtual void undoState(BareNetworkString *s) {} + // ------------------------------------------------------------------------- + virtual void undo(BareNetworkString *s) {} + // ------------------------------------------------------------------------- + virtual void rewind(BareNetworkString *s) {} + // ------------------------------------------------------------------------- + virtual void saveTransform() {} + // ------------------------------------------------------------------------- + virtual void computeError() {} +}; + +#endif + diff --git a/src/network/rewind_queue.cpp b/src/network/rewind_queue.cpp index b9475c4fb..4640e8d3c 100644 --- a/src/network/rewind_queue.cpp +++ b/src/network/rewind_queue.cpp @@ -20,6 +20,7 @@ #include "config/stk_config.hpp" #include "modes/world.hpp" +#include "network/dummy_rewinder.hpp" #include "network/network_config.hpp" #include "network/rewinder.hpp" #include "network/rewind_info.hpp" @@ -405,24 +406,6 @@ void RewindQueue::unitTesting() { // Some classes need the RewindManager (to register themselves with) RewindManager::create(); - - // A dummy Rewinder and EventRewinder class since some of the calls being - // tested here need an instance. - class DummyRewinder : public Rewinder, public EventRewinder - { - public: - BareNetworkString* saveState(std::vector* ru) - { return NULL; } - virtual void undoEvent(BareNetworkString *s) {} - virtual void rewindToEvent(BareNetworkString *s) {} - virtual void restoreState(BareNetworkString *s, int count) {} - virtual void undoState(BareNetworkString *s) {} - virtual void undo(BareNetworkString *s) {} - virtual void rewind(BareNetworkString *s) {} - virtual void saveTransform() {} - virtual void computeError() {} - DummyRewinder() : Rewinder() {} - }; auto dummy_rewinder = std::make_shared(); // First tests: add a state first, then an event, and make @@ -494,7 +477,8 @@ void RewindQueue::unitTesting() assert(!b1.hasMoreRewindInfo()); b1.addLocalEvent(NULL, NULL, true, 2); RewindInfo *ri = b1.getCurrent(); - assert(ri->getTicks() == 2); + if (ri->getTicks() != 2) + Log::fatal("RewindQueue", "ri->getTicks() != 2"); // 2) Make sure when adding an event at the same time as an existing // event, that m_current pooints to the first event, otherwise @@ -504,7 +488,8 @@ void RewindQueue::unitTesting() b1.addLocalEvent(NULL, NULL, true, 2); // Make sure that current was not modified, i.e. the new event at time // 2 was added at the end of the list: - assert(current_old == b1.m_current); + if (current_old != b1.m_current) + Log::fatal("RewindQueue", "current_old != b1.m_current"); // This should not trigger an exception, now current points to the // second event at the same time: