Refresh history code in GameMVC

This commit is contained in:
Tamás Bálint Misius 2021-07-24 13:50:16 +02:00
parent 483fde0698
commit ea07244119
No known key found for this signature in database
GPG Key ID: 5B472A12F6ECA9F2
7 changed files with 161 additions and 136 deletions

View File

@ -16,6 +16,12 @@
#ifndef TPT_COMPAT_H
#define TPT_COMPAT_H
#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>
//some compatibility stuff for non-standard compilers
#if defined(WIN) && !defined(strcasecmp)
#define strcasecmp stricmp
@ -31,4 +37,39 @@ typedef unsigned short Uint16;
# define NULL 0
#endif
// From https://stackoverflow.com/questions/17902405/how-to-implement-make-unique-function-in-c11
#if !(__cplusplus >= 201402L || defined(_MSC_VER))
namespace std {
template<class T> struct _Unique_if {
typedef unique_ptr<T> _Single_object;
};
template<class T> struct _Unique_if<T[]> {
typedef unique_ptr<T[]> _Unknown_bound;
};
template<class T, size_t N> struct _Unique_if<T[N]> {
typedef void _Known_bound;
};
template<class T, class... Args>
typename _Unique_if<T>::_Single_object
make_unique(Args&&... args) {
return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
template<class T>
typename _Unique_if<T>::_Unknown_bound
make_unique(size_t n) {
typedef typename remove_extent<T>::type U;
return unique_ptr<T>(new U[n]());
}
template<class T, class... Args>
typename _Unique_if<T>::_Known_bound
make_unique(Args&&...) = delete;
}
#endif
#endif

View File

@ -146,12 +146,6 @@ GameController::~GameController()
{
delete *iter;
}
//deleted here because it refuses to be deleted when deleted from gameModel even with the same code
std::deque<Snapshot*> history = gameModel->GetHistory();
for(std::deque<Snapshot*>::iterator iter = history.begin(), end = history.end(); iter != end; ++iter)
{
delete *iter;
}
std::vector<QuickOption*> quickOptions = gameModel->GetQuickOptions();
for(std::vector<QuickOption*>::iterator iter = quickOptions.begin(), end = quickOptions.end(); iter != end; ++iter)
{
@ -171,75 +165,44 @@ GameController::~GameController()
void GameController::HistoryRestore()
{
std::deque<Snapshot*> history = gameModel->GetHistory();
if (!history.size())
return;
unsigned int historyPosition = gameModel->GetHistoryPosition();
unsigned int newHistoryPosition = std::max((int)historyPosition-1, 0);
// When undoing, save the current state as a final redo
// This way ctrl+y will always bring you back to the point right before your last ctrl+z
if (historyPosition == history.size())
if (!gameModel->HistoryCanRestore())
{
Snapshot * newSnap = gameModel->GetSimulation()->CreateSnapshot();
if (newSnap)
newSnap->Authors = Client::Ref().GetAuthorInfo();
delete gameModel->GetRedoHistory();
gameModel->SetRedoHistory(newSnap);
return;
}
Snapshot * snap = history[newHistoryPosition];
gameModel->GetSimulation()->Restore(*snap);
Client::Ref().OverwriteAuthorInfo(snap->Authors);
gameModel->SetHistory(history);
gameModel->SetHistoryPosition(newHistoryPosition);
// * When undoing for the first time since the last call to HistorySnapshot, save the current state.
// Ctrl+Y needs this in order to bring you back to the point right before your last Ctrl+Z, because
// the last history entry is what this Ctrl+Z brings you back to, not the current state.
if (!beforeRestore)
{
beforeRestore = gameModel->GetSimulation()->CreateSnapshot();
beforeRestore->Authors = Client::Ref().GetAuthorInfo();
}
gameModel->HistoryRestore();
auto &current = *gameModel->HistoryCurrent();
gameModel->GetSimulation()->Restore(current);
Client::Ref().OverwriteAuthorInfo(current.Authors);
}
void GameController::HistorySnapshot()
{
std::deque<Snapshot*> history = gameModel->GetHistory();
unsigned int historyPosition = gameModel->GetHistoryPosition();
Snapshot * newSnap = gameModel->GetSimulation()->CreateSnapshot();
if (newSnap)
{
newSnap->Authors = Client::Ref().GetAuthorInfo();
while (historyPosition < history.size())
{
Snapshot * snap = history.back();
history.pop_back();
delete snap;
}
if (history.size() >= gameModel->GetUndoHistoryLimit())
{
Snapshot * snap = history.front();
history.pop_front();
delete snap;
if (historyPosition > history.size())
historyPosition--;
}
history.push_back(newSnap);
gameModel->SetHistory(history);
gameModel->SetHistoryPosition(std::min((size_t)historyPosition+1, history.size()));
delete gameModel->GetRedoHistory();
gameModel->SetRedoHistory(NULL);
}
beforeRestore.reset();
gameModel->HistoryPush(gameModel->GetSimulation()->CreateSnapshot());
}
void GameController::HistoryForward()
{
std::deque<Snapshot*> history = gameModel->GetHistory();
if (!history.size())
if (!gameModel->HistoryCanForward())
{
return;
unsigned int historyPosition = gameModel->GetHistoryPosition();
unsigned int newHistoryPosition = std::min((size_t)historyPosition+1, history.size());
Snapshot *snap;
if (newHistoryPosition == history.size())
snap = gameModel->GetRedoHistory();
else
snap = history[newHistoryPosition];
if (!snap)
return;
gameModel->GetSimulation()->Restore(*snap);
Client::Ref().OverwriteAuthorInfo(snap->Authors);
gameModel->SetHistoryPosition(newHistoryPosition);
}
gameModel->HistoryForward();
auto &current = gameModel->HistoryCurrent() ? *gameModel->HistoryCurrent() : *beforeRestore;
gameModel->GetSimulation()->Restore(current);
Client::Ref().OverwriteAuthorInfo(current.Authors);
if (&current == beforeRestore.get())
{
beforeRestore.reset();
}
}
GameView * GameController::GetView()

View File

@ -4,6 +4,7 @@
#include <vector>
#include <utility>
#include <memory>
#include "client/ClientListener.h"
@ -20,6 +21,7 @@ class SaveFile;
class Notification;
class GameModel;
class GameView;
class Snapshot;
class OptionsController;
class LocalBrowserController;
class SearchController;
@ -51,6 +53,7 @@ private:
OptionsController * options;
CommandInterface * commandInterface;
std::vector<DebugInfo*> debugInfo;
std::unique_ptr<Snapshot> beforeRestore;
unsigned int debugFlags;
void OpenSaveDone();

View File

@ -20,6 +20,7 @@
#include "client/SaveFile.h"
#include "client/SaveInfo.h"
#include "common/Platform.h"
#include "common/tpt-compat.h"
#include "graphics/Renderer.h"
#include "simulation/Air.h"
#include "simulation/GOLString.h"
@ -42,7 +43,6 @@ GameModel::GameModel():
currentFile(NULL),
currentUser(0, ""),
toolStrength(1.0f),
redoHistory(NULL),
historyPosition(0),
activeColourPreset(0),
colourSelector(false),
@ -196,7 +196,6 @@ GameModel::~GameModel()
delete clipboard;
delete currentSave;
delete currentFile;
delete redoHistory;
//if(activeTools)
// delete[] activeTools;
}
@ -551,34 +550,51 @@ int GameModel::GetDecoSpace()
return this->decoSpace;
}
std::deque<Snapshot*> GameModel::GetHistory()
const Snapshot *GameModel::HistoryCurrent() const
{
return history;
if (historyPosition > history.size())
{
return nullptr;
}
return historyCurrent.get();
}
unsigned int GameModel::GetHistoryPosition()
bool GameModel::HistoryCanRestore() const
{
return historyPosition;
return historyPosition > 0U;
}
void GameModel::SetHistory(std::deque<Snapshot*> newHistory)
void GameModel::HistoryRestore()
{
history = newHistory;
historyPosition -= 1U;
historyCurrent = std::make_unique<Snapshot>(*history[historyPosition]);
}
void GameModel::SetHistoryPosition(unsigned int newHistoryPosition)
bool GameModel::HistoryCanForward() const
{
historyPosition = newHistoryPosition;
return historyPosition < history.size();
}
Snapshot * GameModel::GetRedoHistory()
void GameModel::HistoryForward()
{
return redoHistory;
historyPosition += 1U;
historyCurrent = historyPosition < history.size() ? std::make_unique<Snapshot>(*history[historyPosition]) : nullptr;
}
void GameModel::SetRedoHistory(Snapshot * redo)
void GameModel::HistoryPush(std::unique_ptr<Snapshot> last)
{
redoHistory = redo;
while (historyPosition < history.size())
{
history.pop_back();
}
history.push_back(std::move(last));
historyPosition += 1U;
historyCurrent.reset();
while (undoHistoryLimit < history.size())
{
history.pop_front();
historyPosition -= 1U;
}
}
unsigned int GameModel::GetUndoHistoryLimit()

View File

@ -4,6 +4,7 @@
#include <vector>
#include <deque>
#include <memory>
#include "gui/interface/Colour.h"
#include "client/User.h"
@ -64,8 +65,8 @@ private:
Tool * regularToolset[4];
User currentUser;
float toolStrength;
std::deque<Snapshot*> history;
Snapshot *redoHistory;
std::deque<std::unique_ptr<Snapshot>> history;
std::unique_ptr<Snapshot> historyCurrent;
unsigned int historyPosition;
unsigned int undoHistoryLimit;
bool mouseClickRequired;
@ -141,12 +142,12 @@ public:
void BuildBrushList();
void BuildQuickOptionMenu(GameController * controller);
std::deque<Snapshot*> GetHistory();
unsigned int GetHistoryPosition();
void SetHistory(std::deque<Snapshot*> newHistory);
void SetHistoryPosition(unsigned int newHistoryPosition);
Snapshot * GetRedoHistory();
void SetRedoHistory(Snapshot * redo);
const Snapshot *HistoryCurrent() const;
bool HistoryCanRestore() const;
void HistoryRestore();
bool HistoryCanForward() const;
void HistoryForward();
void HistoryPush(std::unique_ptr<Snapshot> last);
unsigned int GetUndoHistoryLimit();
void SetUndoHistoryLimit(unsigned int undoHistoryLimit_);

View File

@ -562,67 +562,67 @@ void Simulation::SaveSimOptions(GameSave * gameSave)
gameSave->aheatEnable = aheat_enable;
}
Snapshot * Simulation::CreateSnapshot()
std::unique_ptr<Snapshot> Simulation::CreateSnapshot()
{
Snapshot * snap = new Snapshot();
snap->AirPressure.insert(snap->AirPressure.begin(), &pv[0][0], &pv[0][0]+((XRES/CELL)*(YRES/CELL)));
snap->AirVelocityX.insert(snap->AirVelocityX.begin(), &vx[0][0], &vx[0][0]+((XRES/CELL)*(YRES/CELL)));
snap->AirVelocityY.insert(snap->AirVelocityY.begin(), &vy[0][0], &vy[0][0]+((XRES/CELL)*(YRES/CELL)));
snap->AmbientHeat.insert(snap->AmbientHeat.begin(), &hv[0][0], &hv[0][0]+((XRES/CELL)*(YRES/CELL)));
snap->Particles.insert(snap->Particles.begin(), parts, parts+parts_lastActiveIndex+1);
snap->PortalParticles.insert(snap->PortalParticles.begin(), &portalp[0][0][0], &portalp[CHANNELS-1][8-1][80-1]);
snap->WirelessData.insert(snap->WirelessData.begin(), &wireless[0][0], &wireless[CHANNELS-1][2-1]);
snap->GravVelocityX.insert(snap->GravVelocityX.begin(), gravx, gravx+((XRES/CELL)*(YRES/CELL)));
snap->GravVelocityY.insert(snap->GravVelocityY.begin(), gravy, gravy+((XRES/CELL)*(YRES/CELL)));
snap->GravValue.insert(snap->GravValue.begin(), gravp, gravp+((XRES/CELL)*(YRES/CELL)));
snap->GravMap.insert(snap->GravMap.begin(), gravmap, gravmap+((XRES/CELL)*(YRES/CELL)));
snap->BlockMap.insert(snap->BlockMap.begin(), &bmap[0][0], &bmap[0][0]+((XRES/CELL)*(YRES/CELL)));
snap->ElecMap.insert(snap->ElecMap.begin(), &emap[0][0], &emap[0][0]+((XRES/CELL)*(YRES/CELL)));
snap->FanVelocityX.insert(snap->FanVelocityX.begin(), &fvx[0][0], &fvx[0][0]+((XRES/CELL)*(YRES/CELL)));
snap->FanVelocityY.insert(snap->FanVelocityY.begin(), &fvy[0][0], &fvy[0][0]+((XRES/CELL)*(YRES/CELL)));
snap->stickmen.push_back(player2);
snap->stickmen.push_back(player);
snap->stickmen.insert(snap->stickmen.begin(), &fighters[0], &fighters[MAX_FIGHTERS]);
auto snap = std::make_unique<Snapshot>();
snap->AirPressure .insert (snap->AirPressure .begin(), &pv [0][0] , &pv [0][0] + ((XRES / CELL) * (YRES / CELL)));
snap->AirVelocityX .insert (snap->AirVelocityX .begin(), &vx [0][0] , &vx [0][0] + ((XRES / CELL) * (YRES / CELL)));
snap->AirVelocityY .insert (snap->AirVelocityY .begin(), &vy [0][0] , &vy [0][0] + ((XRES / CELL) * (YRES / CELL)));
snap->AmbientHeat .insert (snap->AmbientHeat .begin(), &hv [0][0] , &hv [0][0] + ((XRES / CELL) * (YRES / CELL)));
snap->BlockMap .insert (snap->BlockMap .begin(), &bmap[0][0] , &bmap[0][0] + ((XRES / CELL) * (YRES / CELL)));
snap->ElecMap .insert (snap->ElecMap .begin(), &emap[0][0] , &emap[0][0] + ((XRES / CELL) * (YRES / CELL)));
snap->FanVelocityX .insert (snap->FanVelocityX .begin(), &fvx [0][0] , &fvx [0][0] + ((XRES / CELL) * (YRES / CELL)));
snap->FanVelocityY .insert (snap->FanVelocityY .begin(), &fvy [0][0] , &fvy [0][0] + ((XRES / CELL) * (YRES / CELL)));
snap->GravVelocityX .insert (snap->GravVelocityX .begin(), &gravx [0] , &gravx [0] + ((XRES / CELL) * (YRES / CELL)));
snap->GravVelocityY .insert (snap->GravVelocityY .begin(), &gravy [0] , &gravy [0] + ((XRES / CELL) * (YRES / CELL)));
snap->GravValue .insert (snap->GravValue .begin(), &gravp [0] , &gravp [0] + ((XRES / CELL) * (YRES / CELL)));
snap->GravMap .insert (snap->GravMap .begin(), &gravmap[0] , &gravmap[0] + ((XRES / CELL) * (YRES / CELL)));
snap->Particles .insert (snap->Particles .begin(), &parts [0] , &parts[parts_lastActiveIndex + 1] );
snap->PortalParticles.insert (snap->PortalParticles.begin(), &portalp[0][0][0], &portalp [CHANNELS - 1][8 - 1][80 - 1] );
snap->WirelessData .insert (snap->WirelessData .begin(), &wireless[0][0] , &wireless[CHANNELS - 1][2 - 1] );
snap->stickmen .insert (snap->stickmen .begin(), &fighters[0] , &fighters[MAX_FIGHTERS] );
snap->stickmen .push_back(player2);
snap->stickmen .push_back(player);
snap->signs = signs;
return snap;
}
void Simulation::Restore(const Snapshot & snap)
void Simulation::Restore(const Snapshot &snap)
{
parts_lastActiveIndex = NPART-1;
std::fill(elementCount, elementCount+PT_NUM, 0);
std::fill(elementCount, elementCount + PT_NUM, 0);
elementRecount = true;
force_stacking_check = true;
std::copy(snap.AirPressure.begin(), snap.AirPressure.end(), &pv[0][0]);
std::copy(snap.AirVelocityX.begin(), snap.AirVelocityX.end(), &vx[0][0]);
std::copy(snap.AirVelocityY.begin(), snap.AirVelocityY.end(), &vy[0][0]);
std::copy(snap.AmbientHeat.begin(), snap.AmbientHeat.end(), &hv[0][0]);
for (int i = 0; i < NPART; i++)
parts[i].type = 0;
std::copy(snap.Particles.begin(), snap.Particles.end(), parts);
parts_lastActiveIndex = NPART-1;
air->RecalculateBlockAirMaps();
RecalcFreeParticles(false);
std::copy(snap.PortalParticles.begin(), snap.PortalParticles.end(), &portalp[0][0][0]);
std::copy(snap.WirelessData.begin(), snap.WirelessData.end(), &wireless[0][0]);
for (auto &part : parts)
{
part.type = 0;
}
std::copy(snap.AirPressure .begin(), snap.AirPressure .end(), &pv[0][0] );
std::copy(snap.AirVelocityX .begin(), snap.AirVelocityX .end(), &vx[0][0] );
std::copy(snap.AirVelocityY .begin(), snap.AirVelocityY .end(), &vy[0][0] );
std::copy(snap.AmbientHeat .begin(), snap.AmbientHeat .end(), &hv[0][0] );
std::copy(snap.BlockMap .begin(), snap.BlockMap .end(), &bmap[0][0] );
std::copy(snap.ElecMap .begin(), snap.ElecMap .end(), &emap[0][0] );
std::copy(snap.FanVelocityX .begin(), snap.FanVelocityX .end(), &fvx[0][0] );
std::copy(snap.FanVelocityY .begin(), snap.FanVelocityY .end(), &fvy[0][0] );
if (grav->IsEnabled())
{
grav->Clear();
std::copy(snap.GravVelocityX.begin(), snap.GravVelocityX.end(), gravx);
std::copy(snap.GravVelocityY.begin(), snap.GravVelocityY.end(), gravy);
std::copy(snap.GravValue.begin(), snap.GravValue.end(), gravp);
std::copy(snap.GravMap.begin(), snap.GravMap.end(), gravmap);
std::copy(snap.GravVelocityX.begin(), snap.GravVelocityX.end(), &gravx [0] );
std::copy(snap.GravVelocityY.begin(), snap.GravVelocityY.end(), &gravy [0] );
std::copy(snap.GravValue .begin(), snap.GravValue .end(), &gravp [0] );
std::copy(snap.GravMap .begin(), snap.GravMap .end(), &gravmap[0] );
}
gravWallChanged = true;
std::copy(snap.BlockMap.begin(), snap.BlockMap.end(), &bmap[0][0]);
std::copy(snap.ElecMap.begin(), snap.ElecMap.end(), &emap[0][0]);
std::copy(snap.FanVelocityX.begin(), snap.FanVelocityX.end(), &fvx[0][0]);
std::copy(snap.FanVelocityY.begin(), snap.FanVelocityY.end(), &fvy[0][0]);
std::copy(snap.stickmen.begin(), snap.stickmen.end()-2, &fighters[0]);
player = snap.stickmen[snap.stickmen.size()-1];
player2 = snap.stickmen[snap.stickmen.size()-2];
std::copy(snap.Particles .begin(), snap.Particles .end(), &parts[0] );
std::copy(snap.PortalParticles.begin(), snap.PortalParticles.end(), &portalp[0][0][0]);
std::copy(snap.WirelessData .begin(), snap.WirelessData .end(), &wireless[0][0] );
std::copy(snap.stickmen .begin(), snap.stickmen.end() - 2 , &fighters[0] );
player = snap.stickmen[snap.stickmen.size() - 1];
player2 = snap.stickmen[snap.stickmen.size() - 2];
signs = snap.signs;
parts_lastActiveIndex = NPART - 1;
air->RecalculateBlockAirMaps();
RecalcFreeParticles(false);
gravWallChanged = true;
}
void Simulation::clear_area(int area_x, int area_y, int area_w, int area_h)

View File

@ -6,6 +6,7 @@
#include <cstddef>
#include <vector>
#include <array>
#include <memory>
#include "Particle.h"
#include "Stickman.h"
@ -121,8 +122,8 @@ public:
void SaveSimOptions(GameSave * gameSave);
SimulationSample GetSample(int x, int y);
Snapshot * CreateSnapshot();
void Restore(const Snapshot & snap);
std::unique_ptr<Snapshot> CreateSnapshot();
void Restore(const Snapshot &snap);
int is_blocking(int t, int x, int y);
int is_boundary(int pt, int x, int y);