mirror of https://github.com/OpenRCT2/OpenRCT2.git
Implement import / export packed objects
This commit is contained in:
parent
3f55053d9c
commit
341f716c9d
|
@ -170,7 +170,7 @@ private:
|
|||
auto dataLen = response.body.size();
|
||||
|
||||
auto& objRepo = OpenRCT2::GetContext()->GetObjectRepository();
|
||||
objRepo.AddObjectFromFile(name, data, dataLen);
|
||||
objRepo.AddObjectFromFile(ObjectGeneration::DAT, name, data, dataLen);
|
||||
|
||||
std::lock_guard<std::mutex> guard(_downloadedEntriesMutex);
|
||||
_downloadedEntries.push_back(entry);
|
||||
|
|
|
@ -16,9 +16,12 @@
|
|||
#include "OpenRCT2.h"
|
||||
#include "ParkImporter.h"
|
||||
#include "Version.h"
|
||||
#include "core/Console.hpp"
|
||||
#include "core/Crypt.h"
|
||||
#include "core/DataSerialiser.h"
|
||||
#include "core/File.h"
|
||||
#include "core/OrcaStream.hpp"
|
||||
#include "core/Path.hpp"
|
||||
#include "drawing/Drawing.h"
|
||||
#include "interface/Viewport.h"
|
||||
#include "interface/Window.h"
|
||||
|
@ -81,6 +84,7 @@ namespace OpenRCT2
|
|||
constexpr uint32_t BANNERS = 0x33;
|
||||
// constexpr uint32_t STAFF = 0x35;
|
||||
constexpr uint32_t CHEATS = 0x36;
|
||||
constexpr uint32_t PACKED_OBJECTS = 0x80;
|
||||
// clang-format on
|
||||
}; // namespace ParkFileChunkType
|
||||
|
||||
|
@ -88,6 +92,7 @@ namespace OpenRCT2
|
|||
{
|
||||
public:
|
||||
ObjectList RequiredObjects;
|
||||
std::vector<const ObjectRepositoryItem*> ExportObjectsList;
|
||||
|
||||
private:
|
||||
std::unique_ptr<OrcaStream> _os;
|
||||
|
@ -104,6 +109,7 @@ namespace OpenRCT2
|
|||
_os = std::make_unique<OrcaStream>(stream, OrcaStream::Mode::READING);
|
||||
RequiredObjects = {};
|
||||
ReadWriteObjectsChunk(*_os);
|
||||
ReadWritePackedObjectsChunk(*_os);
|
||||
}
|
||||
|
||||
void Import()
|
||||
|
@ -149,6 +155,7 @@ namespace OpenRCT2
|
|||
ReadWriteNotificationsChunk(os);
|
||||
ReadWriteInterfaceChunk(os);
|
||||
ReadWriteCheatsChunk(os);
|
||||
ReadWritePackedObjectsChunk(os);
|
||||
}
|
||||
|
||||
void Save(const std::string_view& path)
|
||||
|
@ -431,6 +438,101 @@ namespace OpenRCT2
|
|||
});
|
||||
}
|
||||
|
||||
void ReadWritePackedObjectsChunk(OrcaStream& os)
|
||||
{
|
||||
static constexpr uint8_t DESCRIPTOR_DAT = 0;
|
||||
static constexpr uint8_t DESCRIPTOR_PARKOBJ = 1;
|
||||
|
||||
if (os.GetMode() == OrcaStream::Mode::WRITING && ExportObjectsList.size() == 0)
|
||||
{
|
||||
// Do not emit chunk if there are no packed objects
|
||||
return;
|
||||
}
|
||||
|
||||
os.ReadWriteChunk(ParkFileChunkType::PACKED_OBJECTS, [this](OrcaStream::ChunkStream& cs) {
|
||||
if (cs.GetMode() == OrcaStream::Mode::READING)
|
||||
{
|
||||
auto& objRepository = GetContext()->GetObjectRepository();
|
||||
auto numObjects = cs.Read<uint32_t>();
|
||||
for (uint32_t i = 0; i < numObjects; i++)
|
||||
{
|
||||
auto type = cs.Read<uint8_t>();
|
||||
if (type == DESCRIPTOR_DAT)
|
||||
{
|
||||
rct_object_entry entry;
|
||||
cs.Read(&entry, sizeof(entry));
|
||||
auto size = cs.Read<uint32_t>();
|
||||
std::vector<uint8_t> data;
|
||||
data.resize(size);
|
||||
cs.Read(data.data(), data.size());
|
||||
|
||||
auto legacyIdentifier = entry.GetName();
|
||||
if (objRepository.FindObjectLegacy(legacyIdentifier) == nullptr)
|
||||
{
|
||||
objRepository.AddObjectFromFile(ObjectGeneration::DAT, legacyIdentifier, data.data(), data.size());
|
||||
}
|
||||
}
|
||||
else if (type == DESCRIPTOR_PARKOBJ)
|
||||
{
|
||||
auto identifier = cs.Read<std::string>();
|
||||
auto size = cs.Read<uint32_t>();
|
||||
std::vector<uint8_t> data;
|
||||
data.resize(size);
|
||||
cs.Read(data.data(), data.size());
|
||||
if (objRepository.FindObject(identifier) == nullptr)
|
||||
{
|
||||
objRepository.AddObjectFromFile(ObjectGeneration::JSON, identifier, data.data(), data.size());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Unsupported packed object");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& stream = cs.GetStream();
|
||||
auto countPosition = stream.GetPosition();
|
||||
|
||||
// Write placeholder count, update later
|
||||
uint32_t count = 0;
|
||||
cs.Write(count);
|
||||
|
||||
// Write objects
|
||||
for (const auto* ori : ExportObjectsList)
|
||||
{
|
||||
auto extension = Path::GetExtension(ori->Path);
|
||||
if (String::Equals(extension, ".dat", true))
|
||||
{
|
||||
cs.Write(DESCRIPTOR_DAT);
|
||||
cs.Write(&ori->ObjectEntry, sizeof(rct_object_entry));
|
||||
}
|
||||
else if (String::Equals(extension, ".parkobj", true))
|
||||
{
|
||||
cs.Write(DESCRIPTOR_PARKOBJ);
|
||||
cs.Write(ori->Identifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::WriteLine("%s not packed: unsupported extension.", ori->Identifier);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto data = File::ReadAllBytes(ori->Path);
|
||||
cs.Write<uint32_t>(data.size());
|
||||
cs.Write(data.data(), data.size());
|
||||
count++;
|
||||
}
|
||||
|
||||
auto backupPosition = stream.GetPosition();
|
||||
stream.SetPosition(countPosition);
|
||||
cs.Write(count);
|
||||
stream.SetPosition(backupPosition);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ReadWriteClimateChunk(OrcaStream& os)
|
||||
{
|
||||
os.ReadWriteChunk(ParkFileChunkType::CLIMATE, [](OrcaStream::ChunkStream& cs) {
|
||||
|
@ -1503,11 +1605,11 @@ int32_t scenario_save(const utf8* path, int32_t flags)
|
|||
auto parkFile = std::make_unique<OpenRCT2::ParkFile>();
|
||||
try
|
||||
{
|
||||
// if (flags & S6_SAVE_FLAG_EXPORT)
|
||||
// {
|
||||
// auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
|
||||
// s6exporter->ExportObjectsList = objManager.GetPackableObjects();
|
||||
// }
|
||||
if (flags & S6_SAVE_FLAG_EXPORT)
|
||||
{
|
||||
auto& objManager = OpenRCT2::GetContext()->GetObjectManager();
|
||||
parkFile->ExportObjectsList = objManager.GetPackableObjects();
|
||||
}
|
||||
// s6exporter->RemoveTracklessRides = true;
|
||||
// s6exporter->Export();
|
||||
if (flags & S6_SAVE_FLAG_SCENARIO)
|
||||
|
|
|
@ -216,8 +216,7 @@ public:
|
|||
for (size_t i = 0; i < numObjects; i++)
|
||||
{
|
||||
const ObjectRepositoryItem* item = &_objectRepository.GetObjects()[i];
|
||||
if (item->LoadedObject != nullptr && IsObjectCustom(item) && item->LoadedObject->GetLegacyData() != nullptr
|
||||
&& !item->LoadedObject->IsJsonObject())
|
||||
if (item->LoadedObject != nullptr && IsObjectCustom(item))
|
||||
{
|
||||
objects.push_back(item);
|
||||
}
|
||||
|
|
|
@ -297,7 +297,7 @@ public:
|
|||
else
|
||||
{
|
||||
log_verbose("Adding object: [%s]", objectName);
|
||||
auto path = GetPathForNewObject(objectName);
|
||||
auto path = GetPathForNewObject(ObjectGeneration::DAT, objectName);
|
||||
try
|
||||
{
|
||||
SaveObject(path, objectEntry, data, dataSize);
|
||||
|
@ -310,10 +310,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void AddObjectFromFile(std::string_view objectName, const void* data, size_t dataSize) override
|
||||
void AddObjectFromFile(ObjectGeneration generation, std::string_view objectName, const void* data, size_t dataSize) override
|
||||
{
|
||||
log_verbose("Adding object: [%s]", std::string(objectName).c_str());
|
||||
auto path = GetPathForNewObject(objectName);
|
||||
auto path = GetPathForNewObject(generation, objectName);
|
||||
try
|
||||
{
|
||||
File::WriteAllBytes(path, data, dataSize);
|
||||
|
@ -554,45 +554,53 @@ private:
|
|||
return salt;
|
||||
}
|
||||
|
||||
std::string GetPathForNewObject(std::string_view name)
|
||||
std::string GetPathForNewObject(ObjectGeneration generation, std::string_view name)
|
||||
{
|
||||
// Get object directory and create it if it doesn't exist
|
||||
auto userObjPath = _env->GetDirectoryPath(DIRBASE::USER, DIRID::OBJECT);
|
||||
Path::CreateDirectory(userObjPath);
|
||||
|
||||
// Find a unique file name
|
||||
auto fileName = GetFileNameForNewObject(name);
|
||||
auto fullPath = Path::Combine(userObjPath, fileName + ".DAT");
|
||||
auto fileName = GetFileNameForNewObject(generation, name);
|
||||
auto extension = (generation == ObjectGeneration::DAT ? ".DAT" : ".parkobj");
|
||||
auto fullPath = Path::Combine(userObjPath, fileName + extension);
|
||||
auto counter = 1U;
|
||||
while (File::Exists(fullPath))
|
||||
{
|
||||
counter++;
|
||||
fullPath = Path::Combine(userObjPath, String::StdFormat("%s-%02X.DAT", fileName.c_str(), counter));
|
||||
fullPath = Path::Combine(userObjPath, String::StdFormat("%s-%02X%s", fileName.c_str(), counter, extension));
|
||||
}
|
||||
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
std::string GetFileNameForNewObject(std::string_view name)
|
||||
std::string GetFileNameForNewObject(ObjectGeneration generation, std::string_view name)
|
||||
{
|
||||
// Trim name
|
||||
char normalisedName[9] = { 0 };
|
||||
auto maxLength = std::min<size_t>(name.size(), 8);
|
||||
for (size_t i = 0; i < maxLength; i++)
|
||||
if (generation == ObjectGeneration::DAT)
|
||||
{
|
||||
if (name[i] != ' ')
|
||||
// Trim name
|
||||
char normalisedName[9] = { 0 };
|
||||
auto maxLength = std::min<size_t>(name.size(), 8);
|
||||
for (size_t i = 0; i < maxLength; i++)
|
||||
{
|
||||
normalisedName[i] = toupper(name[i]);
|
||||
if (name[i] != ' ')
|
||||
{
|
||||
normalisedName[i] = toupper(name[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
normalisedName[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
normalisedName[i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to UTF-8 filename
|
||||
return String::Convert(normalisedName, CODE_PAGE::CP_1252, CODE_PAGE::CP_UTF8);
|
||||
// Convert to UTF-8 filename
|
||||
return String::Convert(normalisedName, CODE_PAGE::CP_1252, CODE_PAGE::CP_UTF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string(name);
|
||||
}
|
||||
}
|
||||
|
||||
void WritePackedObject(OpenRCT2::IStream* stream, const rct_object_entry* entry)
|
||||
|
|
|
@ -82,7 +82,7 @@ struct IObjectRepository
|
|||
virtual void UnregisterLoadedObject(const ObjectRepositoryItem* ori, Object* object) abstract;
|
||||
|
||||
virtual void AddObject(const rct_object_entry* objectEntry, const void* data, size_t dataSize) abstract;
|
||||
virtual void AddObjectFromFile(std::string_view objectName, const void* data, size_t dataSize) abstract;
|
||||
virtual void AddObjectFromFile(ObjectGeneration generation, std::string_view objectName, const void* data, size_t dataSize) abstract;
|
||||
|
||||
virtual void ExportPackedObject(OpenRCT2::IStream* stream) abstract;
|
||||
virtual void WritePackedObjects(OpenRCT2::IStream* stream, std::vector<const ObjectRepositoryItem*>& objects) abstract;
|
||||
|
|
Loading…
Reference in New Issue