diff --git a/distribution/linux/openrct2-mimeinfo.xml b/distribution/linux/openrct2-mimeinfo.xml
index 9f616ebb6e..7b72a6b3bb 100644
--- a/distribution/linux/openrct2-mimeinfo.xml
+++ b/distribution/linux/openrct2-mimeinfo.xml
@@ -49,6 +49,7 @@
OpenRCT2 劇情檔案
+
diff --git a/src/openrct2/FileClassifier.cpp b/src/openrct2/FileClassifier.cpp
index 77fedaf7d2..6f6fd74ee3 100644
--- a/src/openrct2/FileClassifier.cpp
+++ b/src/openrct2/FileClassifier.cpp
@@ -175,6 +175,8 @@ uint32_t get_file_extension_type(const utf8* path)
return FILE_EXTENSION_TD4;
if (String::Equals(extension, ".sc6", true))
return FILE_EXTENSION_SC6;
+ if (String::Equals(extension, ".sea", true))
+ return FILE_EXTENSION_SC6;
if (String::Equals(extension, ".sv6", true))
return FILE_EXTENSION_SV6;
if (String::Equals(extension, ".sv7", true))
diff --git a/src/openrct2/ParkImporter.cpp b/src/openrct2/ParkImporter.cpp
index c812df4bf1..a8483a582d 100644
--- a/src/openrct2/ParkImporter.cpp
+++ b/src/openrct2/ParkImporter.cpp
@@ -42,6 +42,7 @@ namespace ParkImporter
bool ExtensionIsScenario(const std::string& extension)
{
- return String::Equals(extension, ".sc4", true) || String::Equals(extension, ".sc6", true);
+ return String::Equals(extension, ".sc4", true) || String::Equals(extension, ".sc6", true)
+ || String::Equals(extension, ".sea", true);
}
} // namespace ParkImporter
diff --git a/src/openrct2/platform/Platform.Win32.cpp b/src/openrct2/platform/Platform.Win32.cpp
index 99b77f5821..59110fa973 100644
--- a/src/openrct2/platform/Platform.Win32.cpp
+++ b/src/openrct2/platform/Platform.Win32.cpp
@@ -363,6 +363,7 @@ namespace Platform
SetUpFileAssociation(".sv4", "RCT1 Saved Game (.sc4)", "Play", "\"%1\"", 0);
SetUpFileAssociation(".sv6", "RCT2 Saved Game (.sv6)", "Play", "\"%1\"", 0);
SetUpFileAssociation(".sv7", "RCT Modified Saved Game (.sv7)", "Play", "\"%1\"", 0);
+ SetUpFileAssociation(".sea", "RCTC Saved Game (.sea)", "Play", "\"%1\"", 0);
SetUpFileAssociation(".td4", "RCT1 Track Design (.td4)", "Install", "\"%1\"", 0);
SetUpFileAssociation(".td6", "RCT2 Track Design (.td6)", "Install", "\"%1\"", 0);
@@ -507,6 +508,7 @@ namespace Platform
RemoveFileAssociation(".sv4");
RemoveFileAssociation(".sv6");
RemoveFileAssociation(".sv7");
+ RemoveFileAssociation(".sea");
RemoveFileAssociation(".td4");
RemoveFileAssociation(".td6");
diff --git a/src/openrct2/scenario/ScenarioRepository.cpp b/src/openrct2/scenario/ScenarioRepository.cpp
index 57790b0345..7205d32150 100644
--- a/src/openrct2/scenario/ScenarioRepository.cpp
+++ b/src/openrct2/scenario/ScenarioRepository.cpp
@@ -18,6 +18,7 @@
#include "../core/File.h"
#include "../core/FileIndex.hpp"
#include "../core/FileStream.hpp"
+#include "../core/MemoryStream.h"
#include "../core/Path.hpp"
#include "../core/String.hpp"
#include "../localisation/Language.h"
@@ -128,7 +129,7 @@ class ScenarioFileIndex final : public FileIndex
private:
static constexpr uint32_t MAGIC_NUMBER = 0x58444953; // SIDX
static constexpr uint16_t VERSION = 3;
- static constexpr auto PATTERN = "*.sc4;*.sc6";
+ static constexpr auto PATTERN = "*.sc4;*.sc6;*.sea";
public:
explicit ScenarioFileIndex(const IPlatformEnvironment& env)
@@ -203,6 +204,19 @@ protected:
}
private:
+ static IStream* GetStreamFromRCT2Scenario(const std::string& path)
+ {
+ if (String::Equals(Path::GetExtension(path), ".sea", true))
+ {
+ auto data = DecryptSea(fs::u8path(path));
+ auto ms = new MemoryStream(data.data(), data.size(), MEMORY_ACCESS::READ);
+ return ms;
+ }
+
+ auto fs = new FileStream(path, FILE_MODE_OPEN);
+ return fs;
+ }
+
/**
* Reads basic information from a scenario file.
*/
@@ -234,9 +248,9 @@ private:
}
else
{
- // RCT2 scenario
- auto fs = FileStream(path, FILE_MODE_OPEN);
- auto chunkReader = SawyerChunkReader(&fs);
+ // RCT2 or RCTC scenario
+ auto stream = GetStreamFromRCT2Scenario(path);
+ auto chunkReader = SawyerChunkReader(stream);
rct_s6_header header = chunkReader.ReadChunkAs();
if (header.type == S6_TYPE_SCENARIO)
@@ -251,10 +265,12 @@ private:
}
*entry = CreateNewScenarioEntry(path, timestamp, &info);
+ delete stream;
return true;
}
else
{
+ delete stream;
log_verbose("%s is not a scenario", path.c_str());
}
}