diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 3a2e00294f..faf4df57fd 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,6 +1,7 @@ 0.4.2 (in development) ------------------------------------------------------------------------ - Feature: [#13634] Add ability to sell merchandise in random colours. +- Feature: [#16283] Added parkinfo command line tool to list objects in a save file. - Feature: [#16662] Show a warning message when g2.dat is mismatched. - Feature: [#17107] Ride operating settings can be set via text input. - Improved: [#15358] Park and scenario names can now contain up to 128 characters. diff --git a/src/openrct2/cmdline/CommandLine.hpp b/src/openrct2/cmdline/CommandLine.hpp index 1df4fa3326..ea34a55ae6 100644 --- a/src/openrct2/cmdline/CommandLine.hpp +++ b/src/openrct2/cmdline/CommandLine.hpp @@ -120,6 +120,7 @@ namespace CommandLine extern const CommandLineCommand BenchSpriteSortCommands[]; extern const CommandLineCommand BenchUpdateCommands[]; extern const CommandLineCommand SimulateCommands[]; + extern const CommandLineCommand ParkInfoCommands[]; extern const CommandLineExample RootExamples[]; diff --git a/src/openrct2/cmdline/ParkInfoCommands.cpp b/src/openrct2/cmdline/ParkInfoCommands.cpp new file mode 100644 index 0000000000..8ce5ec2838 --- /dev/null +++ b/src/openrct2/cmdline/ParkInfoCommands.cpp @@ -0,0 +1,145 @@ +/***************************************************************************** + * Copyright (c) 2014-2022 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#include "../Context.h" +#include "../FileClassifier.h" +#include "../ParkImporter.h" +#include "../core/Console.hpp" +#include "../core/FileStream.h" +#include "../core/Path.hpp" +#include "../object/ObjectRepository.h" +#include "CommandLine.hpp" + +// clang-format off +static constexpr const CommandLineOptionDefinition NoOptions[] +{ + OptionTableEnd +}; + +static exitcode_t HandleObjectsInfo(CommandLineArgEnumerator *argEnumerator); + +const CommandLineCommand CommandLine::ParkInfoCommands[]{ + // Main commands + DefineCommand("objects", "", NoOptions, HandleObjectsInfo), + + CommandTableEnd +}; +// clang-format on + +static exitcode_t HandleObjectsInfo(CommandLineArgEnumerator* argEnumerator) +{ + exitcode_t result = CommandLine::HandleCommandDefault(); + if (result != EXITCODE_CONTINUE) + { + return result; + } + + // Get the source path + const utf8* rawSourcePath; + if (!argEnumerator->TryPopString(&rawSourcePath)) + { + Console::Error::WriteLine("Expected a source save file path."); + return EXITCODE_FAIL; + } + + auto sourcePath = Path::GetAbsolute(rawSourcePath); + + auto context = OpenRCT2::CreateContext(); + context->Initialise(); + + auto stream = OpenRCT2::FileStream(sourcePath, OpenRCT2::FILE_MODE_OPEN); + ClassifiedFileInfo info; + if (!TryClassifyFile(&stream, &info)) + { + Console::Error::WriteLine("Unable to detect file type"); + return EXITCODE_FAIL; + } + + if (info.Type != FILE_TYPE::PARK && info.Type != FILE_TYPE::SAVED_GAME && info.Type != FILE_TYPE::SCENARIO) + { + Console::Error::WriteLine("Invalid file type."); + return EXITCODE_FAIL; + } + + auto& objectRepository = context->GetObjectRepository(); + std::unique_ptr parkImporter; + if (info.Type == FILE_TYPE::PARK) + { + parkImporter = ParkImporter::CreateParkFile(objectRepository); + } + else if (info.Version <= FILE_TYPE_S4_CUTOFF) + { + // Save is an S4 (RCT1 format) + parkImporter = ParkImporter::CreateS4(); + } + else + { + // Save is an S6 (RCT2 format) + parkImporter = ParkImporter::CreateS6(objectRepository); + } + auto loadResult = parkImporter->LoadSavedGame(sourcePath.c_str()); + + Console::WriteLine("File contains the following objects: "); + Console::WriteLine(); + + const std::array typeToName = { + "Ride", "SmallScenery", "LargeScenery", "Walls", "Banners", "Paths", + "PathAdditions", "SceneryGroup", "ParkEntrance", "Water", "ScenarioText", "TerrainSurface", + "TerrainEdge", "Station", "Music", "FootpathSurface", "FootpathRailings", + }; + const std::array sourceGameToName = { + "Custom", "WackyWorlds", "TimeTwister", "OpenRCT2Official", "RCT1", "AddedAttractions", "LoopyLandscapes", "", "RCT2", + }; + + for (auto& objType : { + ObjectType::Ride, + ObjectType::SmallScenery, + ObjectType::LargeScenery, + ObjectType::Walls, + ObjectType::Banners, + ObjectType::Paths, + ObjectType::PathBits, + ObjectType::SceneryGroup, + ObjectType::ParkEntrance, + ObjectType::Water, + ObjectType::ScenarioText, + ObjectType::TerrainSurface, + ObjectType::TerrainEdge, + ObjectType::Station, + ObjectType::Music, + ObjectType::FootpathSurface, + ObjectType::FootpathRailings, + }) + { + auto& list = loadResult.RequiredObjects.GetList(objType); + Console::WriteLine("ObjectType: %s, Number of Objects: %d", typeToName[EnumValue(objType)].c_str(), list.size()); + for (auto& obj : list) + { + if (obj.Generation == ObjectGeneration::JSON && obj.Identifier.size() == 0) + { + // Empty object slot don't output anything + continue; + } + auto* ori = OpenRCT2::GetContext()->GetObjectRepository().FindObject(obj); + Console::WriteFormat("%s Object: ", sourceGameToName[EnumValue(ori->GetFirstSourceGame())].c_str()); + + std::string name{ obj.GetName() }; + if (obj.Generation == ObjectGeneration::DAT) + { + Console::WriteLine("%08X|%s|%08X", obj.Entry.flags, name.c_str(), obj.Entry.checksum); + } + else + { + Console::WriteLine("%s", name.c_str()); + } + } + Console::WriteLine(); + } + return EXITCODE_OK; +} diff --git a/src/openrct2/cmdline/RootCommands.cpp b/src/openrct2/cmdline/RootCommands.cpp index 2cac7d7ca2..3e7fd44adb 100644 --- a/src/openrct2/cmdline/RootCommands.cpp +++ b/src/openrct2/cmdline/RootCommands.cpp @@ -144,6 +144,7 @@ const CommandLineCommand CommandLine::RootCommands[] DefineSubCommand("benchspritesort", CommandLine::BenchSpriteSortCommands ), DefineSubCommand("benchsimulate", CommandLine::BenchUpdateCommands ), DefineSubCommand("simulate", CommandLine::SimulateCommands ), + DefineSubCommand("parkinfo", CommandLine::ParkInfoCommands ), CommandTableEnd }; diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index a17b96d626..181a781347 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -645,6 +645,7 @@ +