From 6ceb51b4088131a2afa585d959a7a5add27dbe6c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= <lbphacker@gmail.com>
Date: Tue, 22 Aug 2023 23:31:38 +0200
Subject: [PATCH] Handle ptsave urls with GameController

---
 src/PowderToy.cpp                     | 35 ++++++---------------------
 src/gui/SavePreviewType.h             |  8 ++++++
 src/gui/game/GameController.cpp       |  8 +++---
 src/gui/game/GameController.h         |  3 ++-
 src/gui/preview/PreviewController.cpp | 10 ++++++--
 src/gui/preview/PreviewController.h   |  4 ++-
 src/gui/preview/PreviewModel.cpp      | 10 ++++++++
 src/gui/preview/PreviewModel.h        |  3 +++
 src/gui/preview/PreviewView.cpp       | 25 +++++++++++--------
 src/gui/search/SearchController.cpp   |  2 +-
 src/lua/LuaScriptInterface.cpp        |  2 +-
 src/lua/TPTScriptInterface.cpp        |  2 +-
 12 files changed, 64 insertions(+), 48 deletions(-)
 create mode 100644 src/gui/SavePreviewType.h

diff --git a/src/PowderToy.cpp b/src/PowderToy.cpp
index 2e991bcd0..07da70f6a 100644
--- a/src/PowderToy.cpp
+++ b/src/PowderToy.cpp
@@ -480,34 +480,15 @@ int Main(int argc, char *argv[])
 				{
 					std::cout << "Got Ptsave: id: " << saveIdPart << std::endl;
 				}
+				ByteString saveHistoryPart = "0";
+				if (auto split = saveIdPart.SplitBy('@'))
+				{
+					saveHistoryPart = split.After();
+					saveIdPart = split.Before();
+				}
 				int saveId = saveIdPart.ToNumber<int>();
-
-				auto getSave = std::make_unique<http::GetSaveRequest>(saveId, 0);
-				getSave->Start();
-				getSave->Wait();
-				std::unique_ptr<SaveInfo> newSave;
-				try
-				{
-					newSave = getSave->Finish();
-				}
-				catch (const http::RequestError &ex)
-				{
-					throw std::runtime_error("Could not load save info\n" + ByteString(ex.what()));
-				}
-				auto getSaveData = std::make_unique<http::GetSaveDataRequest>(saveId, 0);
-				getSaveData->Start();
-				getSaveData->Wait();
-				std::unique_ptr<GameSave> saveData;
-				try
-				{
-					saveData = std::make_unique<GameSave>(getSaveData->Finish());
-				}
-				catch (const http::RequestError &ex)
-				{
-					throw std::runtime_error("Could not load save\n" + ByteString(ex.what()));
-				}
-				newSave->SetGameSave(std::move(saveData));
-				gameController->LoadSave(std::move(newSave));
+				int saveHistory = saveHistoryPart.ToNumber<int>();
+				gameController->OpenSavePreview(saveId, saveHistory, savePreviewUrl);
 			}
 			catch (std::exception & e)
 			{
diff --git a/src/gui/SavePreviewType.h b/src/gui/SavePreviewType.h
new file mode 100644
index 000000000..67a1fdc3e
--- /dev/null
+++ b/src/gui/SavePreviewType.h
@@ -0,0 +1,8 @@
+#pragma once
+
+enum SavePreviewType
+{
+	savePreviewNormal,
+	savePreviewInstant,
+	savePreviewUrl,
+};
diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp
index c9c962db6..609e73755 100644
--- a/src/gui/game/GameController.cpp
+++ b/src/gui/game/GameController.cpp
@@ -543,7 +543,7 @@ bool GameController::MouseUp(int x, int y, unsigned button, MouseupReason reason
 						{
 							int saveID = str.Substr(3, si.first - 3).ToNumber<int>(true);
 							if (saveID)
-								OpenSavePreview(saveID, 0, false);
+								OpenSavePreview(saveID, 0, savePreviewNormal);
 						}
 						break;
 					case sign::Type::Thread:
@@ -1223,9 +1223,9 @@ void GameController::OpenSaveDone()
 	}
 }
 
-void GameController::OpenSavePreview(int saveID, int saveDate, bool instant)
+void GameController::OpenSavePreview(int saveID, int saveDate, SavePreviewType savePreviewType)
 {
-	activePreview = new PreviewController(saveID, saveDate, instant, [this] { OpenSaveDone(); }, nullptr);
+	activePreview = new PreviewController(saveID, saveDate, savePreviewType, [this] { OpenSaveDone(); }, nullptr);
 	ui::Engine::Ref().ShowWindow(activePreview->GetView());
 }
 
@@ -1233,7 +1233,7 @@ void GameController::OpenSavePreview()
 {
 	if(gameModel->GetSave())
 	{
-		activePreview = new PreviewController(gameModel->GetSave()->GetID(), 0, false, [this] { OpenSaveDone(); }, nullptr);
+		activePreview = new PreviewController(gameModel->GetSave()->GetID(), 0, savePreviewNormal, [this] { OpenSaveDone(); }, nullptr);
 		ui::Engine::Ref().ShowWindow(activePreview->GetView());
 	}
 }
diff --git a/src/gui/game/GameController.h b/src/gui/game/GameController.h
index d09b8e3f1..6a1ebeca6 100644
--- a/src/gui/game/GameController.h
+++ b/src/gui/game/GameController.h
@@ -3,6 +3,7 @@
 #include "client/StartupInfo.h"
 #include "gui/interface/Point.h"
 #include "gui/interface/Colour.h"
+#include "gui/SavePreviewType.h"
 #include "simulation/Sign.h"
 #include "simulation/Particle.h"
 #include "Misc.h"
@@ -135,7 +136,7 @@ public:
 	void OpenLogin();
 	void OpenProfile();
 	void OpenTags();
-	void OpenSavePreview(int saveID, int saveDate, bool instant);
+	void OpenSavePreview(int saveID, int saveDate, SavePreviewType savePreiviewType);
 	void OpenSavePreview();
 	void OpenLocalSaveWindow(bool asCurrent);
 	void OpenLocalBrowse();
diff --git a/src/gui/preview/PreviewController.cpp b/src/gui/preview/PreviewController.cpp
index 205c3f8b4..cbea1accb 100644
--- a/src/gui/preview/PreviewController.cpp
+++ b/src/gui/preview/PreviewController.cpp
@@ -18,7 +18,7 @@
 #include "gui/login/LoginView.h"
 #include "Config.h"
 
-PreviewController::PreviewController(int saveID, int saveDate, bool instant, std::function<void ()> onDone_, std::unique_ptr<VideoBuffer> thumbnail):
+PreviewController::PreviewController(int saveID, int saveDate, SavePreviewType savePreviewType, std::function<void ()> onDone_, std::unique_ptr<VideoBuffer> thumbnail):
 	saveId(saveID),
 	loginWindow(NULL),
 	HasExited(false)
@@ -27,7 +27,8 @@ PreviewController::PreviewController(int saveID, int saveDate, bool instant, std
 	previewView = new PreviewView(std::move(thumbnail));
 	previewModel->AddObserver(previewView);
 	previewView->AttachController(this);
-	previewModel->SetDoOpen(instant);
+	previewModel->SetDoOpen(savePreviewType != savePreviewNormal);
+	previewModel->SetFromUrl(savePreviewType == savePreviewUrl);
 
 	previewModel->UpdateSave(saveID, saveDate);
 
@@ -81,6 +82,11 @@ bool PreviewController::GetDoOpen()
 	return previewModel->GetDoOpen();
 }
 
+bool PreviewController::GetFromUrl()
+{
+	return previewModel->GetFromUrl();
+}
+
 void PreviewController::DoOpen()
 {
 	previewModel->SetDoOpen(true);
diff --git a/src/gui/preview/PreviewController.h b/src/gui/preview/PreviewController.h
index 834512807..c9adeaafb 100644
--- a/src/gui/preview/PreviewController.h
+++ b/src/gui/preview/PreviewController.h
@@ -1,5 +1,6 @@
 #pragma once
 #include "client/ClientListener.h"
+#include "gui/SavePreviewType.h"
 #include <functional>
 #include <memory>
 
@@ -19,12 +20,13 @@ public:
 	inline int SaveID() { return saveId; }
 
 	bool HasExited;
-	PreviewController(int saveID, int saveDate, bool instant, std::function<void ()> onDone, std::unique_ptr<VideoBuffer> thumbnail);
+	PreviewController(int saveID, int saveDate, SavePreviewType savePreviewType, std::function<void ()> onDone, std::unique_ptr<VideoBuffer> thumbnail);
 	void Exit();
 	void DoOpen();
 	void OpenInBrowser();
 	void ShowLogin();
 	bool GetDoOpen();
+	bool GetFromUrl();
 	const SaveInfo *GetSaveInfo() const;
 	std::unique_ptr<SaveInfo> TakeSaveInfo();
 	PreviewView * GetView() { return previewView; }
diff --git a/src/gui/preview/PreviewModel.cpp b/src/gui/preview/PreviewModel.cpp
index 2dd1d29ec..ad748f4af 100644
--- a/src/gui/preview/PreviewModel.cpp
+++ b/src/gui/preview/PreviewModel.cpp
@@ -75,6 +75,16 @@ bool PreviewModel::GetDoOpen()
 	return doOpen;
 }
 
+void PreviewModel::SetFromUrl(bool fromUrl)
+{
+	this->fromUrl = fromUrl;
+}
+
+bool PreviewModel::GetFromUrl()
+{
+	return fromUrl;
+}
+
 bool PreviewModel::GetCanOpen()
 {
 	return canOpen;
diff --git a/src/gui/preview/PreviewModel.h b/src/gui/preview/PreviewModel.h
index bbba16a90..d0e8f8475 100644
--- a/src/gui/preview/PreviewModel.h
+++ b/src/gui/preview/PreviewModel.h
@@ -18,6 +18,7 @@ class SaveInfo;
 class PreviewModel
 {
 	bool doOpen = false;
+	bool fromUrl = false;
 	bool canOpen = true;
 	std::vector<PreviewView*> observers;
 	std::unique_ptr<SaveInfo> saveInfo;
@@ -63,8 +64,10 @@ public:
 	void UpdateSave(int saveID, int saveDate);
 	void SetFavourite(bool favourite);
 	bool GetDoOpen();
+	bool GetFromUrl();
 	bool GetCanOpen();
 	void SetDoOpen(bool doOpen);
+	void SetFromUrl(bool fromUrl);
 	void Update();
 	void OnSaveReady();
 	bool ParseSaveInfo(ByteString &saveInfoResponse);
diff --git a/src/gui/preview/PreviewView.cpp b/src/gui/preview/PreviewView.cpp
index 721a5d26c..d42a73c10 100644
--- a/src/gui/preview/PreviewView.cpp
+++ b/src/gui/preview/PreviewView.cpp
@@ -271,16 +271,19 @@ void PreviewView::CheckComment()
 
 void PreviewView::DoDraw()
 {
-	Window::DoDraw();
 	Graphics * g = GetGraphics();
-	for (size_t i = 0; i < commentTextComponents.size(); i++)
+	if (!c->GetFromUrl())
 	{
-		int linePos = commentTextComponents[i]->Position.Y+commentsPanel->ViewportPosition.Y+commentTextComponents[i]->Size.Y+4;
-		if (linePos > 0 && linePos < Size.Y-commentBoxHeight)
-		g->BlendLine(
-				Position + Vec2{ 1+XRES/2, linePos },
-				Position + Vec2{ Size.X-2, linePos },
-				0xFFFFFF_rgb .WithAlpha(100));
+		Window::DoDraw();
+		for (size_t i = 0; i < commentTextComponents.size(); i++)
+		{
+			int linePos = commentTextComponents[i]->Position.Y+commentsPanel->ViewportPosition.Y+commentTextComponents[i]->Size.Y+4;
+			if (linePos > 0 && linePos < Size.Y-commentBoxHeight)
+			g->BlendLine(
+					Position + Vec2{ 1+XRES/2, linePos },
+					Position + Vec2{ Size.X-2, linePos },
+					0xFFFFFF_rgb .WithAlpha(100));
+		}
 	}
 	if (c->GetDoOpen())
 	{
@@ -288,8 +291,10 @@ void PreviewView::DoDraw()
 		g->BlendRect(RectSized(Position + Size / 2 - Vec2{ 100, 25 }, Vec2{ 200, 50 }), 0xFFFFFF_rgb .WithAlpha(180));
 		g->BlendText(Position + Vec2{(Size.X/2)-((Graphics::TextSize("Loading save...").X - 1)/2), (Size.Y/2)-5}, "Loading save...", style::Colour::InformationTitle.NoAlpha().WithAlpha(255));
 	}
-	g->DrawRect(RectSized(Position, Size), 0xFFFFFF_rgb);
-
+	if (!c->GetFromUrl())
+	{
+		g->DrawRect(RectSized(Position, Size), 0xFFFFFF_rgb);
+	}
 }
 
 void PreviewView::OnDraw()
diff --git a/src/gui/search/SearchController.cpp b/src/gui/search/SearchController.cpp
index 7a1509edb..9b742f155 100644
--- a/src/gui/search/SearchController.cpp
+++ b/src/gui/search/SearchController.cpp
@@ -217,7 +217,7 @@ void SearchController::OpenSave(int saveID, int saveDate, std::unique_ptr<VideoB
 	delete activePreview;
 	Graphics * g = searchView->GetGraphics();
 	g->BlendFilledRect(RectSized(Vec2{ XRES/3, WINDOWH-20 }, Vec2{ XRES/3, 20 }), 0x000000_rgb .WithAlpha(150)); //dim the "Page X of Y" a little to make the CopyTextButton more noticeable
-	activePreview = new PreviewController(saveID, saveDate, instantOpen, [this] { OpenSaveDone(); }, std::move(thumbnail));
+	activePreview = new PreviewController(saveID, saveDate, instantOpen ? savePreviewInstant : savePreviewNormal, [this] { OpenSaveDone(); }, std::move(thumbnail));
 	activePreview->GetView()->MakeActiveWindow();
 }
 
diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp
index a3fa94114..8f6fd9df6 100644
--- a/src/lua/LuaScriptInterface.cpp
+++ b/src/lua/LuaScriptInterface.cpp
@@ -2192,7 +2192,7 @@ int LuaScriptInterface::simulation_loadSave(lua_State * l)
 	int saveID = luaL_optint(l,1,0);
 	int instant = luaL_optint(l,2,0);
 	int history = luaL_optint(l,3,0); //Exact second a previous save was saved
-	luacon_controller->OpenSavePreview(saveID, history, instant?true:false);
+	luacon_controller->OpenSavePreview(saveID, history, instant ? savePreviewInstant : savePreviewNormal);
 	return 0;
 }
 
diff --git a/src/lua/TPTScriptInterface.cpp b/src/lua/TPTScriptInterface.cpp
index c93fc2c3d..659715f17 100644
--- a/src/lua/TPTScriptInterface.cpp
+++ b/src/lua/TPTScriptInterface.cpp
@@ -505,7 +505,7 @@ AnyType TPTScriptInterface::tptS_load(std::deque<String> * words)
 
 	if (saveID.Value() > 0)
 	{
-		c->OpenSavePreview(saveID.Value(), 0, false);
+		c->OpenSavePreview(saveID.Value(), 0, savePreviewNormal);
 		return NumberType(0);
 	}
 	else