mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-16 03:23:15 +01:00
Modify object loading for JSON-only objects
This commit is contained in:
@@ -77,7 +77,7 @@ class ObjectFileIndex final : public FileIndex<ObjectRepositoryItem>
|
||||
{
|
||||
private:
|
||||
static constexpr uint32_t MAGIC_NUMBER = 0x5844494F; // OIDX
|
||||
static constexpr uint16_t VERSION = 27;
|
||||
static constexpr uint16_t VERSION = 28;
|
||||
static constexpr auto PATTERN = "*.dat;*.pob;*.json;*.parkobj";
|
||||
|
||||
IObjectRepository& _objectRepository;
|
||||
@@ -114,8 +114,10 @@ public:
|
||||
if (object != nullptr)
|
||||
{
|
||||
ObjectRepositoryItem item = {};
|
||||
item.Type = object->GetObjectType();
|
||||
item.Generation = object->GetGeneration();
|
||||
item.Identifier = object->GetIdentifier();
|
||||
item.ObjectEntry = *object->GetObjectEntry();
|
||||
item.ObjectEntry = object->GetObjectEntry();
|
||||
item.Path = path;
|
||||
item.Name = object->GetName();
|
||||
item.Authors = object->GetAuthors();
|
||||
@@ -129,6 +131,8 @@ public:
|
||||
protected:
|
||||
void Serialise(DataSerialiser& ds, ObjectRepositoryItem& item) const override
|
||||
{
|
||||
ds << item.Type;
|
||||
ds << item.Generation;
|
||||
ds << item.Identifier;
|
||||
ds << item.ObjectEntry;
|
||||
ds << item.Path;
|
||||
@@ -137,7 +141,7 @@ protected:
|
||||
ds << item.Sources;
|
||||
ds << item.Authors;
|
||||
|
||||
switch (item.ObjectEntry.GetType())
|
||||
switch (item.Type)
|
||||
{
|
||||
case ObjectType::Ride:
|
||||
ds << item.RideInfo.RideFlags;
|
||||
@@ -149,6 +153,9 @@ protected:
|
||||
ds << item.SceneryGroupInfo.Entries;
|
||||
break;
|
||||
}
|
||||
case ObjectType::FootpathSurface:
|
||||
ds << item.FootpathSurfaceInfo.Flags;
|
||||
break;
|
||||
default:
|
||||
// Switch processes only ObjectType::Ride and ObjectType::SceneryGroup
|
||||
break;
|
||||
@@ -298,7 +305,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);
|
||||
@@ -311,10 +318,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);
|
||||
@@ -415,7 +422,15 @@ private:
|
||||
|
||||
bool AddItem(const ObjectRepositoryItem& item)
|
||||
{
|
||||
auto conflict = FindObject(&item.ObjectEntry);
|
||||
const ObjectRepositoryItem* conflict{};
|
||||
if (item.ObjectEntry.name[0] != '\0')
|
||||
{
|
||||
conflict = FindObject(&item.ObjectEntry);
|
||||
}
|
||||
if (conflict == nullptr)
|
||||
{
|
||||
conflict = FindObject(item.Identifier);
|
||||
}
|
||||
if (conflict == nullptr)
|
||||
{
|
||||
size_t index = _items.size();
|
||||
@@ -426,7 +441,10 @@ private:
|
||||
{
|
||||
_newItemMap[item.Identifier] = index;
|
||||
}
|
||||
_itemMap[item.ObjectEntry] = index;
|
||||
if (!item.ObjectEntry.IsEmpty())
|
||||
{
|
||||
_itemMap[item.ObjectEntry] = index;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -555,45 +573,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)
|
||||
@@ -607,7 +633,7 @@ private:
|
||||
// Read object data from file
|
||||
auto fs = OpenRCT2::FileStream(item->Path, OpenRCT2::FILE_MODE_OPEN);
|
||||
auto fileEntry = fs.ReadValue<rct_object_entry>();
|
||||
if (!object_entry_compare(entry, &fileEntry))
|
||||
if (*entry != fileEntry)
|
||||
{
|
||||
throw std::runtime_error("Header found in object file does not match object to pack.");
|
||||
}
|
||||
@@ -632,14 +658,16 @@ bool IsObjectCustom(const ObjectRepositoryItem* object)
|
||||
|
||||
// Do not count our new object types as custom yet, otherwise the game
|
||||
// will try to pack them into saved games.
|
||||
auto type = object->ObjectEntry.GetType();
|
||||
if (type > ObjectType::ScenarioText)
|
||||
if (object->Type > ObjectType::ScenarioText)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (object->GetFirstSourceGame())
|
||||
{
|
||||
case ObjectSourceGame::RCT1:
|
||||
case ObjectSourceGame::AddedAttractions:
|
||||
case ObjectSourceGame::LoopyLandscapes:
|
||||
case ObjectSourceGame::RCT2:
|
||||
case ObjectSourceGame::WackyWorlds:
|
||||
case ObjectSourceGame::TimeTwister:
|
||||
@@ -718,40 +746,6 @@ const ObjectRepositoryItem* object_repository_find_object_by_name(const char* na
|
||||
return objectRepository.FindObjectLegacy(name);
|
||||
}
|
||||
|
||||
bool object_entry_compare(const rct_object_entry* a, const rct_object_entry* b)
|
||||
{
|
||||
// If an official object don't bother checking checksum
|
||||
if ((a->flags & 0xF0) || (b->flags & 0xF0))
|
||||
{
|
||||
if (a->GetType() != b->GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int32_t match = memcmp(a->name, b->name, 8);
|
||||
if (match)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a->flags != b->flags)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int32_t match = memcmp(a->name, b->name, 8);
|
||||
if (match)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (a->checksum != b->checksum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t object_calculate_checksum(const rct_object_entry* entry, const void* data, size_t dataLength)
|
||||
{
|
||||
const uint8_t* entryBytePtr = reinterpret_cast<const uint8_t*>(entry);
|
||||
|
||||
Reference in New Issue
Block a user