1 /*****************************************************************************
2 * Copyright (c) 2014-2020 OpenRCT2 developers
3 *
4 * For a complete list of all authors, please refer to contributors.md
5 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6 *
7 * OpenRCT2 is licensed under the GNU General Public License version 3.
8 *****************************************************************************/
9
10 #include "../FileClassifier.h"
11 #include "../OpenRCT2.h"
12 #include "../ParkImporter.h"
13 #include "../common.h"
14 #include "../core/Console.hpp"
15 #include "../core/Path.hpp"
16 #include "../interface/Window.h"
17 #include "../rct2/S6Exporter.h"
18 #include "CommandLine.hpp"
19
20 #include <memory>
21
22 static void WriteConvertFromAndToMessage(uint32_t sourceFileType, uint32_t destinationFileType);
23 static const utf8* GetFileTypeFriendlyName(uint32_t fileType);
24
HandleCommandConvert(CommandLineArgEnumerator * enumerator)25 exitcode_t CommandLine::HandleCommandConvert(CommandLineArgEnumerator* enumerator)
26 {
27 exitcode_t result = CommandLine::HandleCommandDefault();
28 if (result != EXITCODE_CONTINUE)
29 {
30 return result;
31 }
32
33 // Get the source path
34 const utf8* rawSourcePath;
35 if (!enumerator->TryPopString(&rawSourcePath))
36 {
37 Console::Error::WriteLine("Expected a source path.");
38 return EXITCODE_FAIL;
39 }
40
41 utf8 sourcePath[MAX_PATH];
42 Path::GetAbsolute(sourcePath, sizeof(sourcePath), rawSourcePath);
43 uint32_t sourceFileType = get_file_extension_type(sourcePath);
44
45 // Get the destination path
46 const utf8* rawDestinationPath;
47 if (!enumerator->TryPopString(&rawDestinationPath))
48 {
49 Console::Error::WriteLine("Expected a destination path.");
50 return EXITCODE_FAIL;
51 }
52
53 utf8 destinationPath[MAX_PATH];
54 Path::GetAbsolute(destinationPath, sizeof(sourcePath), rawDestinationPath);
55 uint32_t destinationFileType = get_file_extension_type(destinationPath);
56
57 // Validate target type
58 if (destinationFileType != FILE_EXTENSION_SC6 && destinationFileType != FILE_EXTENSION_SV6)
59 {
60 Console::Error::WriteLine("Only conversion to .SC6 or .SV4 is supported.");
61 return EXITCODE_FAIL;
62 }
63
64 // Validate the source type
65 switch (sourceFileType)
66 {
67 case FILE_EXTENSION_SC4:
68 case FILE_EXTENSION_SV4:
69 break;
70 case FILE_EXTENSION_SC6:
71 if (destinationFileType == FILE_EXTENSION_SC6)
72 {
73 Console::Error::WriteLine("File is already a RollerCoaster Tycoon 2 scenario.");
74 return EXITCODE_FAIL;
75 }
76 break;
77 case FILE_EXTENSION_SV6:
78 if (destinationFileType == FILE_EXTENSION_SV6)
79 {
80 Console::Error::WriteLine("File is already a RollerCoaster Tycoon 2 saved game.");
81 return EXITCODE_FAIL;
82 }
83 break;
84 default:
85 Console::Error::WriteLine("Only conversion from .SC4, .SV4, .SC6 or .SV6 is supported.");
86 return EXITCODE_FAIL;
87 }
88
89 // Perform conversion
90 WriteConvertFromAndToMessage(sourceFileType, destinationFileType);
91
92 gOpenRCT2Headless = true;
93
94 try
95 {
96 auto importer = ParkImporter::Create(sourcePath);
97 importer->Load(sourcePath);
98 importer->Import();
99 }
100 catch (const std::exception& ex)
101 {
102 Console::Error::WriteLine(ex.what());
103 return EXITCODE_FAIL;
104 }
105
106 if (sourceFileType == FILE_EXTENSION_SC4 || sourceFileType == FILE_EXTENSION_SC6)
107 {
108 // We are converting a scenario, so reset the park
109 scenario_begin();
110 }
111
112 try
113 {
114 auto exporter = std::make_unique<S6Exporter>();
115
116 // HACK remove the main window so it saves the park with the
117 // correct initial view
118 window_close_by_class(WC_MAIN_WINDOW);
119
120 exporter->Export();
121 if (destinationFileType == FILE_EXTENSION_SC6)
122 {
123 exporter->SaveScenario(destinationPath);
124 }
125 else
126 {
127 exporter->SaveGame(destinationPath);
128 }
129 }
130 catch (const std::exception& ex)
131 {
132 Console::Error::WriteLine(ex.what());
133 return EXITCODE_FAIL;
134 }
135
136 Console::WriteLine("Conversion successful!");
137 return EXITCODE_OK;
138 }
139
WriteConvertFromAndToMessage(uint32_t sourceFileType,uint32_t destinationFileType)140 static void WriteConvertFromAndToMessage(uint32_t sourceFileType, uint32_t destinationFileType)
141 {
142 const utf8* sourceFileTypeName = GetFileTypeFriendlyName(sourceFileType);
143 const utf8* destinationFileTypeName = GetFileTypeFriendlyName(destinationFileType);
144 Console::WriteFormat("Converting from a %s to a %s.", sourceFileTypeName, destinationFileTypeName);
145 Console::WriteLine();
146 }
147
GetFileTypeFriendlyName(uint32_t fileType)148 static const utf8* GetFileTypeFriendlyName(uint32_t fileType)
149 {
150 switch (fileType)
151 {
152 case FILE_EXTENSION_SC4:
153 return "RollerCoaster Tycoon 1 scenario";
154 case FILE_EXTENSION_SV4:
155 return "RollerCoaster Tycoon 1 saved game";
156 case FILE_EXTENSION_SC6:
157 return "RollerCoaster Tycoon 2 scenario";
158 case FILE_EXTENSION_SV6:
159 return "RollerCoaster Tycoon 2 saved game";
160 }
161
162 assert(false);
163 return nullptr;
164 }
165