From 0fa703a1cb297d6e17424f071d1a674320a8c9b9 Mon Sep 17 00:00:00 2001 From: Ted John Date: Fri, 24 Jun 2016 21:16:51 +0100 Subject: [PATCH 001/116] add new ObjectCache class with Entry --- openrct2.vcxproj | 3 + src/core/IStream.cpp | 49 ++++++++++++ src/core/IStream.hpp | 3 + src/object/ObjectCache.cpp | 149 +++++++++++++++++++++++++++++++++++++ src/object/ObjectCache.h | 27 +++++++ 5 files changed, 231 insertions(+) create mode 100644 src/core/IStream.cpp create mode 100644 src/object/ObjectCache.cpp create mode 100644 src/object/ObjectCache.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 1561101908..87f7d53f9c 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -43,6 +43,7 @@ + @@ -116,6 +117,7 @@ + @@ -416,6 +418,7 @@ + diff --git a/src/core/IStream.cpp b/src/core/IStream.cpp new file mode 100644 index 0000000000..5e9bf80c30 --- /dev/null +++ b/src/core/IStream.cpp @@ -0,0 +1,49 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include +#include "IStream.hpp" +#include "Memory.hpp" +#include "String.hpp" + +utf8 * IStream::ReadString() +{ + std::vector result; + + uint8 ch; + while ((ch = ReadValue()) != 0) + { + result.push_back(ch); + } + result.push_back(0); + + utf8 * resultString = Memory::AllocateArray(result.size()); + Memory::CopyArray(resultString, result.data(), result.size()); + return resultString; +} + +void IStream::WriteString(utf8 * str) +{ + if (str == nullptr) + { + WriteValue(0); + } + else + { + size_t numBytes = String::SizeOf(str) + 1; + Write(str, numBytes); + } +} diff --git a/src/core/IStream.hpp b/src/core/IStream.hpp index 5240e9b604..9f85e1b229 100644 --- a/src/core/IStream.hpp +++ b/src/core/IStream.hpp @@ -89,6 +89,9 @@ interface IStream : public IDisposable { Write(&value); } + + utf8 * ReadString(); + void WriteString(utf8 * str); }; class IOException : public Exception diff --git a/src/object/ObjectCache.cpp b/src/object/ObjectCache.cpp new file mode 100644 index 0000000000..158c4cd5d7 --- /dev/null +++ b/src/object/ObjectCache.cpp @@ -0,0 +1,149 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../common.h" +#include "../core/Guard.hpp" +#include "../core/IStream.hpp" +#include "../core/Memory.hpp" +#include "../core/String.hpp" +#include "ObjectCache.h" + +extern "C" +{ + #include "../object.h" +} + +struct ObjectCacheEntry +{ + rct_object_entry_extended ObjectEntry; + utf8 * Path; + uint32 NumImages; + utf8 * Name; + size_t ChunkSize; + uint16 NumRequiredObjects; + rct_object_entry_extended * RequiredObjects; + union + { + struct + { + uint16 NumThemeObjects; + rct_object_entry_extended * ThemeObjects; + }; + struct + { + uint8 RideFlags; + uint8 RideCategory[2]; + uint8 RideType[3]; + }; + }; + + void Dispose() + { + Memory::Free(RequiredObjects); + Memory::Free(ThemeObjects); + RequiredObjects = nullptr; + ThemeObjects = nullptr; + } + + void Read(IStream * stream) + { + Guard::Assert(RequiredObjects == nullptr); + Guard::Assert(ThemeObjects == nullptr); + + ObjectEntry = stream->ReadValue(); + Path = stream->ReadString(); + NumImages = stream->ReadValue(); + Name = stream->ReadString(); + ChunkSize = stream->ReadValue(); + NumRequiredObjects = stream->ReadValue(); + + RequiredObjects = Memory::AllocateArray(NumRequiredObjects); + for (uint16 i = 0; i < NumRequiredObjects; i++) + { + RequiredObjects[i] = stream->ReadValue(); + } + + switch (ObjectEntry.flags & 0x0F) { + case OBJECT_TYPE_RIDE: + RideFlags = stream->ReadValue(); + for (int i = 0; i < 2; i++) + { + RideCategory[i] = stream->ReadValue(); + } + for (int i = 0; i < 3; i++) + { + RideType[i] = stream->ReadValue(); + } + break; + case OBJECT_TYPE_SCENERY_SETS: + NumThemeObjects = stream->ReadValue(); + for (uint16 i = 0; i < NumThemeObjects; i++) + { + ThemeObjects[i] = stream->ReadValue(); + } + break; + } + } + + void Write(IStream * stream) + { + stream->WriteValue(ObjectEntry); + stream->WriteString(Path); + stream->WriteValue(NumImages); + stream->WriteString(Name); + stream->WriteValue(ChunkSize); + + stream->WriteValue(NumRequiredObjects); + for (uint16 i = 0; i < NumRequiredObjects; i++) + { + stream->WriteValue(RequiredObjects[i]); + } + + switch (ObjectEntry.flags & 0x0F) { + case OBJECT_TYPE_RIDE: + stream->WriteValue(RideFlags); + for (int i = 0; i < 2; i++) + { + stream->WriteValue(RideCategory[i]); + } + for (int i = 0; i < 3; i++) + { + stream->WriteValue(RideType[i]); + } + break; + case OBJECT_TYPE_SCENERY_SETS: + stream->WriteValue(NumThemeObjects); + for (uint16 i = 0; i < NumThemeObjects; i++) + { + stream->WriteValue(ThemeObjects[i]); + } + break; + } + } +}; + +class ObjectCache : IObjectCache +{ + void Load() override + { + // TODO + } + + void Save() override + { + // TODO + } +}; diff --git a/src/object/ObjectCache.h b/src/object/ObjectCache.h new file mode 100644 index 0000000000..cb7b4ba5b3 --- /dev/null +++ b/src/object/ObjectCache.h @@ -0,0 +1,27 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "../common.h" + +interface IObjectCache +{ + virtual ~IObjectCache(); + + virtual void Load() abstract; + virtual void Save() abstract; +}; From 06bf6bb39d2b4633c84113ac792feccb832483f2 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 00:58:56 +0100 Subject: [PATCH 002/116] settle for ObjectRepository and write load / save --- openrct2.vcxproj | 4 +- src/object/ObjectCache.cpp | 149 ----------------- src/object/ObjectCache.h | 27 ---- src/object/ObjectRepository.cpp | 275 ++++++++++++++++++++++++++++++++ src/object/ObjectRepository.h | 58 +++++++ 5 files changed, 335 insertions(+), 178 deletions(-) delete mode 100644 src/object/ObjectCache.cpp delete mode 100644 src/object/ObjectCache.h create mode 100644 src/object/ObjectRepository.cpp create mode 100644 src/object/ObjectRepository.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 87f7d53f9c..aa51bb272c 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -117,7 +117,7 @@ - + @@ -418,7 +418,7 @@ - + diff --git a/src/object/ObjectCache.cpp b/src/object/ObjectCache.cpp deleted file mode 100644 index 158c4cd5d7..0000000000 --- a/src/object/ObjectCache.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers -/***************************************************************************** - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * OpenRCT2 is the work of many authors, a full list can be found in contributors.md - * For more information, visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * A full copy of the GNU General Public License can be found in licence.txt - *****************************************************************************/ -#pragma endregion - -#include "../common.h" -#include "../core/Guard.hpp" -#include "../core/IStream.hpp" -#include "../core/Memory.hpp" -#include "../core/String.hpp" -#include "ObjectCache.h" - -extern "C" -{ - #include "../object.h" -} - -struct ObjectCacheEntry -{ - rct_object_entry_extended ObjectEntry; - utf8 * Path; - uint32 NumImages; - utf8 * Name; - size_t ChunkSize; - uint16 NumRequiredObjects; - rct_object_entry_extended * RequiredObjects; - union - { - struct - { - uint16 NumThemeObjects; - rct_object_entry_extended * ThemeObjects; - }; - struct - { - uint8 RideFlags; - uint8 RideCategory[2]; - uint8 RideType[3]; - }; - }; - - void Dispose() - { - Memory::Free(RequiredObjects); - Memory::Free(ThemeObjects); - RequiredObjects = nullptr; - ThemeObjects = nullptr; - } - - void Read(IStream * stream) - { - Guard::Assert(RequiredObjects == nullptr); - Guard::Assert(ThemeObjects == nullptr); - - ObjectEntry = stream->ReadValue(); - Path = stream->ReadString(); - NumImages = stream->ReadValue(); - Name = stream->ReadString(); - ChunkSize = stream->ReadValue(); - NumRequiredObjects = stream->ReadValue(); - - RequiredObjects = Memory::AllocateArray(NumRequiredObjects); - for (uint16 i = 0; i < NumRequiredObjects; i++) - { - RequiredObjects[i] = stream->ReadValue(); - } - - switch (ObjectEntry.flags & 0x0F) { - case OBJECT_TYPE_RIDE: - RideFlags = stream->ReadValue(); - for (int i = 0; i < 2; i++) - { - RideCategory[i] = stream->ReadValue(); - } - for (int i = 0; i < 3; i++) - { - RideType[i] = stream->ReadValue(); - } - break; - case OBJECT_TYPE_SCENERY_SETS: - NumThemeObjects = stream->ReadValue(); - for (uint16 i = 0; i < NumThemeObjects; i++) - { - ThemeObjects[i] = stream->ReadValue(); - } - break; - } - } - - void Write(IStream * stream) - { - stream->WriteValue(ObjectEntry); - stream->WriteString(Path); - stream->WriteValue(NumImages); - stream->WriteString(Name); - stream->WriteValue(ChunkSize); - - stream->WriteValue(NumRequiredObjects); - for (uint16 i = 0; i < NumRequiredObjects; i++) - { - stream->WriteValue(RequiredObjects[i]); - } - - switch (ObjectEntry.flags & 0x0F) { - case OBJECT_TYPE_RIDE: - stream->WriteValue(RideFlags); - for (int i = 0; i < 2; i++) - { - stream->WriteValue(RideCategory[i]); - } - for (int i = 0; i < 3; i++) - { - stream->WriteValue(RideType[i]); - } - break; - case OBJECT_TYPE_SCENERY_SETS: - stream->WriteValue(NumThemeObjects); - for (uint16 i = 0; i < NumThemeObjects; i++) - { - stream->WriteValue(ThemeObjects[i]); - } - break; - } - } -}; - -class ObjectCache : IObjectCache -{ - void Load() override - { - // TODO - } - - void Save() override - { - // TODO - } -}; diff --git a/src/object/ObjectCache.h b/src/object/ObjectCache.h deleted file mode 100644 index cb7b4ba5b3..0000000000 --- a/src/object/ObjectCache.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers -/***************************************************************************** - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * OpenRCT2 is the work of many authors, a full list can be found in contributors.md - * For more information, visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * A full copy of the GNU General Public License can be found in licence.txt - *****************************************************************************/ -#pragma endregion - -#pragma once - -#include "../common.h" - -interface IObjectCache -{ - virtual ~IObjectCache(); - - virtual void Load() abstract; - virtual void Save() abstract; -}; diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp new file mode 100644 index 0000000000..70c1382534 --- /dev/null +++ b/src/object/ObjectRepository.cpp @@ -0,0 +1,275 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include + +#include "../common.h" +#include "../core/FileStream.hpp" +#include "../core/Guard.hpp" +#include "../core/IStream.hpp" +#include "../core/Memory.hpp" +#include "../core/String.hpp" +#include "ObjectRepository.h" + +extern "C" +{ + #include "../object.h" + #include "../platform/platform.h" +} + +constexpr uint16 OBJECT_REPOSITORY_VERSION = 6; + +struct ObjectRepositoryHeader +{ + uint16 Version; + uint32 TotalFiles; + uint64 TotalFileSize; + uint32 FileDateModifiedChecksum; + uint32 NumItems; +}; + +struct QueryDirectoryResult +{ + uint32 TotalFiles; + uint64 TotalFileSize; + uint32 FileDateModifiedChecksum; +}; + +class ObjectRepository : public IObjectRepository +{ + std::vector _items; + QueryDirectoryResult _queryDirectoryResult; + +public: + void LoadOrConstruct() + { + _queryDirectoryResult = QueryDirectory(); + if (!Load()) + { + Construct(); + Save(); + } + } + + const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) override + { + for (uint32 i = 0; i < _items.size(); i++) + { + ObjectRepositoryItem * item = &_items[i]; + rct_object_entry * itemEntry = (rct_object_entry*)&item->ObjectEntry; + if (object_entry_compare(itemEntry, objectEntry)) + { + return item; + } + } + return nullptr; + } + +private: + void Construct() + { + // TODO + } + + bool Load() + { + utf8 path[MAX_PATH]; + GetRepositoryPath(path, sizeof(path)); + + try + { + auto fs = FileStream(path, FILE_MODE_OPEN); + auto header = fs.ReadValue(); + + if (header.Version == OBJECT_REPOSITORY_VERSION && + header.TotalFiles == _queryDirectoryResult.TotalFiles && + header.TotalFileSize == _queryDirectoryResult.TotalFileSize && + header.FileDateModifiedChecksum == _queryDirectoryResult.FileDateModifiedChecksum) + { + // Header matches, so the index is not out of date + for (uint32 i = 0; i < header.NumItems; i++) + { + ObjectRepositoryItem item = ReadItem(&fs); + _items.push_back(item); + } + return true; + } + log_info("Object repository is out of date."); + return false; + } + catch (IOException ex) + { + return false; + } + } + + void Save() const + { + utf8 path[MAX_PATH]; + GetRepositoryPath(path, sizeof(path)); + + try + { + auto fs = FileStream(path, FILE_MODE_WRITE); + + // Write header + ObjectRepositoryHeader header; + header.Version = OBJECT_REPOSITORY_VERSION; + header.TotalFiles = _queryDirectoryResult.TotalFiles; + header.TotalFileSize = _queryDirectoryResult.TotalFileSize; + header.FileDateModifiedChecksum = _queryDirectoryResult.FileDateModifiedChecksum; + header.NumItems = _items.size(); + fs.WriteValue(header); + + // Write items + for (uint32 i = 0; i < header.NumItems; i++) + { + fs.WriteValue(_items[i]); + } + } + catch (IOException ex) + { + log_error("Unable to write object repository index."); + } + } + + static ObjectRepositoryItem ReadItem(IStream * stream) + { + ObjectRepositoryItem item = { 0 }; + + item.ObjectEntry = stream->ReadValue(); + item.Path = stream->ReadString(); + item.NumImages = stream->ReadValue(); + item.Name = stream->ReadString(); + item.ChunkSize = stream->ReadValue(); + item.NumRequiredObjects = stream->ReadValue(); + + item.RequiredObjects = Memory::AllocateArray(item.NumRequiredObjects); + for (uint16 i = 0; i < item.NumRequiredObjects; i++) + { + item.RequiredObjects[i] = stream->ReadValue(); + } + + switch (item.ObjectEntry.flags & 0x0F) { + case OBJECT_TYPE_RIDE: + item.RideFlags = stream->ReadValue(); + for (int i = 0; i < 2; i++) + { + item.RideCategory[i] = stream->ReadValue(); + } + for (int i = 0; i < 3; i++) + { + item.RideType[i] = stream->ReadValue(); + } + break; + case OBJECT_TYPE_SCENERY_SETS: + item.NumThemeObjects = stream->ReadValue(); + item.ThemeObjects = Memory::AllocateArray(item.NumThemeObjects); + for (uint16 i = 0; i < item.NumThemeObjects; i++) + { + item.ThemeObjects[i] = stream->ReadValue(); + } + break; + } + return item; + } + + static void WriteItem(IStream * stream, const ObjectRepositoryItem &item) + { + stream->WriteValue(item.ObjectEntry); + stream->WriteString(item.Path); + stream->WriteValue(item.NumImages); + stream->WriteString(item.Name); + stream->WriteValue(item.ChunkSize); + + stream->WriteValue(item.NumRequiredObjects); + for (uint16 i = 0; i < item.NumRequiredObjects; i++) + { + stream->WriteValue(item.RequiredObjects[i]); + } + + switch (item.ObjectEntry.flags & 0x0F) { + case OBJECT_TYPE_RIDE: + stream->WriteValue(item.RideFlags); + for (int i = 0; i < 2; i++) + { + stream->WriteValue(item.RideCategory[i]); + } + for (int i = 0; i < 3; i++) + { + stream->WriteValue(item.RideType[i]); + } + break; + case OBJECT_TYPE_SCENERY_SETS: + stream->WriteValue(item.NumThemeObjects); + for (uint16 i = 0; i < item.NumThemeObjects; i++) + { + stream->WriteValue(item.ThemeObjects[i]); + } + break; + } + } + + static void FreeItem(ObjectRepositoryItem * item) + { + Memory::Free(item->RequiredObjects); + Memory::Free(item->ThemeObjects); + item->RequiredObjects = nullptr; + item->ThemeObjects = nullptr; + } + + static void GetRepositoryPath(utf8 * buffer, size_t bufferSize) + { + platform_get_user_directory(buffer, nullptr); + strcat(buffer, "objects.idx"); + } + + static QueryDirectoryResult QueryDirectory() + { + QueryDirectoryResult result = { 0 }; + + // Enumerate through each object in the directory + int enumFileHandle = platform_enumerate_files_begin(gRCT2AddressObjectDataPath); + if (enumFileHandle != INVALID_HANDLE) + { + file_info enumFileInfo; + while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) + { + result.TotalFiles++; + result.TotalFileSize += enumFileInfo.size; + result.FileDateModifiedChecksum ^= + (uint32)(enumFileInfo.last_modified >> 32) ^ + (uint32)(enumFileInfo.last_modified & 0xFFFFFFFF); + result.FileDateModifiedChecksum = ror32(result.FileDateModifiedChecksum, 5); + } + platform_enumerate_files_end(enumFileHandle); + } + + return result; + } +}; + +static ObjectRepository * _objectRepository = nullptr; + +IObjectRepository * GetObjectRepository() +{ + if (_objectRepository == nullptr) + { + _objectRepository = new ObjectRepository(); + _objectRepository->LoadOrConstruct(); + } + return _objectRepository; +} diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h new file mode 100644 index 0000000000..c686a49de7 --- /dev/null +++ b/src/object/ObjectRepository.h @@ -0,0 +1,58 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "../common.h" + +extern "C" +{ + #include "../object.h" +} + +struct ObjectRepositoryItem +{ + rct_object_entry_extended ObjectEntry; + utf8 * Path; + uint32 NumImages; + utf8 * Name; + size_t ChunkSize; + uint16 NumRequiredObjects; + rct_object_entry_extended * RequiredObjects; + union + { + struct + { + uint16 NumThemeObjects; + rct_object_entry_extended * ThemeObjects; + }; + struct + { + uint8 RideFlags; + uint8 RideCategory[2]; + uint8 RideType[3]; + }; + }; +}; + +interface IObjectRepository +{ + virtual ~IObjectRepository() { } + + virtual const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) abstract; +}; + +IObjectRepository * GetObjectRepository(); From 3f65a3a383641bba0a17c9b98f5037a4783e1f54 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 01:41:25 +0100 Subject: [PATCH 003/116] add object scan call --- src/object/ObjectRepository.cpp | 96 ++++++++++++++++++++++++--------- src/object_list.c | 2 +- 2 files changed, 71 insertions(+), 27 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 70c1382534..72527c4532 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -21,6 +21,7 @@ #include "../core/Guard.hpp" #include "../core/IStream.hpp" #include "../core/Memory.hpp" +#include "../core/Path.hpp" #include "../core/String.hpp" #include "ObjectRepository.h" @@ -56,7 +57,8 @@ class ObjectRepository : public IObjectRepository public: void LoadOrConstruct() { - _queryDirectoryResult = QueryDirectory(); + ClearItems(); + QueryDirectory(); if (!Load()) { Construct(); @@ -79,9 +81,67 @@ public: } private: + void ClearItems() + { + for (uint32 i = 0; i < _items.size(); i++) + { + FreeItem(&_items[i]); + } + _items.clear(); + } + + void QueryDirectory() + { + QueryDirectoryResult * result = &_queryDirectoryResult; + + // Enumerate through each object in the directory + int enumFileHandle = platform_enumerate_files_begin(gRCT2AddressObjectDataPath); + if (enumFileHandle != INVALID_HANDLE) + { + file_info enumFileInfo; + while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) + { + result->TotalFiles++; + result->TotalFileSize += enumFileInfo.size; + result->FileDateModifiedChecksum ^= + (uint32)(enumFileInfo.last_modified >> 32) ^ + (uint32)(enumFileInfo.last_modified & 0xFFFFFFFF); + result->FileDateModifiedChecksum = ror32(result->FileDateModifiedChecksum, 5); + } + platform_enumerate_files_end(enumFileHandle); + } + } + void Construct() { - // TODO + utf8 objectDirectory[MAX_PATH]; + Path::GetDirectory(objectDirectory, sizeof(objectDirectory), gRCT2AddressObjectDataPath); + + int enumFileHandle = platform_enumerate_files_begin(gRCT2AddressObjectDataPath); + if (enumFileHandle != INVALID_HANDLE) + { + file_info enumFileInfo; + while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) + { + utf8 objectPath[MAX_PATH]; + String::Set(objectPath, sizeof(objectPath), objectDirectory); + Path::Append(objectPath, sizeof(objectPath), enumFileInfo.path); + + ScanObject(objectPath); + } + platform_enumerate_files_end(enumFileHandle); + } + } + + void ScanObject(utf8 * path) + { + rct_object_entry entry; + if (!object_load_entry(path, &entry)) + { + return; + } + + __nop(); } bool Load() @@ -236,30 +296,6 @@ private: platform_get_user_directory(buffer, nullptr); strcat(buffer, "objects.idx"); } - - static QueryDirectoryResult QueryDirectory() - { - QueryDirectoryResult result = { 0 }; - - // Enumerate through each object in the directory - int enumFileHandle = platform_enumerate_files_begin(gRCT2AddressObjectDataPath); - if (enumFileHandle != INVALID_HANDLE) - { - file_info enumFileInfo; - while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) - { - result.TotalFiles++; - result.TotalFileSize += enumFileInfo.size; - result.FileDateModifiedChecksum ^= - (uint32)(enumFileInfo.last_modified >> 32) ^ - (uint32)(enumFileInfo.last_modified & 0xFFFFFFFF); - result.FileDateModifiedChecksum = ror32(result.FileDateModifiedChecksum, 5); - } - platform_enumerate_files_end(enumFileHandle); - } - - return result; - } }; static ObjectRepository * _objectRepository = nullptr; @@ -273,3 +309,11 @@ IObjectRepository * GetObjectRepository() } return _objectRepository; } + +extern "C" +{ + void object_list_load() + { + IObjectRepository * objRepo = GetObjectRepository(); + } +} diff --git a/src/object_list.c b/src/object_list.c index 19cbc4f301..2fcf94c9cd 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -276,7 +276,7 @@ static int object_list_query_directory(int *outTotalFiles, uint64 *outTotalFileS * * rct2: 0x006A8B40 */ -void object_list_load() +void object_list_load_old() { int enumFileHandle, totalFiles, fileDateModifiedChecksum; uint64 totalFileSize; From 463e88583d6b19400718a3493ee2f44b10775604 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 02:52:58 +0100 Subject: [PATCH 004/116] prepare new object classes with EntranceObject --- openrct2.vcxproj | 8 ++++ src/object/EntranceObject.cpp | 29 +++++++++++++ src/object/EntranceObject.h | 38 ++++++++++++++++ src/object/ImageTable.cpp | 22 ++++++++++ src/object/ImageTable.h | 27 ++++++++++++ src/object/Object.cpp | 27 ++++++++++++ src/object/Object.h | 49 +++++++++++++++++++++ src/object/StringTable.cpp | 81 +++++++++++++++++++++++++++++++++++ src/object/StringTable.h | 41 ++++++++++++++++++ 9 files changed, 322 insertions(+) create mode 100644 src/object/EntranceObject.cpp create mode 100644 src/object/EntranceObject.h create mode 100644 src/object/ImageTable.cpp create mode 100644 src/object/ImageTable.h create mode 100644 src/object/Object.cpp create mode 100644 src/object/Object.h create mode 100644 src/object/StringTable.cpp create mode 100644 src/object/StringTable.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index aa51bb272c..9fec386430 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -117,7 +117,11 @@ + + + + @@ -418,7 +422,11 @@ + + + + diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp new file mode 100644 index 0000000000..8a95e905d3 --- /dev/null +++ b/src/object/EntranceObject.cpp @@ -0,0 +1,29 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/IStream.hpp" +#include "EntranceObject.h" + +void EntranceObject::Load(IStream * stream) +{ + _legacyType.string_idx = stream->ReadValue(); + _legacyType.image_id = stream->ReadValue(); + _legacyType.scrolling_mode = stream->ReadValue(); + _legacyType.text_height = stream->ReadValue(); + + LoadStringTable(stream, 0); + LoadImageTable(stream); +} diff --git a/src/object/EntranceObject.h b/src/object/EntranceObject.h new file mode 100644 index 0000000000..608cbe788a --- /dev/null +++ b/src/object/EntranceObject.h @@ -0,0 +1,38 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "Object.h" + +extern "C" +{ + #include "../world/entrance.h" +} + +class EntranceObject : public Object +{ +private: + rct_object_entry _objectEntry; + rct_entrance_type _legacyType; + +public: + const rct_object_entry * GetObjectEntry() override { return &_objectEntry; } + void * GetLegacyData() override { return &_legacyType; } + +protected: + void Load(IStream * stream) override; +}; diff --git a/src/object/ImageTable.cpp b/src/object/ImageTable.cpp new file mode 100644 index 0000000000..9a20b42abc --- /dev/null +++ b/src/object/ImageTable.cpp @@ -0,0 +1,22 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "ImageTable.h" + +void ImageTable::Read(IStream * stream) +{ + // TODO +} diff --git a/src/object/ImageTable.h b/src/object/ImageTable.h new file mode 100644 index 0000000000..30cf7ae5d6 --- /dev/null +++ b/src/object/ImageTable.h @@ -0,0 +1,27 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "../common.h" + +interface IStream; + +class ImageTable +{ +public: + void Read(IStream * stream); +}; \ No newline at end of file diff --git a/src/object/Object.cpp b/src/object/Object.cpp new file mode 100644 index 0000000000..e758e2e1c1 --- /dev/null +++ b/src/object/Object.cpp @@ -0,0 +1,27 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "Object.h" + +void Object::LoadStringTable(IStream * stream, uint8 id) +{ + _stringTable.Read(stream, id); +} + +void Object::LoadImageTable(IStream * stream) +{ + _imageTable.Read(stream); +} diff --git a/src/object/Object.h b/src/object/Object.h new file mode 100644 index 0000000000..00c85cf5f9 --- /dev/null +++ b/src/object/Object.h @@ -0,0 +1,49 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "../common.h" +#include "ImageTable.h" +#include "StringTable.h" + +extern "C" +{ + #include "../object.h" +} + +interface IStream; + +class Object +{ +private: + StringTable _stringTable; + ImageTable _imageTable; + +public: + virtual ~Object() { } + + // Legacy data structures + virtual const rct_object_entry * GetObjectEntry() abstract; + virtual void * GetLegacyData() abstract; + +protected: + virtual void Load(IStream * stream) abstract; + virtual void Unload() abstract; + + void LoadStringTable(IStream * stream, uint8 id); + void LoadImageTable(IStream * stream); +}; diff --git a/src/object/StringTable.cpp b/src/object/StringTable.cpp new file mode 100644 index 0000000000..578dc28bc4 --- /dev/null +++ b/src/object/StringTable.cpp @@ -0,0 +1,81 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include +#include "../core/IStream.hpp" +#include "../core/String.hpp" +#include "../localisation/LanguagePack.h" +#include "StringTable.h" + +constexpr uint8 RCT2_LANGUAGE_ID_ENGLISH_UK = 0; +constexpr uint8 RCT2_LANGUAGE_ID_BLANK = 254; +constexpr uint8 RCT2_LANGUAGE_ID_END = 255; + +bool StringIsBlank(utf8 * str) +{ + for (utf8 * ch = str; *ch != '\0'; ch++) + { + if (!isblank(*ch)) + { + return false; + } + } + return true; +} + +void StringTable::Read(IStream * stream, uint8 id) +{ + uint8 languageId; + while ((languageId = stream->ReadValue()) != RCT2_LANGUAGE_ID_END) + { + StringTableEntry entry; + entry.Id = id; + entry.LanguageId = languageId; + entry.Text = stream->ReadString(); + + if (StringIsBlank(entry.Text)) + { + entry.LanguageId = RCT2_LANGUAGE_ID_BLANK; + } + + _strings.push_back(entry); + } + Sort(); +} + +void StringTable::Sort() +{ + std::sort(_strings.begin(), _strings.end(), [](const StringTableEntry &a, const StringTableEntry &b) -> int + { + if (a.Id == b.Id) + { + if (a.LanguageId == b.LanguageId) + { + return _strcmpi(a.Text, b.Text); + } + if (a.LanguageId == LanguagesDescriptors[gCurrentLanguage].rct2_original_id) + { + return -1; + } + if (a.LanguageId == RCT2_LANGUAGE_ID_ENGLISH_UK) + { + return -1; + } + return 1; + } + return a.Id - b.Id; + }); +} diff --git a/src/object/StringTable.h b/src/object/StringTable.h new file mode 100644 index 0000000000..4b14755d8a --- /dev/null +++ b/src/object/StringTable.h @@ -0,0 +1,41 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include +#include "../common.h" + +interface IStream; + +struct StringTableEntry +{ + uint8 Id; + uint8 LanguageId; + utf8 * Text; +}; + +class StringTable +{ +private: + std::vector _strings; + +public: + void Read(IStream * stream, uint8 id); + +private: + void Sort(); +}; \ No newline at end of file From 28ae0cbee6d6bef05e17cf940f9f2176745341cb Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 10:48:54 +0100 Subject: [PATCH 005/116] add image table reading --- src/object/ImageTable.cpp | 37 ++++++++++++++++++++++++++++++++++++- src/object/ImageTable.h | 13 +++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/object/ImageTable.cpp b/src/object/ImageTable.cpp index 9a20b42abc..ebd877dbd7 100644 --- a/src/object/ImageTable.cpp +++ b/src/object/ImageTable.cpp @@ -14,9 +14,44 @@ *****************************************************************************/ #pragma endregion +#include "../core/IStream.hpp" +#include "../core/Memory.hpp" #include "ImageTable.h" +ImageTable::~ImageTable() +{ + Memory::Free(_data); + _data = nullptr; + _dataSize = 0; +} + void ImageTable::Read(IStream * stream) { - // TODO + uint32 numImages = stream->ReadValue(); + uint32 imageDataSize = stream->ReadValue(); + + _dataSize = imageDataSize; + _data = Memory::Reallocate(_data, _dataSize); + + // Read g1 element headers + uintptr_t imageDataBase = (uintptr_t)_data; + for (uint32 i = 0; i < numImages; i++) + { + rct_g1_element g1Element; + + uintptr_t imageDataOffset = (uintptr_t)stream->ReadValue(); + g1Element.offset = (uint8*)(imageDataBase + imageDataOffset); + + g1Element.width = stream->ReadValue(); + g1Element.height = stream->ReadValue(); + g1Element.x_offset = stream->ReadValue(); + g1Element.y_offset = stream->ReadValue(); + g1Element.flags = stream->ReadValue(); + g1Element.zoomed_offset = stream->ReadValue(); + + _entries.push_back(g1Element); + } + + // Read g1 element data + stream->Read(_data, _dataSize); } diff --git a/src/object/ImageTable.h b/src/object/ImageTable.h index 30cf7ae5d6..5514694fb4 100644 --- a/src/object/ImageTable.h +++ b/src/object/ImageTable.h @@ -16,12 +16,25 @@ #pragma once +#include #include "../common.h" +extern "C" +{ + #include "../drawing/drawing.h" +} + interface IStream; class ImageTable { +private: + std::vector _entries; + void * _data = nullptr; + size_t _dataSize = 0; + public: + ~ImageTable(); + void Read(IStream * stream); }; \ No newline at end of file From c9a135799404fc0f440e732e8357f9fb133a08c5 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 12:04:12 +0100 Subject: [PATCH 006/116] add new MemoryStream class --- openrct2.vcxproj | 3 +- src/core/FileStream.hpp | 5 - src/core/IDisposable.hpp | 27 ------ src/core/IStream.hpp | 6 +- src/core/MemoryStream.cpp | 186 ++++++++++++++++++++++++++++++++++++++ src/core/MemoryStream.h | 68 ++++++++++++++ 6 files changed, 258 insertions(+), 37 deletions(-) delete mode 100644 src/core/IDisposable.hpp create mode 100644 src/core/MemoryStream.cpp create mode 100644 src/core/MemoryStream.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 9fec386430..641b84d74f 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -45,6 +45,7 @@ + @@ -345,12 +346,12 @@ - + diff --git a/src/core/FileStream.hpp b/src/core/FileStream.hpp index dce4ee866c..9a0bca777d 100644 --- a/src/core/FileStream.hpp +++ b/src/core/FileStream.hpp @@ -67,11 +67,6 @@ public: } ~FileStream() - { - Dispose(); - } - - void Dispose() override { if (!_disposed) { diff --git a/src/core/IDisposable.hpp b/src/core/IDisposable.hpp deleted file mode 100644 index 7a0492f877..0000000000 --- a/src/core/IDisposable.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers -/***************************************************************************** - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * OpenRCT2 is the work of many authors, a full list can be found in contributors.md - * For more information, visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * A full copy of the GNU General Public License can be found in licence.txt - *****************************************************************************/ -#pragma endregion - -#pragma once - -#include "../common.h" - -/** - * Represents an object that can be disposed. So things can explicitly close resources before the destructor kicks in. - */ -interface IDisposable -{ - virtual void Dispose() abstract; -}; diff --git a/src/core/IStream.hpp b/src/core/IStream.hpp index 9f85e1b229..577f1d29e8 100644 --- a/src/core/IStream.hpp +++ b/src/core/IStream.hpp @@ -17,9 +17,7 @@ #pragma once #include "../common.h" - #include "Exception.hpp" -#include "IDisposable.hpp" enum { STREAM_SEEK_BEGIN, @@ -30,12 +28,12 @@ enum { /** * Represents a stream that can be read or written to. Implemented by types such as FileStream, NetworkStream or MemoryStream. */ -interface IStream : public IDisposable +interface IStream { /////////////////////////////////////////////////////////////////////////// // Interface methods /////////////////////////////////////////////////////////////////////////// - // virtual ~IStream() abstract; + virtual ~IStream() { } virtual bool CanRead() const abstract; virtual bool CanWrite() const abstract; diff --git a/src/core/MemoryStream.cpp b/src/core/MemoryStream.cpp new file mode 100644 index 0000000000..2e6d46f525 --- /dev/null +++ b/src/core/MemoryStream.cpp @@ -0,0 +1,186 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "Math.hpp" +#include "Memory.hpp" +#include "MemoryStream.h" + +MemoryStream::MemoryStream() +{ + _access = MEMORY_ACCESS_READ | + MEMORY_ACCESS_WRITE | + MEMORY_ACCESS_OWNER; + _dataCapacity = 0; + _dataSize = 0; + _data = nullptr; + _position = nullptr; +} + +MemoryStream::MemoryStream(const MemoryStream ©) +{ + _access = copy._access; + _dataCapacity = copy._dataCapacity; + _dataSize = copy._dataSize; + + if (_access == MEMORY_ACCESS_OWNER) + { + _data = Memory::Duplicate(copy._data, _dataCapacity); + _position = (void*)((uintptr_t)_data + copy.GetPosition()); + } +} + +MemoryStream::MemoryStream(size_t capacity) +{ + _access = MEMORY_ACCESS_READ | + MEMORY_ACCESS_WRITE | + MEMORY_ACCESS_OWNER; + _dataCapacity = capacity; + _dataSize = 0; + _data = Memory::Allocate(capacity); + _position = _data; +} + +MemoryStream::MemoryStream(void * data, size_t dataSize, MEMORY_ACCESS access) +{ + _access = access; + _dataCapacity = dataSize; + _dataSize = dataSize; + _data = data; + _position = _data; +} + +MemoryStream::MemoryStream(const void * data, size_t dataSize) + : MemoryStream((void *)data, dataSize, MEMORY_ACCESS_READ) +{ +} + +MemoryStream::~MemoryStream() +{ + if (MEMORY_ACCESS_OWNER) + { + Memory::Free(_data); + } + _dataCapacity = 0; + _dataSize = 0; + _data = nullptr; +} + +void * MemoryStream::GetData() const +{ + return Memory::Duplicate(_data, _dataSize); +} + +void * MemoryStream::TakeData() +{ + _access &= ~MEMORY_ACCESS_OWNER; + return _data; +} + +bool MemoryStream::CanRead() const +{ + return (_access & MEMORY_ACCESS_READ) != 0; +} + +bool MemoryStream::CanWrite() const +{ + return (_access & MEMORY_ACCESS_WRITE) != 0; +} + +uint64 MemoryStream::GetLength() const +{ + return _dataSize; +} + +uint64 MemoryStream::GetPosition() const +{ + return (uint64)((uintptr_t)_position - (uintptr_t)_data); +} + +void MemoryStream::SetPosition(uint64 position) +{ + Seek(position, STREAM_SEEK_BEGIN); +} + +void MemoryStream::Seek(sint64 offset, int origin) +{ + uint64 newPosition; + switch (origin) { + default: + case STREAM_SEEK_BEGIN: + newPosition = offset; + break; + case STREAM_SEEK_CURRENT: + newPosition = GetPosition() + offset; + break; + case STREAM_SEEK_END: + newPosition = _dataSize + offset; + break; + } + + if (newPosition > _dataSize) + { + throw IOException("New position out of bounds."); + } + _position = (void*)((uintptr_t)_data + (uintptr_t)newPosition); +} + +void MemoryStream::Read(void * buffer, uint64 length) +{ + uint64 position = GetPosition(); + if (position + length > _dataSize) + { + throw IOException("Attempted to read past end of stream."); + } + + Memory::Copy(buffer, _position, (size_t)length); + _position = (void*)((uintptr_t)_position + length); +} + +void MemoryStream::Write(const void * buffer, uint64 length) +{ + uint64 position = GetPosition(); + uint64 nextPosition = position + length; + if (nextPosition > _dataCapacity) + { + if (_access & MEMORY_ACCESS_OWNER) + { + EnsureCapacity((size_t)nextPosition); + } + else + { + throw IOException("Attempted to write past end of stream."); + } + } + + Memory::Copy(_position, buffer, (size_t)length); + _position = (void*)((uintptr_t)_position + length); + _dataSize = Math::Max(_dataSize, (size_t)nextPosition); +} + +void MemoryStream::EnsureCapacity(size_t capacity) +{ + if (_dataCapacity < capacity) + { + size_t newCapacity = Math::Max(8, _dataCapacity); + while (newCapacity < capacity) + { + newCapacity *= 2; + } + + _dataCapacity = newCapacity; + Memory::Reallocate(_data, _dataCapacity); + } +} diff --git a/src/core/MemoryStream.h b/src/core/MemoryStream.h new file mode 100644 index 0000000000..c7a2a0763b --- /dev/null +++ b/src/core/MemoryStream.h @@ -0,0 +1,68 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "../common.h" +#include "IStream.hpp" + +enum MEMORY_ACCESS +{ + MEMORY_ACCESS_READ = 1 << 0, + MEMORY_ACCESS_WRITE = 1 << 1, + MEMORY_ACCESS_OWNER = 1 << 2, +}; + +/** + * A stream for reading and writing to files. Wraps an SDL_RWops, SDL2's cross platform file stream. + */ +class MemoryStream : public IStream +{ +private: + uint16 _access; + size_t _dataCapacity; + size_t _dataSize; + void * _data; + void * _position; + +public: + MemoryStream(); + MemoryStream(const MemoryStream ©); + explicit MemoryStream(size_t capacity); + MemoryStream(void * data, size_t dataSize, MEMORY_ACCESS access = MEMORY_ACCESS_READ); + MemoryStream(const void * data, size_t dataSize); + virtual ~MemoryStream(); + + void * GetData() const; + void * TakeData(); + + /////////////////////////////////////////////////////////////////////////// + // ISteam methods + /////////////////////////////////////////////////////////////////////////// + bool CanRead() const override; + bool CanWrite() const override; + + uint64 GetLength() const override; + uint64 GetPosition() const override; + void SetPosition(uint64 position) override; + void Seek(sint64 offset, int origin) override; + + void Read(void * buffer, uint64 length) override; + void Write(const void * buffer, uint64 length) override; + +private: + void EnsureCapacity(size_t capacity); +}; From 2449b7dbf01315663eac9e7524a2b25cf23164cc Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 12:30:20 +0100 Subject: [PATCH 007/116] add reading of entrance objects --- openrct2.vcxproj | 2 + src/object/EntranceObject.cpp | 12 +++++- src/object/EntranceObject.h | 5 ++- src/object/Object.h | 5 ++- src/object/ObjectFactory.cpp | 71 +++++++++++++++++++++++++++++++++ src/object/ObjectFactory.h | 27 +++++++++++++ src/object/ObjectRepository.cpp | 10 ++--- src/object/StringTable.cpp | 34 ++++++++++++---- src/object/StringTable.h | 1 + 9 files changed, 150 insertions(+), 17 deletions(-) create mode 100644 src/object/ObjectFactory.cpp create mode 100644 src/object/ObjectFactory.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 641b84d74f..34dfd4296f 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -121,6 +121,7 @@ + @@ -426,6 +427,7 @@ + diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index 8a95e905d3..73149bcb11 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -17,7 +17,7 @@ #include "../core/IStream.hpp" #include "EntranceObject.h" -void EntranceObject::Load(IStream * stream) +void EntranceObject::ReadLegacy(IStream * stream) { _legacyType.string_idx = stream->ReadValue(); _legacyType.image_id = stream->ReadValue(); @@ -27,3 +27,13 @@ void EntranceObject::Load(IStream * stream) LoadStringTable(stream, 0); LoadImageTable(stream); } + +void EntranceObject::Load() +{ + +} + +void EntranceObject::Unload() +{ + +} diff --git a/src/object/EntranceObject.h b/src/object/EntranceObject.h index 608cbe788a..e9586a5de1 100644 --- a/src/object/EntranceObject.h +++ b/src/object/EntranceObject.h @@ -33,6 +33,7 @@ public: const rct_object_entry * GetObjectEntry() override { return &_objectEntry; } void * GetLegacyData() override { return &_legacyType; } -protected: - void Load(IStream * stream) override; + void ReadLegacy(IStream * stream) override; + void Load() override; + void Unload() override; }; diff --git a/src/object/Object.h b/src/object/Object.h index 00c85cf5f9..0f5548eeca 100644 --- a/src/object/Object.h +++ b/src/object/Object.h @@ -40,10 +40,11 @@ public: virtual const rct_object_entry * GetObjectEntry() abstract; virtual void * GetLegacyData() abstract; -protected: - virtual void Load(IStream * stream) abstract; + virtual void ReadLegacy(IStream * stream) abstract; + virtual void Load() abstract; virtual void Unload() abstract; +protected: void LoadStringTable(IStream * stream, uint8 id); void LoadImageTable(IStream * stream); }; diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp new file mode 100644 index 0000000000..aa926e3b0b --- /dev/null +++ b/src/object/ObjectFactory.cpp @@ -0,0 +1,71 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/FileStream.hpp" +#include "../core/Memory.hpp" +#include "../core/MemoryStream.h" +#include "EntranceObject.h" +#include "Object.h" +#include "ObjectFactory.h" + +extern "C" +{ + #include "../object.h" + #include "../util/sawyercoding.h" +} + +namespace ObjectFactory +{ + Object * CreateObjectFromLegacyFile(utf8 * path) + { + Object * result = nullptr; + + SDL_RWops * file = SDL_RWFromFile(path, "rb"); + if (file != nullptr) + { + rct_object_entry entry; + if (SDL_RWread(file, &entry, sizeof(entry), 1) == 1) + { + uint8 objectType = entry.flags & 0x0F; + result = CreateObject(objectType); + if (result != nullptr) + { + size_t bufferSize = 0x600000; + void * buffer = Memory::Allocate(bufferSize); + bufferSize = sawyercoding_read_chunk_with_size(file, (uint8 *)buffer, bufferSize); + buffer = Memory::Reallocate(buffer, bufferSize); + auto ms = MemoryStream(buffer, bufferSize); + result->ReadLegacy(&ms); + } + } + SDL_RWclose(file); + } + return result; + } + + Object * CreateObject(uint8 type) + { + Object * result = nullptr; + + switch (type) { + case OBJECT_TYPE_PARK_ENTRANCE: + result = new EntranceObject(); + break; + } + + return result; + } +} diff --git a/src/object/ObjectFactory.h b/src/object/ObjectFactory.h new file mode 100644 index 0000000000..5819adf242 --- /dev/null +++ b/src/object/ObjectFactory.h @@ -0,0 +1,27 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "../common.h" + +class Object; + +namespace ObjectFactory +{ + Object * CreateObjectFromLegacyFile(utf8 * path); + Object * CreateObject(uint8 type); +} diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 72527c4532..954814940b 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -23,6 +23,8 @@ #include "../core/Memory.hpp" #include "../core/Path.hpp" #include "../core/String.hpp" +#include "Object.h" +#include "ObjectFactory.h" #include "ObjectRepository.h" extern "C" @@ -135,13 +137,11 @@ private: void ScanObject(utf8 * path) { - rct_object_entry entry; - if (!object_load_entry(path, &entry)) + Object * object = ObjectFactory::CreateObjectFromLegacyFile(path); + if (object != nullptr) { - return; + // TODO } - - __nop(); } bool Load() diff --git a/src/object/StringTable.cpp b/src/object/StringTable.cpp index 578dc28bc4..9a0c823b3e 100644 --- a/src/object/StringTable.cpp +++ b/src/object/StringTable.cpp @@ -36,6 +36,14 @@ bool StringIsBlank(utf8 * str) return true; } +StringTable::~StringTable() +{ + for (auto entry : _strings) + { + Memory::Free(entry.Text); + } +} + void StringTable::Read(IStream * stream, uint8 id) { uint8 languageId; @@ -58,24 +66,36 @@ void StringTable::Read(IStream * stream, uint8 id) void StringTable::Sort() { - std::sort(_strings.begin(), _strings.end(), [](const StringTableEntry &a, const StringTableEntry &b) -> int + std::sort(_strings.begin(), _strings.end(), [](const StringTableEntry &a, const StringTableEntry &b) -> bool { if (a.Id == b.Id) { if (a.LanguageId == b.LanguageId) { - return _strcmpi(a.Text, b.Text); + return _strcmpi(a.Text, b.Text) == -1; } - if (a.LanguageId == LanguagesDescriptors[gCurrentLanguage].rct2_original_id) + + uint8 currentLanguage = LanguagesDescriptors[gCurrentLanguage].rct2_original_id; + if (a.LanguageId == currentLanguage) { - return -1; + return true; } + if (b.LanguageId == currentLanguage) + { + return false; + } + if (a.LanguageId == RCT2_LANGUAGE_ID_ENGLISH_UK) { - return -1; + return true; } - return 1; + if (b.LanguageId == RCT2_LANGUAGE_ID_ENGLISH_UK) + { + return false; + } + + return a.LanguageId < b.LanguageId; } - return a.Id - b.Id; + return a.Id < b.Id; }); } diff --git a/src/object/StringTable.h b/src/object/StringTable.h index 4b14755d8a..8458a63346 100644 --- a/src/object/StringTable.h +++ b/src/object/StringTable.h @@ -34,6 +34,7 @@ private: std::vector _strings; public: + ~StringTable(); void Read(IStream * stream, uint8 id); private: From e93b2141a14c35cb166c41a7b9e7f5f9f528e9b3 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 14:44:04 +0100 Subject: [PATCH 008/116] save object details to repository file --- src/object/EntranceObject.cpp | 14 ++++++++++++-- src/object/EntranceObject.h | 8 +++++--- src/object/Object.cpp | 9 ++------- src/object/Object.h | 16 +++++++++------- src/object/ObjectFactory.cpp | 10 +++++----- src/object/ObjectFactory.h | 2 +- src/object/ObjectRepository.cpp | 17 +++++++++++++++-- src/object/StringTable.cpp | 12 ++++++++++++ src/object/StringTable.h | 4 +++- 9 files changed, 64 insertions(+), 28 deletions(-) diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index 73149bcb11..d1b0e3a45b 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -17,6 +17,11 @@ #include "../core/IStream.hpp" #include "EntranceObject.h" +enum OBJ_STRING_ID +{ + OBJ_STRING_ID_NAME, +}; + void EntranceObject::ReadLegacy(IStream * stream) { _legacyType.string_idx = stream->ReadValue(); @@ -24,8 +29,8 @@ void EntranceObject::ReadLegacy(IStream * stream) _legacyType.scrolling_mode = stream->ReadValue(); _legacyType.text_height = stream->ReadValue(); - LoadStringTable(stream, 0); - LoadImageTable(stream); + StringTable.Read(stream, OBJ_STRING_ID_NAME); + ImageTable.Read(stream); } void EntranceObject::Load() @@ -37,3 +42,8 @@ void EntranceObject::Unload() { } + +const utf8 * EntranceObject::GetName() +{ + return StringTable.GetString(OBJ_STRING_ID_NAME); +} diff --git a/src/object/EntranceObject.h b/src/object/EntranceObject.h index e9586a5de1..08091cbcd5 100644 --- a/src/object/EntranceObject.h +++ b/src/object/EntranceObject.h @@ -26,14 +26,16 @@ extern "C" class EntranceObject : public Object { private: - rct_object_entry _objectEntry; rct_entrance_type _legacyType; public: - const rct_object_entry * GetObjectEntry() override { return &_objectEntry; } - void * GetLegacyData() override { return &_legacyType; } + explicit EntranceObject(const rct_object_entry &entry) : Object(entry) { }; + + void * GetLegacyData() override { return &_legacyType; } void ReadLegacy(IStream * stream) override; void Load() override; void Unload() override; + + const utf8 * GetName() override; }; diff --git a/src/object/Object.cpp b/src/object/Object.cpp index e758e2e1c1..decc2e977f 100644 --- a/src/object/Object.cpp +++ b/src/object/Object.cpp @@ -16,12 +16,7 @@ #include "Object.h" -void Object::LoadStringTable(IStream * stream, uint8 id) +Object::Object(const rct_object_entry &entry) { - _stringTable.Read(stream, id); -} - -void Object::LoadImageTable(IStream * stream) -{ - _imageTable.Read(stream); + _objectEntry = entry; } diff --git a/src/object/Object.h b/src/object/Object.h index 0f5548eeca..a68b19c03c 100644 --- a/src/object/Object.h +++ b/src/object/Object.h @@ -30,21 +30,23 @@ interface IStream; class Object { private: - StringTable _stringTable; - ImageTable _imageTable; + rct_object_entry _objectEntry; + +protected: + StringTable StringTable; + ImageTable ImageTable; public: + explicit Object(const rct_object_entry &entry); virtual ~Object() { } // Legacy data structures - virtual const rct_object_entry * GetObjectEntry() abstract; - virtual void * GetLegacyData() abstract; + const rct_object_entry * GetObjectEntry() const { return &_objectEntry; } + virtual void * GetLegacyData() abstract; virtual void ReadLegacy(IStream * stream) abstract; virtual void Load() abstract; virtual void Unload() abstract; -protected: - void LoadStringTable(IStream * stream, uint8 id); - void LoadImageTable(IStream * stream); + virtual const utf8 * GetName() abstract; }; diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index aa926e3b0b..957f10e34b 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -39,8 +39,7 @@ namespace ObjectFactory rct_object_entry entry; if (SDL_RWread(file, &entry, sizeof(entry), 1) == 1) { - uint8 objectType = entry.flags & 0x0F; - result = CreateObject(objectType); + result = CreateObject(entry); if (result != nullptr) { size_t bufferSize = 0x600000; @@ -56,13 +55,14 @@ namespace ObjectFactory return result; } - Object * CreateObject(uint8 type) + Object * CreateObject(const rct_object_entry &entry) { Object * result = nullptr; - switch (type) { + uint8 objectType = entry.flags & 0x0F; + switch (objectType) { case OBJECT_TYPE_PARK_ENTRANCE: - result = new EntranceObject(); + result = new EntranceObject(entry); break; } diff --git a/src/object/ObjectFactory.h b/src/object/ObjectFactory.h index 5819adf242..4d89b7ca6e 100644 --- a/src/object/ObjectFactory.h +++ b/src/object/ObjectFactory.h @@ -23,5 +23,5 @@ class Object; namespace ObjectFactory { Object * CreateObjectFromLegacyFile(utf8 * path); - Object * CreateObject(uint8 type); + Object * CreateObject(const rct_object_entry &entry); } diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 954814940b..203a1ffe79 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -57,6 +57,11 @@ class ObjectRepository : public IObjectRepository QueryDirectoryResult _queryDirectoryResult; public: + ~ObjectRepository() + { + ClearItems(); + } + void LoadOrConstruct() { ClearItems(); @@ -140,7 +145,11 @@ private: Object * object = ObjectFactory::CreateObjectFromLegacyFile(path); if (object != nullptr) { - // TODO + ObjectRepositoryItem item = { 0 }; + Memory::Copy(&item.ObjectEntry, object->GetObjectEntry(), sizeof(rct_object_entry)); + item.Path = String::Duplicate(path); + item.Name = String::Duplicate(object->GetName()); + _items.push_back(item); } } @@ -197,7 +206,7 @@ private: // Write items for (uint32 i = 0; i < header.NumItems; i++) { - fs.WriteValue(_items[i]); + WriteItem(&fs, _items[i]); } } catch (IOException ex) @@ -285,8 +294,12 @@ private: static void FreeItem(ObjectRepositoryItem * item) { + Memory::Free(item->Path); + Memory::Free(item->Name); Memory::Free(item->RequiredObjects); Memory::Free(item->ThemeObjects); + item->Path = nullptr; + item->Name = nullptr; item->RequiredObjects = nullptr; item->ThemeObjects = nullptr; } diff --git a/src/object/StringTable.cpp b/src/object/StringTable.cpp index 9a0c823b3e..4939aefb21 100644 --- a/src/object/StringTable.cpp +++ b/src/object/StringTable.cpp @@ -64,6 +64,18 @@ void StringTable::Read(IStream * stream, uint8 id) Sort(); } +const utf8 * StringTable::GetString(uint8 id) +{ + for (auto &string : _strings) + { + if (string.Id == id) + { + return string.Text; + } + } + return nullptr; +} + void StringTable::Sort() { std::sort(_strings.begin(), _strings.end(), [](const StringTableEntry &a, const StringTableEntry &b) -> bool diff --git a/src/object/StringTable.h b/src/object/StringTable.h index 8458a63346..aef6ba6d75 100644 --- a/src/object/StringTable.h +++ b/src/object/StringTable.h @@ -35,7 +35,9 @@ private: public: ~StringTable(); - void Read(IStream * stream, uint8 id); + + void Read(IStream * stream, uint8 id); + const utf8 * GetString(uint8 id); private: void Sort(); From 78e15b1d56207c6da99afd5b0b0bed8555f2f08a Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 16:34:35 +0100 Subject: [PATCH 009/116] start getting object loading working --- openrct2.vcxproj | 2 + src/drawing/drawing.h | 2 + src/drawing/sprite.c | 23 +++++++++ src/localisation/language.cpp | 13 +++++ src/localisation/language.h | 2 + src/object.c | 2 +- src/object/EntranceObject.cpp | 11 ++++- src/object/ImageTable.h | 4 +- src/object/Object.h | 3 +- src/object/ObjectFactory.cpp | 6 ++- src/object/ObjectFactory.h | 2 +- src/object/ObjectRepository.cpp | 88 +++++++++++++++++++++++++++++++++ src/object/ObjectRepository.h | 3 +- src/object/StexObject.cpp | 77 +++++++++++++++++++++++++++++ src/object/StexObject.h | 45 +++++++++++++++++ src/scenario.h | 2 + src/scenario_list.c | 24 --------- 17 files changed, 277 insertions(+), 32 deletions(-) create mode 100644 src/object/StexObject.cpp create mode 100644 src/object/StexObject.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 34dfd4296f..78e43f5706 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -123,6 +123,7 @@ + @@ -429,6 +430,7 @@ + diff --git a/src/drawing/drawing.h b/src/drawing/drawing.h index 04367bc40e..4c0d568ea8 100644 --- a/src/drawing/drawing.h +++ b/src/drawing/drawing.h @@ -176,6 +176,8 @@ int gfx_load_g2(); void gfx_unload_g1(); void gfx_unload_g2(); rct_g1_element* gfx_get_g1_element(int image_id); +uint32 gfx_object_allocate_images(const rct_g1_element * images, uint32 count); +void gfx_object_free_images(uint32 baseImageId, uint32 count); void sub_68371D(); void FASTCALL gfx_rle_sprite_to_buffer(const uint8* RESTRICT source_bits_pointer, uint8* RESTRICT dest_bits_pointer, const uint8* RESTRICT palette_pointer, const rct_drawpixelinfo * RESTRICT dpi, int image_type, int source_y_start, int height, int source_x_start, int width); void FASTCALL gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 tertiary_colour); diff --git a/src/drawing/sprite.c b/src/drawing/sprite.c index 26458bb1ab..0c16ef28cc 100644 --- a/src/drawing/sprite.c +++ b/src/drawing/sprite.c @@ -173,6 +173,29 @@ int gfx_load_g2() return 0; } +static uint32 _nextImageId = 29294; + +uint32 gfx_object_allocate_images(const rct_g1_element * images, uint32 count) +{ + uint32 baseImageId = _nextImageId; + for (uint32 i = 0; i < count; i++) { + uint32 imageId = _nextImageId; + if (imageId >= 291438) { + log_error("Reached maximum image limit."); + break; + } + + g1Elements[imageId] = images[i]; + drawing_engine_invalidate_image(imageId); + _nextImageId++; + } + return baseImageId; +} + +void gfx_object_free_images(uint32 baseImageId, uint32 count) +{ +} + /** * This function looks like it initialises the 0x009E3CE4 array which references sprites used for background / palette mixing or * something. Further investigation is needed. diff --git a/src/localisation/language.cpp b/src/localisation/language.cpp index 43c9e635f0..70f357c162 100644 --- a/src/localisation/language.cpp +++ b/src/localisation/language.cpp @@ -455,4 +455,17 @@ bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_s outStringIds[2] != STR_NONE; } +static rct_string_id _nextObjectStringId = NONSTEX_BASE_STRING_ID; + +rct_string_id language_allocate_object_string(const utf8 * target) +{ + rct_string_id stringId = _nextObjectStringId++; + _languageCurrent->SetString(stringId, target); + return stringId; +} + +void language_free_object_string(rct_string_id stringId) +{ +} + } diff --git a/src/localisation/language.h b/src/localisation/language.h index 8e2d1f8511..4bcab7a61f 100644 --- a/src/localisation/language.h +++ b/src/localisation/language.h @@ -82,5 +82,7 @@ wchar_t *utf8_to_widechar(const utf8 *src); utf8 *widechar_to_utf8(const wchar_t *src); bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_string_id *outStringIds); +rct_string_id language_allocate_object_string(const utf8 * target); +void language_free_object_string(rct_string_id stringId); #endif diff --git a/src/object.c b/src/object.c index ce0d7c86e3..225cf5518f 100644 --- a/src/object.c +++ b/src/object.c @@ -149,7 +149,7 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi * * rct2: 0x006A985D */ -int object_load_chunk(int groupIndex, rct_object_entry *entry, int* chunkSize) +int object_load_chunk_old(int groupIndex, rct_object_entry *entry, int* chunkSize) { // Alow chunkSize to be null int tempChunkSize; diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index d1b0e3a45b..edd1db42b5 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -17,6 +17,12 @@ #include "../core/IStream.hpp" #include "EntranceObject.h" +extern "C" +{ + #include "../drawing/drawing.h" + #include "../localisation/localisation.h" +} + enum OBJ_STRING_ID { OBJ_STRING_ID_NAME, @@ -35,12 +41,13 @@ void EntranceObject::ReadLegacy(IStream * stream) void EntranceObject::Load() { - + _legacyType.string_idx = language_allocate_object_string(GetName()); + _legacyType.image_id = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); } void EntranceObject::Unload() { - + language_free_object_string(_legacyType.string_idx); } const utf8 * EntranceObject::GetName() diff --git a/src/object/ImageTable.h b/src/object/ImageTable.h index 5514694fb4..788501cf44 100644 --- a/src/object/ImageTable.h +++ b/src/object/ImageTable.h @@ -36,5 +36,7 @@ private: public: ~ImageTable(); - void Read(IStream * stream); + void Read(IStream * stream); + const rct_g1_element * GetImages() const { return _entries.data(); } + uint32 GetCount() const { return _entries.size(); }; }; \ No newline at end of file diff --git a/src/object/Object.h b/src/object/Object.h index a68b19c03c..adeebc0894 100644 --- a/src/object/Object.h +++ b/src/object/Object.h @@ -48,5 +48,6 @@ public: virtual void Load() abstract; virtual void Unload() abstract; - virtual const utf8 * GetName() abstract; + virtual uint8 GetObjectType() { return _objectEntry.flags & 0x0F; } + virtual const utf8 * GetName() abstract; }; diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 957f10e34b..7cd94070fa 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -20,6 +20,7 @@ #include "EntranceObject.h" #include "Object.h" #include "ObjectFactory.h" +#include "StexObject.h" extern "C" { @@ -29,7 +30,7 @@ extern "C" namespace ObjectFactory { - Object * CreateObjectFromLegacyFile(utf8 * path) + Object * CreateObjectFromLegacyFile(const utf8 * path) { Object * result = nullptr; @@ -64,6 +65,9 @@ namespace ObjectFactory case OBJECT_TYPE_PARK_ENTRANCE: result = new EntranceObject(entry); break; + case OBJECT_TYPE_SCENARIO_TEXT: + result = new StexObject(entry); + break; } return result; diff --git a/src/object/ObjectFactory.h b/src/object/ObjectFactory.h index 4d89b7ca6e..1f1ac4647e 100644 --- a/src/object/ObjectFactory.h +++ b/src/object/ObjectFactory.h @@ -22,6 +22,6 @@ class Object; namespace ObjectFactory { - Object * CreateObjectFromLegacyFile(utf8 * path); + Object * CreateObjectFromLegacyFile(const utf8 * path); Object * CreateObject(const rct_object_entry &entry); } diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 203a1ffe79..1eaf17c1d6 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -17,6 +17,7 @@ #include #include "../common.h" +#include "../core/Console.hpp" #include "../core/FileStream.hpp" #include "../core/Guard.hpp" #include "../core/IStream.hpp" @@ -26,11 +27,14 @@ #include "Object.h" #include "ObjectFactory.h" #include "ObjectRepository.h" +#include "StexObject.h" extern "C" { + #include "../localisation/localisation.h" #include "../object.h" #include "../platform/platform.h" + #include "../scenario.h" } constexpr uint16 OBJECT_REPOSITORY_VERSION = 6; @@ -87,6 +91,17 @@ public: return nullptr; } + Object * LoadObject(const rct_object_entry * objectEntry) override + { + Object * object = nullptr; + const ObjectRepositoryItem * item = FindObject(objectEntry); + if (item != nullptr) + { + object = ObjectFactory::CreateObjectFromLegacyFile(item->Path); + } + return object; + } + private: void ClearItems() { @@ -329,4 +344,77 @@ extern "C" { IObjectRepository * objRepo = GetObjectRepository(); } + + int object_load_chunk(int groupIndex, rct_object_entry * entry, int * chunkSize) + { + IObjectRepository * objRepo = GetObjectRepository(); + Object * object = objRepo->LoadObject(entry); + if (object == nullptr) + { + utf8 objName[9] = { 0 }; + Memory::Copy(objName, entry->name, 8); + Console::Error::WriteFormat("[%s]: Object not found or could not be loaded.", objName); + Console::Error::WriteLine(); + return 0; + } + + uint8 objectType = object->GetObjectType(); + void * * chunkList = object_entry_groups[objectType].chunks; + if (groupIndex == -1) + { + for (groupIndex = 0; chunkList[groupIndex] != (void*)-1; groupIndex++) + { + if (groupIndex + 1 >= object_entry_group_counts[objectType]) + { + log_error("Object Load failed due to too many objects of a certain type."); + delete object; + return 0; + } + } + } + chunkList[groupIndex] = object->GetLegacyData(); + + rct_object_entry_extended * extendedEntry = &object_entry_groups[objectType].entries[groupIndex]; + Memory::Copy(extendedEntry, object->GetObjectEntry(), sizeof(rct_object_entry)); + extendedEntry->chunk_size = 0; + + object->Load(); + return 1; + } + + void scenario_translate(scenario_index_entry * scenarioEntry, const rct_object_entry * stexObjectEntry) + { + rct_string_id localisedStringIds[3]; + if (language_get_localised_scenario_strings(scenarioEntry->name, localisedStringIds)) + { + if (localisedStringIds[0] != STR_NONE) + { + String::Set(scenarioEntry->name, sizeof(scenarioEntry->name), language_get_string(localisedStringIds[0])); + } + if (localisedStringIds[2] != STR_NONE) + { + String::Set(scenarioEntry->details, sizeof(scenarioEntry->details), language_get_string(localisedStringIds[2])); + } + } + else + { + // Checks for a scenario string object (possibly for localisation) + if ((stexObjectEntry->flags & 0xFF) != 255) + { + IObjectRepository * objRepo = GetObjectRepository(); + Object * object = objRepo->LoadObject(stexObjectEntry); + if (object != nullptr) + { + StexObject * stexObject = static_cast(object); + const utf8 * scenarioName = stexObject->GetScenarioName(); + const utf8 * scenarioDetails = stexObject->GetScenarioDetails(); + + String::Set(scenarioEntry->name, sizeof(scenarioEntry->name), scenarioName); + String::Set(scenarioEntry->details, sizeof(scenarioEntry->details), scenarioDetails); + + delete object; + } + } + } + } } diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index c686a49de7..f64b6e6b86 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -52,7 +52,8 @@ interface IObjectRepository { virtual ~IObjectRepository() { } - virtual const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) abstract; + virtual const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) abstract; + virtual Object * LoadObject(const rct_object_entry * objectEntry) abstract; }; IObjectRepository * GetObjectRepository(); diff --git a/src/object/StexObject.cpp b/src/object/StexObject.cpp new file mode 100644 index 0000000000..3a8434f732 --- /dev/null +++ b/src/object/StexObject.cpp @@ -0,0 +1,77 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/IStream.hpp" +#include "StexObject.h" + +extern "C" +{ + #include "../localisation/localisation.h" +} + +enum OBJ_STRING_ID +{ + OBJ_STRING_ID_SCENARIO_NAME, + OBJ_STRING_ID_PARK_NAME, + OBJ_STRING_ID_SCENARIO_DETAILS, +}; + +void StexObject::ReadLegacy(IStream * stream) +{ + _legacyType.scenario_name = stream->ReadValue(); + _legacyType.park_name = stream->ReadValue(); + _legacyType.details = stream->ReadValue(); + _legacyType.var_06 = stream->ReadValue(); + stream->Seek(1, STREAM_SEEK_CURRENT); + + StringTable.Read(stream, OBJ_STRING_ID_SCENARIO_NAME); + StringTable.Read(stream, OBJ_STRING_ID_PARK_NAME); + StringTable.Read(stream, OBJ_STRING_ID_SCENARIO_DETAILS); +} + +void StexObject::Load() +{ + _legacyType.scenario_name = language_allocate_object_string(GetScenarioName()); + _legacyType.park_name = language_allocate_object_string(GetParkName()); + _legacyType.details = language_allocate_object_string(GetScenarioDetails()); +} + +void StexObject::Unload() +{ + language_free_object_string(_legacyType.scenario_name); + language_free_object_string(_legacyType.park_name); + language_free_object_string(_legacyType.details); +} + +const utf8 * StexObject::GetName() +{ + return GetScenarioName(); +} + +const utf8 * StexObject::GetScenarioName() +{ + return StringTable.GetString(OBJ_STRING_ID_SCENARIO_NAME); +} + +const utf8 * StexObject::GetScenarioDetails() +{ + return StringTable.GetString(OBJ_STRING_ID_SCENARIO_DETAILS); +} + +const utf8 * StexObject::GetParkName() +{ + return StringTable.GetString(OBJ_STRING_ID_PARK_NAME); +} diff --git a/src/object/StexObject.h b/src/object/StexObject.h new file mode 100644 index 0000000000..3204cc40db --- /dev/null +++ b/src/object/StexObject.h @@ -0,0 +1,45 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "Object.h" + +extern "C" +{ + #include "../scenario.h" +} + +class StexObject : public Object +{ +private: + rct_stex_entry _legacyType; + +public: + explicit StexObject(const rct_object_entry &entry) : Object(entry) { }; + + void * GetLegacyData() override { return &_legacyType; } + + void ReadLegacy(IStream * stream) override; + void Load() override; + void Unload() override; + + const utf8 * GetName() override; + + const utf8 * GetScenarioName(); + const utf8 * GetScenarioDetails(); + const utf8 * GetParkName(); +}; diff --git a/src/scenario.h b/src/scenario.h index dd35641e2a..b78057b8e8 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -490,6 +490,8 @@ bool scenario_get_source_desc(const utf8 *name, source_desc *outDesc); bool scenario_get_source_desc_by_id(uint8 id, source_desc *outDesc); void scenario_normalise_name(utf8 *name); +void scenario_translate(scenario_index_entry *scenarioEntry, const rct_object_entry *stexObjectEntry); + // RCT1 scenario index map enum { SC_UNIDENTIFIED = 255, diff --git a/src/scenario_list.c b/src/scenario_list.c index c92a9a520e..29819410d6 100644 --- a/src/scenario_list.c +++ b/src/scenario_list.c @@ -36,7 +36,6 @@ static void scenario_list_add(const utf8 *path, uint64 timestamp); static void scenario_list_sort(); static int scenario_list_sort_by_category(const void *a, const void *b); static int scenario_list_sort_by_index(const void *a, const void *b); -static void scenario_translate(scenario_index_entry *scenarioEntry, const rct_object_entry *stexObjectEntry); static bool scenario_scores_load(); static void scenario_scores_legacy_get_path(utf8 *outPath); @@ -183,29 +182,6 @@ static void scenario_list_add(const utf8 *path, uint64 timestamp) scenario_translate(newEntry, &s6Info.entry); } -static void scenario_translate(scenario_index_entry *scenarioEntry, const rct_object_entry *stexObjectEntry) -{ - rct_string_id localisedStringIds[3]; - if (language_get_localised_scenario_strings(scenarioEntry->name, localisedStringIds)) { - if (localisedStringIds[0] != STR_NONE) { - safe_strcpy(scenarioEntry->name, language_get_string(localisedStringIds[0]), 64); - } - if (localisedStringIds[2] != STR_NONE) { - safe_strcpy(scenarioEntry->details, language_get_string(localisedStringIds[2]), 256); - } - } else { - // Checks for a scenario string object (possibly for localisation) - if ((stexObjectEntry->flags & 0xFF) != 255) { - if (object_get_scenario_text((rct_object_entry*)stexObjectEntry)) { - rct_stex_entry* stex_entry = gStexTempChunk; - format_string(scenarioEntry->name, stex_entry->scenario_name, NULL); - format_string(scenarioEntry->details, stex_entry->details, NULL); - object_free_scenario_text(); - } - } - } -} - void scenario_list_dispose() { gScenarioListCapacity = 0; From 90923fbb43bb7b3c8475bf560c461fbffd066edd Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 17:09:56 +0100 Subject: [PATCH 010/116] add footpath objects --- openrct2.vcxproj | 2 ++ src/object/FootpathObject.cpp | 61 +++++++++++++++++++++++++++++++++++ src/object/FootpathObject.h | 41 +++++++++++++++++++++++ src/object/ObjectFactory.cpp | 4 +++ 4 files changed, 108 insertions(+) create mode 100644 src/object/FootpathObject.cpp create mode 100644 src/object/FootpathObject.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 78e43f5706..064ab53ca0 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -119,6 +119,7 @@ + @@ -426,6 +427,7 @@ + diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp new file mode 100644 index 0000000000..522da5d649 --- /dev/null +++ b/src/object/FootpathObject.cpp @@ -0,0 +1,61 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/IStream.hpp" +#include "FootpathObject.h" + +extern "C" +{ + #include "../drawing/drawing.h" + #include "../localisation/localisation.h" + #include "../world/footpath.h" +} + +enum OBJ_STRING_ID +{ + OBJ_STRING_ID_NAME, +}; + +void FootpathObject::ReadLegacy(IStream * stream) +{ + _legacyType.string_idx = stream->ReadValue(); + _legacyType.image = stream->ReadValue(); + _legacyType.bridge_image = stream->ReadValue(); + _legacyType.var_0A = stream->ReadValue(); + _legacyType.flags = stream->ReadValue(); + _legacyType.scrolling_mode = stream->ReadValue(); + stream->Seek(1, STREAM_SEEK_BEGIN); + + StringTable.Read(stream, OBJ_STRING_ID_NAME); + ImageTable.Read(stream); +} + +void FootpathObject::Load() +{ + _legacyType.string_idx = language_allocate_object_string(GetName()); + _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.bridge_image = _legacyType.image + 109; +} + +void FootpathObject::Unload() +{ + language_free_object_string(_legacyType.string_idx); +} + +const utf8 * FootpathObject::GetName() +{ + return StringTable.GetString(OBJ_STRING_ID_NAME); +} diff --git a/src/object/FootpathObject.h b/src/object/FootpathObject.h new file mode 100644 index 0000000000..096758e66d --- /dev/null +++ b/src/object/FootpathObject.h @@ -0,0 +1,41 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "Object.h" + +extern "C" +{ + #include "../world/footpath.h" +} + +class FootpathObject : public Object +{ +private: + rct_footpath_entry _legacyType; + +public: + explicit FootpathObject(const rct_object_entry &entry) : Object(entry) { }; + + void * GetLegacyData() override { return &_legacyType; } + + void ReadLegacy(IStream * stream) override; + void Load() override; + void Unload() override; + + const utf8 * GetName() override; +}; diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 7cd94070fa..4f047cb3d5 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -18,6 +18,7 @@ #include "../core/Memory.hpp" #include "../core/MemoryStream.h" #include "EntranceObject.h" +#include "FootpathObject.h" #include "Object.h" #include "ObjectFactory.h" #include "StexObject.h" @@ -62,6 +63,9 @@ namespace ObjectFactory uint8 objectType = entry.flags & 0x0F; switch (objectType) { + case OBJECT_TYPE_PATHS: + result = new FootpathObject(entry); + break; case OBJECT_TYPE_PARK_ENTRANCE: result = new EntranceObject(entry); break; From 7e206d1a853c9db2e31605a080631470d21c9aca Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 18:05:24 +0100 Subject: [PATCH 011/116] add path item object --- openrct2.vcxproj | 2 + src/object/EntranceObject.cpp | 1 + src/object/FootpathItemObject.cpp | 74 +++++++++++++++++++++++++++++++ src/object/FootpathItemObject.h | 42 ++++++++++++++++++ src/object/FootpathObject.cpp | 1 + src/object/ObjectFactory.cpp | 4 ++ 6 files changed, 124 insertions(+) create mode 100644 src/object/FootpathItemObject.cpp create mode 100644 src/object/FootpathItemObject.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 064ab53ca0..8690833636 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -119,6 +119,7 @@ + @@ -427,6 +428,7 @@ + diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index edd1db42b5..fc9ee35a40 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -48,6 +48,7 @@ void EntranceObject::Load() void EntranceObject::Unload() { language_free_object_string(_legacyType.string_idx); + gfx_object_free_images(_legacyType.image_id, ImageTable.GetCount()); } const utf8 * EntranceObject::GetName() diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp new file mode 100644 index 0000000000..6538292425 --- /dev/null +++ b/src/object/FootpathItemObject.cpp @@ -0,0 +1,74 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/IStream.hpp" +#include "FootpathItemObject.h" + +extern "C" +{ + #include "../drawing/drawing.h" + #include "../localisation/localisation.h" +} + +enum OBJ_STRING_ID +{ + OBJ_STRING_ID_NAME, +}; + +void FootpathItemObject::ReadLegacy(IStream * stream) +{ + _legacyType.name = stream->ReadValue(); + _legacyType.image = stream->ReadValue(); + _legacyType.path_bit.flags = stream->ReadValue(); + _legacyType.path_bit.draw_type = stream->ReadValue(); + _legacyType.path_bit.tool_id = stream->ReadValue(); + _legacyType.path_bit.price = stream->ReadValue(); + _legacyType.path_bit.scenery_tab_id = stream->ReadValue(); + stream->Seek(0, STREAM_SEEK_BEGIN); + + StringTable.Read(stream, OBJ_STRING_ID_NAME); + + _sceneryTabEntry = stream->ReadValue(); + + ImageTable.Read(stream); +} + +void FootpathItemObject::Load() +{ + _legacyType.name = language_allocate_object_string(GetName()); + _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + + _legacyType.path_bit.scenery_tab_id = 0xFF; + if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) + { + uint8 entryType, entryIndex; + if (find_object_in_entry_group(&_sceneryTabEntry, &entryType, &entryIndex)) + { + _legacyType.path_bit.scenery_tab_id = entryIndex; + } + } +} + +void FootpathItemObject::Unload() +{ + language_free_object_string(_legacyType.name); + gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); +} + +const utf8 * FootpathItemObject::GetName() +{ + return StringTable.GetString(OBJ_STRING_ID_NAME); +} diff --git a/src/object/FootpathItemObject.h b/src/object/FootpathItemObject.h new file mode 100644 index 0000000000..83ed82bd55 --- /dev/null +++ b/src/object/FootpathItemObject.h @@ -0,0 +1,42 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "Object.h" + +extern "C" +{ + #include "../world/scenery.h" +} + +class FootpathItemObject : public Object +{ +private: + rct_scenery_entry _legacyType; + rct_object_entry _sceneryTabEntry; + +public: + explicit FootpathItemObject(const rct_object_entry &entry) : Object(entry) { }; + + void * GetLegacyData() override { return &_legacyType; } + + void ReadLegacy(IStream * stream) override; + void Load() override; + void Unload() override; + + const utf8 * GetName() override; +}; diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp index 522da5d649..55b9e726b5 100644 --- a/src/object/FootpathObject.cpp +++ b/src/object/FootpathObject.cpp @@ -53,6 +53,7 @@ void FootpathObject::Load() void FootpathObject::Unload() { language_free_object_string(_legacyType.string_idx); + gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); } const utf8 * FootpathObject::GetName() diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 4f047cb3d5..e91fa07d5b 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -18,6 +18,7 @@ #include "../core/Memory.hpp" #include "../core/MemoryStream.h" #include "EntranceObject.h" +#include "FootpathItemObject.h" #include "FootpathObject.h" #include "Object.h" #include "ObjectFactory.h" @@ -66,6 +67,9 @@ namespace ObjectFactory case OBJECT_TYPE_PATHS: result = new FootpathObject(entry); break; + case OBJECT_TYPE_PATH_BITS: + result = new FootpathItemObject(entry); + break; case OBJECT_TYPE_PARK_ENTRANCE: result = new EntranceObject(entry); break; From daa5a0c506bc654a56e68b6628f877b1df6dfe82 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 18:58:04 +0100 Subject: [PATCH 012/116] add small scenery object --- openrct2.vcxproj | 2 + src/object/FootpathItemObject.cpp | 1 - src/object/ObjectFactory.cpp | 4 ++ src/object/SmallSceneryObject.cpp | 103 ++++++++++++++++++++++++++++++ src/object/SmallSceneryObject.h | 47 ++++++++++++++ 5 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 src/object/SmallSceneryObject.cpp create mode 100644 src/object/SmallSceneryObject.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 8690833636..59adc5e95e 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -125,6 +125,7 @@ + @@ -434,6 +435,7 @@ + diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp index 6538292425..c765f4f3a7 100644 --- a/src/object/FootpathItemObject.cpp +++ b/src/object/FootpathItemObject.cpp @@ -37,7 +37,6 @@ void FootpathItemObject::ReadLegacy(IStream * stream) _legacyType.path_bit.tool_id = stream->ReadValue(); _legacyType.path_bit.price = stream->ReadValue(); _legacyType.path_bit.scenery_tab_id = stream->ReadValue(); - stream->Seek(0, STREAM_SEEK_BEGIN); StringTable.Read(stream, OBJ_STRING_ID_NAME); diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index e91fa07d5b..b89463287b 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -22,6 +22,7 @@ #include "FootpathObject.h" #include "Object.h" #include "ObjectFactory.h" +#include "SmallSceneryObject.h" #include "StexObject.h" extern "C" @@ -64,6 +65,9 @@ namespace ObjectFactory uint8 objectType = entry.flags & 0x0F; switch (objectType) { + case OBJECT_TYPE_SMALL_SCENERY: + result = new SmallSceneryObject(entry); + break; case OBJECT_TYPE_PATHS: result = new FootpathObject(entry); break; diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp new file mode 100644 index 0000000000..055b28fa4b --- /dev/null +++ b/src/object/SmallSceneryObject.cpp @@ -0,0 +1,103 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/IStream.hpp" +#include "../core/Memory.hpp" +#include "SmallSceneryObject.h" + +extern "C" +{ + #include "../drawing/drawing.h" + #include "../localisation/localisation.h" +} + +enum OBJ_STRING_ID +{ + OBJ_STRING_ID_NAME, +}; + +SmallSceneryObject::~SmallSceneryObject() +{ + Memory::Free(_var10data); +} + +void SmallSceneryObject::ReadLegacy(IStream * stream) +{ + _legacyType.name = stream->ReadValue(); + _legacyType.image = stream->ReadValue(); + + _legacyType.small_scenery.flags = stream->ReadValue(); + _legacyType.small_scenery.height = stream->ReadValue(); + _legacyType.small_scenery.tool_id = stream->ReadValue(); + _legacyType.small_scenery.price = stream->ReadValue(); + _legacyType.small_scenery.removal_price = stream->ReadValue(); + _legacyType.small_scenery.var_10 = stream->ReadValue(); + _legacyType.small_scenery.var_14 = stream->ReadValue(); + _legacyType.small_scenery.var_16 = stream->ReadValue(); + _legacyType.small_scenery.var_18 = stream->ReadValue(); + _legacyType.small_scenery.scenery_tab_id = 0xFF; + + StringTable.Read(stream, OBJ_STRING_ID_NAME); + + _sceneryTabEntry = stream->ReadValue(); + + if (_legacyType.small_scenery.flags & SMALL_SCENERY_FLAG16) + { + _var10data = ReadVar10(stream); + } + + ImageTable.Read(stream); +} + +void SmallSceneryObject::Load() +{ + _legacyType.name = language_allocate_object_string(GetName()); + _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + + _legacyType.small_scenery.scenery_tab_id = 0xFF; + if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) + { + uint8 entryType, entryIndex; + if (find_object_in_entry_group(&_sceneryTabEntry, &entryType, &entryIndex)) + { + _legacyType.small_scenery.scenery_tab_id = entryIndex; + } + } +} + +void SmallSceneryObject::Unload() +{ + language_free_object_string(_legacyType.name); + gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); +} + +const utf8 * SmallSceneryObject::GetName() +{ + return StringTable.GetString(OBJ_STRING_ID_NAME); +} + +uint8 * SmallSceneryObject::ReadVar10(IStream * stream) +{ + uint8 b; + auto data = std::vector(); + data.push_back(stream->ReadValue()); + while ((b = stream->ReadValue()) != 0xFF) + { + data.push_back(b); + } + data.push_back(b); + return Memory::Duplicate(data.data(), data.size()); +} diff --git a/src/object/SmallSceneryObject.h b/src/object/SmallSceneryObject.h new file mode 100644 index 0000000000..5f0aa5e73f --- /dev/null +++ b/src/object/SmallSceneryObject.h @@ -0,0 +1,47 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "Object.h" + +extern "C" +{ + #include "../world/scenery.h" +} + +class SmallSceneryObject : public Object +{ +private: + rct_scenery_entry _legacyType; + rct_object_entry _sceneryTabEntry; + uint8 * _var10data = nullptr; + +public: + explicit SmallSceneryObject(const rct_object_entry &entry) : Object(entry) { }; + ~SmallSceneryObject(); + + void * GetLegacyData() override { return &_legacyType; } + + void ReadLegacy(IStream * stream) override; + void Load() override; + void Unload() override; + + const utf8 * GetName() override; + +private: + static uint8 * ReadVar10(IStream * stream); +}; From 2c02412f989e7833c57a0197603fee02bace434b Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 22:07:01 +0100 Subject: [PATCH 013/116] add ride object loading --- openrct2.vcxproj | 2 + src/core/IStream.hpp | 15 ++ src/object/ObjectFactory.cpp | 4 + src/object/RideObject.cpp | 348 +++++++++++++++++++++++++++++++++++ src/object/RideObject.h | 49 +++++ 5 files changed, 418 insertions(+) create mode 100644 src/object/RideObject.cpp create mode 100644 src/object/RideObject.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 59adc5e95e..0bce3c36a8 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -125,6 +125,7 @@ + @@ -435,6 +436,7 @@ + diff --git a/src/core/IStream.hpp b/src/core/IStream.hpp index 577f1d29e8..697cadfe75 100644 --- a/src/core/IStream.hpp +++ b/src/core/IStream.hpp @@ -18,6 +18,7 @@ #include "../common.h" #include "Exception.hpp" +#include "Memory.hpp" enum { STREAM_SEEK_BEGIN, @@ -88,6 +89,20 @@ interface IStream Write(&value); } + template + T * ReadArray(size_t count) + { + T * buffer = Memory::AllocateArray(count); + Read(buffer, sizeof(T) * count); + return buffer; + } + + template + void WriteArray(T * buffer, size_t count) + { + Write(buffer, sizeof(T) * count); + } + utf8 * ReadString(); void WriteString(utf8 * str); }; diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index b89463287b..9d3a1ccc34 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -22,6 +22,7 @@ #include "FootpathObject.h" #include "Object.h" #include "ObjectFactory.h" +#include "RideObject.h" #include "SmallSceneryObject.h" #include "StexObject.h" @@ -65,6 +66,9 @@ namespace ObjectFactory uint8 objectType = entry.flags & 0x0F; switch (objectType) { + case OBJECT_TYPE_RIDE: + result = new RideObject(entry); + break; case OBJECT_TYPE_SMALL_SCENERY: result = new SmallSceneryObject(entry); break; diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp new file mode 100644 index 0000000000..7be47fdc53 --- /dev/null +++ b/src/object/RideObject.cpp @@ -0,0 +1,348 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/IStream.hpp" +#include "../core/Memory.hpp" +#include "../core/Util.hpp" +#include "RideObject.h" + +extern "C" +{ + #include "../config.h" + #include "../drawing/drawing.h" + #include "../localisation/localisation.h" + #include "../rct1.h" +} + +enum OBJ_STRING_ID +{ + OBJ_STRING_ID_NAME, + OBJ_STRING_ID_DESCRIPTION, + OBJ_STRING_ID_CAPACITY, +}; + +RideObject::~RideObject() +{ + Memory::FreeArray(_peepLoadingPositions, 4); +} + +void RideObject::ReadLegacy(IStream * stream) +{ + stream->Read(&_legacyType); + + StringTable.Read(stream, OBJ_STRING_ID_NAME); + StringTable.Read(stream, OBJ_STRING_ID_DESCRIPTION); + + // TODO: Move to its own function when ride construction window is merged. + if (gConfigInterface.select_by_track_type) { + _legacyType.enabledTrackPieces = 0xFFFFFFFFFFFFFFFF; + } + + StringTable.Read(stream, OBJ_STRING_ID_CAPACITY); + + // Read preset colours, by default there are 32 + _presetColours.count = stream->ReadValue(); + if (_presetColours.count == 255) + { + _presetColours.count = 32; + } + for (uint8 i = 0; i < _presetColours.count; i++) + { + _presetColours.list[i] = stream->ReadValue(); + } + + // Read peep loading positions + for (int i = 0; i < 4; i++) + { + uint16 numPeepLoadingPositions = stream->ReadValue(); + if (numPeepLoadingPositions == 255) + { + numPeepLoadingPositions = stream->ReadValue(); + } + _peepLoadingPositions[i] = stream->ReadArray(numPeepLoadingPositions); + } + + ImageTable.Read(stream); +} + +void RideObject::Load() +{ + _legacyType.name = language_allocate_object_string(GetName()); + _legacyType.description = language_allocate_object_string(GetDescription()); + _legacyType.images_offset = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + + int cur_vehicle_images_offset = _legacyType.images_offset + 3; + for (int i = 0; i < 4; i++) + { + rct_ride_entry_vehicle * vehicleEntry = &_legacyType.vehicles[i]; + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT) + { + int al = 1; + if (vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_SWINGING) + { + al = 13; + if ((vehicleEntry->flags_b & (VEHICLE_ENTRY_FLAG_B_5 | VEHICLE_ENTRY_FLAG_B_11)) != (VEHICLE_ENTRY_FLAG_B_5 | VEHICLE_ENTRY_FLAG_B_11)) + { + al = 7; + if (!(vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_5)) + { + if (!(vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_11)) + { + al = 5; + if (vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_9) + { + al = 3; + } + } + } + } + } + vehicleEntry->var_03 = al; + // 0x6DE90B + al = 0x20; + if (!(vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_14)) + { + al = 1; + if (vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_7) + { + if (vehicleEntry->var_11 != 6) + { + al = 2; + if (!(vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_7)) + { + al = 4; + } + } + } + } + if (vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_12) + { + al = vehicleEntry->special_frames; + } + vehicleEntry->var_02 = al; + // 0x6DE946 + + vehicleEntry->var_16 = vehicleEntry->var_02 * vehicleEntry->var_03; + vehicleEntry->base_image_id = cur_vehicle_images_offset; + int image_index = vehicleEntry->base_image_id; + + if (vehicleEntry->car_visual != VEHICLE_VISUAL_RIVER_RAPIDS) + { + int b = vehicleEntry->var_16 * 32; + + if (vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_11) b /= 2; + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_15) b /= 8; + + image_index += b; + + // Incline 25 + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_GENTLE_SLOPES) + { + vehicleEntry->var_20 = image_index; + b = vehicleEntry->var_16 * 72; + if (vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_14) + { + b = vehicleEntry->var_16 * 16; + } + image_index += b; + } + + // Incline 60 + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_STEEP_SLOPES) + { + vehicleEntry->var_24 = image_index; + b = vehicleEntry->var_16 * 80; + image_index += b; + } + + // Verticle + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_VERTICAL_SLOPES) + { + vehicleEntry->var_28 = image_index; + b = vehicleEntry->var_16 * 116; + image_index += b; + } + + // Unknown + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_DIAGONAL_SLOPES) + { + vehicleEntry->var_2C = image_index; + b = vehicleEntry->var_16 * 24; + image_index += b; + } + + // Bank + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT_BANKED) + { + vehicleEntry->var_30 = image_index; + b = vehicleEntry->var_16 * 80; + image_index += b; + } + + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_INLINE_TWISTS) + { + vehicleEntry->var_34 = image_index; + b = vehicleEntry->var_16 * 40; + image_index += b; + } + + // Track half? Up/Down + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_BANKED_TRANSITIONS) + { + vehicleEntry->var_38 = image_index; + b = vehicleEntry->var_16 * 128; + image_index += b; + } + + // Unknown + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_DIAGONAL_GENTLE_SLOPE_BANKED_TRANSITIONS) + { + vehicleEntry->var_3C = image_index; + b = vehicleEntry->var_16 * 16; + image_index += b; + } + + // Unknown + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TRANSITIONS) + { + vehicleEntry->var_40 = image_index; + b = vehicleEntry->var_16 * 16; + image_index += b; + } + + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TURNS) + { + vehicleEntry->var_44 = image_index; + b = vehicleEntry->var_16 * 128; + image_index += b; + } + + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_WHILE_BANKED_TRANSITIONS) + { + vehicleEntry->var_48 = image_index; + b = vehicleEntry->var_16 * 16; + image_index += b; + } + + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_CORKSCREWS) + { + vehicleEntry->var_4C = image_index; + b = vehicleEntry->var_16 * 80; + image_index += b; + } + + // Unknown + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_RESTRAINT_ANIMATION) + { + vehicleEntry->var_1C = image_index; + b = vehicleEntry->var_16 * 12; + image_index += b; + } + + if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_14) + { + // Same offset as above??? + vehicleEntry->var_4C = image_index; + b = vehicleEntry->var_16 * 32; + image_index += b; + } + } + else + { + image_index += vehicleEntry->var_16 * 36; + } + + // No vehicle images + vehicleEntry->no_vehicle_images = image_index - cur_vehicle_images_offset; + + // Move the offset over this vehicles images. Including peeps + cur_vehicle_images_offset = image_index + vehicleEntry->no_seating_rows * vehicleEntry->no_vehicle_images; + // 0x6DEB0D + + if (!(vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_10)) + { + int num_images = cur_vehicle_images_offset - vehicleEntry->base_image_id; + if (vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_13) + { + num_images *= 2; + } + + set_vehicle_type_image_max_sizes(vehicleEntry, num_images); + } + vehicleEntry->peep_loading_positions = _peepLoadingPositions[i]; + } + } + + // 0x6DEB71 + if (RCT2_GLOBAL(0x9ADAFD, uint8) == 0) + { + for (int i = 0; i < 3; i++) + { + sint16 rideType = _legacyType.ride_type[i]; + if (rideType != RIDE_TYPE_NULL) + { + uint8 * typeToRideEntryIndexMap = gTypeToRideEntryIndexMap; + while (rideType >= 0) + { + if (*typeToRideEntryIndexMap++ == 0xFF) + { + rideType--; + } + } + + typeToRideEntryIndexMap--; + uint8 previous_entry = 0; // TODO set this to entryIndex + while (typeToRideEntryIndexMap < gTypeToRideEntryIndexMap + Util::CountOf(gTypeToRideEntryIndexMap)) + { + uint8 backup_entry = *typeToRideEntryIndexMap; + *typeToRideEntryIndexMap++ = previous_entry; + previous_entry = backup_entry; + } + } + } + } + + // TODO sort out this filter stuff + int di = _legacyType.ride_type[0] | (_legacyType.ride_type[1] << 8) | (_legacyType.ride_type[2] << 16); + if ((_legacyType.flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) && + !rideTypeShouldLoseSeparateFlag(&_legacyType)) + { + di |= 0x1000000; + } + RCT2_GLOBAL(0xF433DD, uint32) = di; +} + +void RideObject::Unload() +{ + language_free_object_string(_legacyType.name); + language_free_object_string(_legacyType.description); + gfx_object_free_images(_legacyType.images_offset, ImageTable.GetCount()); +} + +const utf8 * RideObject::GetName() +{ + return StringTable.GetString(OBJ_STRING_ID_NAME); +} + +const utf8 * RideObject::GetDescription() +{ + return StringTable.GetString(OBJ_STRING_ID_DESCRIPTION); +} + +const utf8 * RideObject::GetCapacity() +{ + return StringTable.GetString(OBJ_STRING_ID_CAPACITY); +} diff --git a/src/object/RideObject.h b/src/object/RideObject.h new file mode 100644 index 0000000000..8e286e9a8a --- /dev/null +++ b/src/object/RideObject.h @@ -0,0 +1,49 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "Object.h" + +extern "C" +{ + #include "../ride/ride.h" +} + +class RideObject : public Object +{ +private: + rct_ride_entry _legacyType; + vehicle_colour_preset_list _presetColours = { 0 }; + sint8 * _peepLoadingPositions[4] = { nullptr }; + +public: + explicit RideObject(const rct_object_entry &entry) : Object(entry) { }; + ~RideObject(); + + void * GetLegacyData() override { return &_legacyType; } + + void ReadLegacy(IStream * stream) override; + void Load() override; + void Unload() override; + + const utf8 * GetName() override; + const utf8 * GetDescription(); + const utf8 * GetCapacity(); + +private: + +}; From 958dfa662381feaa0e3849542f6fba5f48348038 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 22:47:09 +0100 Subject: [PATCH 014/116] add large scenery object loading --- openrct2.vcxproj | 2 + src/object/LargeSceneryObject.cpp | 121 ++++++++++++++++++++++++++++++ src/object/LargeSceneryObject.h | 48 ++++++++++++ src/object/ObjectFactory.cpp | 4 + 4 files changed, 175 insertions(+) create mode 100644 src/object/LargeSceneryObject.cpp create mode 100644 src/object/LargeSceneryObject.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 0bce3c36a8..2bbbb5b06a 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -122,6 +122,7 @@ + @@ -433,6 +434,7 @@ + diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp new file mode 100644 index 0000000000..4eb3ccf754 --- /dev/null +++ b/src/object/LargeSceneryObject.cpp @@ -0,0 +1,121 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/IStream.hpp" +#include "../core/Memory.hpp" +#include "LargeSceneryObject.h" + +extern "C" +{ + #include "../drawing/drawing.h" + #include "../localisation/localisation.h" +} + +enum OBJ_STRING_ID +{ + OBJ_STRING_ID_NAME, +}; + +LargeSceneryObject::~LargeSceneryObject() +{ + Memory::Free(_3dFont); + Memory::Free(_tiles); +} + +void LargeSceneryObject::ReadLegacy(IStream * stream) +{ + _legacyType.name = stream->ReadValue(); + _legacyType.image = stream->ReadValue(); + + _legacyType.large_scenery.tool_id = stream->ReadValue(); + _legacyType.large_scenery.flags = stream->ReadValue(); + _legacyType.large_scenery.price = stream->ReadValue(); + _legacyType.large_scenery.removal_price = stream->ReadValue(); + stream->Seek(4, STREAM_SEEK_CURRENT); + _legacyType.large_scenery.scenery_tab_id = 0xFF; + _legacyType.large_scenery.var_11 = stream->ReadValue(); + stream->Seek(5, STREAM_SEEK_CURRENT); + + StringTable.Read(stream, OBJ_STRING_ID_NAME); + + _sceneryTabEntry = stream->ReadValue(); + + if (_legacyType.large_scenery.flags & (1 << 2)) + { + _3dFont = Memory::Allocate(); + stream->Read(_3dFont); + _legacyType.large_scenery.text = _3dFont; + } + + _tiles = ReadTiles(stream); + + ImageTable.Read(stream); +} + +void LargeSceneryObject::Load() +{ + _legacyType.name = language_allocate_object_string(GetName()); + _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + + _legacyType.large_scenery.scenery_tab_id = 0xFF; + if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) + { + uint8 entryType, entryIndex; + if (find_object_in_entry_group(&_sceneryTabEntry, &entryType, &entryIndex)) + { + _legacyType.large_scenery.scenery_tab_id = entryIndex; + } + } + + if (_legacyType.large_scenery.flags & (1 << 2)) + { + _legacyType.large_scenery.text_image = _legacyType.image; + if (_3dFont->var_C & (1 << 0)) + { + _legacyType.image += (_3dFont->var_C >> 8) * 2; + } + else + { + _legacyType.image += (_3dFont->var_C >> 8) * 4; + } + } +} + +void LargeSceneryObject::Unload() +{ + language_free_object_string(_legacyType.name); + gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); +} + +const utf8 * LargeSceneryObject::GetName() +{ + return StringTable.GetString(OBJ_STRING_ID_NAME); +} + +rct_large_scenery_tile * LargeSceneryObject::ReadTiles(IStream * stream) +{ + auto tiles = std::vector(); + + uint16 tilesEndMarker; + while ((tilesEndMarker = stream->ReadValue()) != 0xFFFF) + { + stream->Seek(-2, STREAM_SEEK_CURRENT); + auto tile = stream->ReadValue(); + tiles.push_back(tile); + } + + return Memory::DuplicateArray(tiles.data(), tiles.size()); +} diff --git a/src/object/LargeSceneryObject.h b/src/object/LargeSceneryObject.h new file mode 100644 index 0000000000..3222844175 --- /dev/null +++ b/src/object/LargeSceneryObject.h @@ -0,0 +1,48 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "Object.h" + +extern "C" +{ + #include "../world/scenery.h" +} + +class LargeSceneryObject : public Object +{ +private: + rct_scenery_entry _legacyType; + rct_object_entry _sceneryTabEntry; + rct_large_scenery_text * _3dFont; + rct_large_scenery_tile * _tiles; + +public: + explicit LargeSceneryObject(const rct_object_entry &entry) : Object(entry) { }; + ~LargeSceneryObject(); + + void * GetLegacyData() override { return &_legacyType; } + + void ReadLegacy(IStream * stream) override; + void Load() override; + void Unload() override; + + const utf8 * GetName() override; + +private: + static rct_large_scenery_tile * ReadTiles(IStream * stream); +}; diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 9d3a1ccc34..f5ed13dcc1 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -20,6 +20,7 @@ #include "EntranceObject.h" #include "FootpathItemObject.h" #include "FootpathObject.h" +#include "LargeSceneryObject.h" #include "Object.h" #include "ObjectFactory.h" #include "RideObject.h" @@ -72,6 +73,9 @@ namespace ObjectFactory case OBJECT_TYPE_SMALL_SCENERY: result = new SmallSceneryObject(entry); break; + case OBJECT_TYPE_LARGE_SCENERY: + result = new LargeSceneryObject(entry); + break; case OBJECT_TYPE_PATHS: result = new FootpathObject(entry); break; From 54f50c1f205f600dfca6e4dacfd43b74b79bd930 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 22:59:24 +0100 Subject: [PATCH 015/116] add wall object loading --- openrct2.vcxproj | 2 + src/object/ObjectFactory.cpp | 4 ++ src/object/WallObject.cpp | 77 ++++++++++++++++++++++++++++++++++++ src/object/WallObject.h | 42 ++++++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 src/object/WallObject.cpp create mode 100644 src/object/WallObject.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 2bbbb5b06a..459f950a37 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -130,6 +130,7 @@ + @@ -442,6 +443,7 @@ + diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index f5ed13dcc1..87c5310c46 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -26,6 +26,7 @@ #include "RideObject.h" #include "SmallSceneryObject.h" #include "StexObject.h" +#include "WallObject.h" extern "C" { @@ -76,6 +77,9 @@ namespace ObjectFactory case OBJECT_TYPE_LARGE_SCENERY: result = new LargeSceneryObject(entry); break; + case OBJECT_TYPE_WALLS: + result = new WallObject(entry); + break; case OBJECT_TYPE_PATHS: result = new FootpathObject(entry); break; diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp new file mode 100644 index 0000000000..f4ca173b02 --- /dev/null +++ b/src/object/WallObject.cpp @@ -0,0 +1,77 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/IStream.hpp" +#include "../core/Memory.hpp" +#include "WallObject.h" + +extern "C" +{ + #include "../drawing/drawing.h" + #include "../localisation/localisation.h" +} + +enum OBJ_STRING_ID +{ + OBJ_STRING_ID_NAME, +}; + +void WallObject::ReadLegacy(IStream * stream) +{ + _legacyType.name = stream->ReadValue(); + _legacyType.image = stream->ReadValue(); + + _legacyType.wall.tool_id = stream->ReadValue(); + _legacyType.wall.flags = stream->ReadValue(); + _legacyType.wall.height = stream->ReadValue(); + _legacyType.wall.flags2 = stream->ReadValue(); + _legacyType.wall.price = stream->ReadValue(); + _legacyType.wall.scenery_tab_id = stream->ReadValue(); + _legacyType.wall.var_0D = stream->ReadValue(); + + StringTable.Read(stream, OBJ_STRING_ID_NAME); + + _sceneryTabEntry = stream->ReadValue(); + + ImageTable.Read(stream); +} + +void WallObject::Load() +{ + _legacyType.name = language_allocate_object_string(GetName()); + _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + + _legacyType.small_scenery.scenery_tab_id = 0xFF; + if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) + { + uint8 entryType, entryIndex; + if (find_object_in_entry_group(&_sceneryTabEntry, &entryType, &entryIndex)) + { + _legacyType.small_scenery.scenery_tab_id = entryIndex; + } + } +} + +void WallObject::Unload() +{ + language_free_object_string(_legacyType.name); + gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); +} + +const utf8 * WallObject::GetName() +{ + return StringTable.GetString(OBJ_STRING_ID_NAME); +} diff --git a/src/object/WallObject.h b/src/object/WallObject.h new file mode 100644 index 0000000000..af32bcaa38 --- /dev/null +++ b/src/object/WallObject.h @@ -0,0 +1,42 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "Object.h" + +extern "C" +{ + #include "../world/scenery.h" +} + +class WallObject : public Object +{ +private: + rct_scenery_entry _legacyType; + rct_object_entry _sceneryTabEntry; + +public: + explicit WallObject(const rct_object_entry &entry) : Object(entry) { }; + + void * GetLegacyData() override { return &_legacyType; } + + void ReadLegacy(IStream * stream) override; + void Load() override; + void Unload() override; + + const utf8 * GetName() override; +}; From a07bbc6bcef34eb5174d0a1c110fd9d8d4bcd1b9 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Jun 2016 23:43:30 +0100 Subject: [PATCH 016/116] add banner object loading --- openrct2.vcxproj | 2 + src/object/BannerObject.cpp | 74 ++++++++++++++++++++++++++++++++++++ src/object/BannerObject.h | 42 ++++++++++++++++++++ src/object/ObjectFactory.cpp | 4 ++ 4 files changed, 122 insertions(+) create mode 100644 src/object/BannerObject.cpp create mode 100644 src/object/BannerObject.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 459f950a37..361dc624e3 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -118,6 +118,7 @@ + @@ -431,6 +432,7 @@ + diff --git a/src/object/BannerObject.cpp b/src/object/BannerObject.cpp new file mode 100644 index 0000000000..76a3ef2c53 --- /dev/null +++ b/src/object/BannerObject.cpp @@ -0,0 +1,74 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/IStream.hpp" +#include "../core/Memory.hpp" +#include "BannerObject.h" + +extern "C" +{ + #include "../drawing/drawing.h" + #include "../localisation/localisation.h" +} + +enum OBJ_STRING_ID +{ + OBJ_STRING_ID_NAME, +}; + +void BannerObject::ReadLegacy(IStream * stream) +{ + _legacyType.name = stream->ReadValue(); + _legacyType.image = stream->ReadValue(); + + _legacyType.banner.scrolling_mode = stream->ReadValue(); + _legacyType.banner.flags = stream->ReadValue(); + _legacyType.banner.price = stream->ReadValue(); + _legacyType.banner.scenery_tab_id = stream->ReadValue(); + + StringTable.Read(stream, OBJ_STRING_ID_NAME); + + _sceneryTabEntry = stream->ReadValue(); + + ImageTable.Read(stream); +} + +void BannerObject::Load() +{ + _legacyType.name = language_allocate_object_string(GetName()); + _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + + _legacyType.banner.scenery_tab_id = 0xFF; + if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) + { + uint8 entryType, entryIndex; + if (find_object_in_entry_group(&_sceneryTabEntry, &entryType, &entryIndex)) + { + _legacyType.banner.scenery_tab_id = entryIndex; + } + } +} + +void BannerObject::Unload() +{ + language_free_object_string(_legacyType.name); + gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); +} + +const utf8 * BannerObject::GetName() +{ + return StringTable.GetString(OBJ_STRING_ID_NAME); +} diff --git a/src/object/BannerObject.h b/src/object/BannerObject.h new file mode 100644 index 0000000000..afb701f560 --- /dev/null +++ b/src/object/BannerObject.h @@ -0,0 +1,42 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "Object.h" + +extern "C" +{ + #include "../world/scenery.h" +} + +class BannerObject : public Object +{ +private: + rct_scenery_entry _legacyType; + rct_object_entry _sceneryTabEntry; + +public: + explicit BannerObject(const rct_object_entry &entry) : Object(entry) { }; + + void * GetLegacyData() override { return &_legacyType; } + + void ReadLegacy(IStream * stream) override; + void Load() override; + void Unload() override; + + const utf8 * GetName() override; +}; diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 87c5310c46..4f7c0041d2 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -17,6 +17,7 @@ #include "../core/FileStream.hpp" #include "../core/Memory.hpp" #include "../core/MemoryStream.h" +#include "BannerObject.h" #include "EntranceObject.h" #include "FootpathItemObject.h" #include "FootpathObject.h" @@ -80,6 +81,9 @@ namespace ObjectFactory case OBJECT_TYPE_WALLS: result = new WallObject(entry); break; + case OBJECT_TYPE_BANNERS: + result = new BannerObject(entry); + break; case OBJECT_TYPE_PATHS: result = new FootpathObject(entry); break; From 6912c537bb83485df60b792524cae2c83f7de528 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 00:06:55 +0100 Subject: [PATCH 017/116] add scenery group object loading --- openrct2.vcxproj | 2 + src/object/ObjectFactory.cpp | 4 ++ src/object/SceneryGroupObject.cpp | 107 ++++++++++++++++++++++++++++++ src/object/SceneryGroupObject.h | 47 +++++++++++++ 4 files changed, 160 insertions(+) create mode 100644 src/object/SceneryGroupObject.cpp create mode 100644 src/object/SceneryGroupObject.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 361dc624e3..f6e3e10429 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -128,6 +128,7 @@ + @@ -442,6 +443,7 @@ + diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 4f7c0041d2..667019af33 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -25,6 +25,7 @@ #include "Object.h" #include "ObjectFactory.h" #include "RideObject.h" +#include "SceneryGroupObject.h" #include "SmallSceneryObject.h" #include "StexObject.h" #include "WallObject.h" @@ -90,6 +91,9 @@ namespace ObjectFactory case OBJECT_TYPE_PATH_BITS: result = new FootpathItemObject(entry); break; + case OBJECT_TYPE_SCENERY_SETS: + result = new SceneryGroupObject(entry); + break; case OBJECT_TYPE_PARK_ENTRANCE: result = new EntranceObject(entry); break; diff --git a/src/object/SceneryGroupObject.cpp b/src/object/SceneryGroupObject.cpp new file mode 100644 index 0000000000..ab9c6d555f --- /dev/null +++ b/src/object/SceneryGroupObject.cpp @@ -0,0 +1,107 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/IStream.hpp" +#include "../core/Memory.hpp" +#include "SceneryGroupObject.h" + +extern "C" +{ + #include "../drawing/drawing.h" + #include "../localisation/localisation.h" +} + +enum OBJ_STRING_ID +{ + OBJ_STRING_ID_NAME, +}; + +SceneryGroupObject::~SceneryGroupObject() +{ + Memory::Free(_items); +} + +void SceneryGroupObject::ReadLegacy(IStream * stream) +{ + _legacyType.name = stream->ReadValue(); + _legacyType.image = stream->ReadValue(); + stream->Seek(0x80 * 2, STREAM_SEEK_CURRENT); + _legacyType.entry_count = stream->ReadValue(); + _legacyType.var_107 = stream->ReadValue(); + _legacyType.var_108 = stream->ReadValue(); + _legacyType.pad_109 = stream->ReadValue(); + _legacyType.var_10A = stream->ReadValue(); + + StringTable.Read(stream, OBJ_STRING_ID_NAME); + ReadItems(stream); + ImageTable.Read(stream); + + _legacyType.var_107 = _numItems; +} + +void SceneryGroupObject::Load() +{ + _legacyType.name = language_allocate_object_string(GetName()); + _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + + _legacyType.entry_count = 0; + for (uint32 i = 0; i < _numItems; i++) + { + uint8 entryType; + uint8 entryIndex; + if (find_object_in_entry_group(&_items[i], &entryType, &entryIndex)) + { + uint16 sceneryEntry = entryIndex; + switch (entryType) { + case OBJECT_TYPE_SMALL_SCENERY: break; + case OBJECT_TYPE_LARGE_SCENERY: sceneryEntry |= 0x300; break; + case OBJECT_TYPE_WALLS: sceneryEntry |= 0x200; break; + case OBJECT_TYPE_PATH_BITS: sceneryEntry |= 0x100; break; + default: sceneryEntry |= 0x400; break; + } + + _legacyType.scenery_entries[_legacyType.entry_count] = sceneryEntry; + _legacyType.entry_count++; + } + } +} + +void SceneryGroupObject::Unload() +{ + language_free_object_string(_legacyType.name); + gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); +} + +const utf8 * SceneryGroupObject::GetName() +{ + return StringTable.GetString(OBJ_STRING_ID_NAME); +} + +void SceneryGroupObject::ReadItems(IStream * stream) +{ + auto items = std::vector(); + + uint8 endMarker; + while ((endMarker = stream->ReadValue()) != 0xFF) + { + stream->Seek(-1, STREAM_SEEK_CURRENT); + rct_object_entry entry = stream->ReadValue(); + items.push_back(entry); + } + + _numItems = items.size(); + _items = Memory::DuplicateArray(items.data(), items.size()); +} diff --git a/src/object/SceneryGroupObject.h b/src/object/SceneryGroupObject.h new file mode 100644 index 0000000000..8f8b45ae48 --- /dev/null +++ b/src/object/SceneryGroupObject.h @@ -0,0 +1,47 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "Object.h" + +extern "C" +{ + #include "../world/scenery.h" +} + +class SceneryGroupObject : public Object +{ +private: + rct_scenery_set_entry _legacyType; + uint32 _numItems; + rct_object_entry * _items; + +public: + explicit SceneryGroupObject(const rct_object_entry &entry) : Object(entry) { }; + ~SceneryGroupObject(); + + void * GetLegacyData() override { return &_legacyType; } + + void ReadLegacy(IStream * stream) override; + void Load() override; + void Unload() override; + + const utf8 * GetName() override; + +private: + void ReadItems(IStream * stream); +}; From 25af7d346cc31970be19d5d0b99145a4f711ced8 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 00:31:16 +0100 Subject: [PATCH 018/116] add water object loading --- openrct2.vcxproj | 2 ++ src/object/ObjectFactory.cpp | 4 +++ src/object/WaterObject.cpp | 65 ++++++++++++++++++++++++++++++++++++ src/object/WaterObject.h | 41 +++++++++++++++++++++++ 4 files changed, 112 insertions(+) create mode 100644 src/object/WaterObject.cpp create mode 100644 src/object/WaterObject.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index f6e3e10429..f0f2277fe1 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -133,6 +133,7 @@ + @@ -448,6 +449,7 @@ + diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 667019af33..6af113b9ba 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -29,6 +29,7 @@ #include "SmallSceneryObject.h" #include "StexObject.h" #include "WallObject.h" +#include "WaterObject.h" extern "C" { @@ -97,6 +98,9 @@ namespace ObjectFactory case OBJECT_TYPE_PARK_ENTRANCE: result = new EntranceObject(entry); break; + case OBJECT_TYPE_WATER: + result = new WaterObject(entry); + break; case OBJECT_TYPE_SCENARIO_TEXT: result = new StexObject(entry); break; diff --git a/src/object/WaterObject.cpp b/src/object/WaterObject.cpp new file mode 100644 index 0000000000..9f87be8c5b --- /dev/null +++ b/src/object/WaterObject.cpp @@ -0,0 +1,65 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/IStream.hpp" +#include "WaterObject.h" + +extern "C" +{ + #include "../addresses.h" + #include "../localisation/localisation.h" +} + +enum OBJ_STRING_ID +{ + OBJ_STRING_ID_NAME, +}; + +void WaterObject::ReadLegacy(IStream * stream) +{ + _legacyType.string_idx = stream->ReadValue(); + _legacyType.image_id = stream->ReadValue(); + _legacyType.var_06 = stream->ReadValue(); + _legacyType.var_0A = stream->ReadValue(); + _legacyType.var_0E = stream->ReadValue(); + + StringTable.Read(stream, OBJ_STRING_ID_NAME); + ImageTable.Read(stream); +} + +void WaterObject::Load() +{ + _legacyType.string_idx = language_allocate_object_string(GetName()); + _legacyType.image_id = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.var_06 = _legacyType.image_id + 1; + _legacyType.var_0A = _legacyType.image_id + 4; + + if (RCT2_GLOBAL(0x009ADAFD, uint8) == 0) + { + load_palette(); + gfx_invalidate_screen(); + } +} + +void WaterObject::Unload() +{ + language_free_object_string(_legacyType.string_idx); +} + +const utf8 * WaterObject::GetName() +{ + return StringTable.GetString(OBJ_STRING_ID_NAME); +} diff --git a/src/object/WaterObject.h b/src/object/WaterObject.h new file mode 100644 index 0000000000..147ad7f570 --- /dev/null +++ b/src/object/WaterObject.h @@ -0,0 +1,41 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "Object.h" + +extern "C" +{ + #include "../world/water.h" +} + +class WaterObject : public Object +{ +private: + rct_water_type _legacyType; + +public: + explicit WaterObject(const rct_object_entry &entry) : Object(entry) { }; + + void * GetLegacyData() override { return &_legacyType; } + + void ReadLegacy(IStream * stream) override; + void Load() override; + void Unload() override; + + const utf8 * GetName() override; +}; From d7575732fbc5277fb3a626eb22883edd75eb556c Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 00:48:11 +0100 Subject: [PATCH 019/116] get title screen loading correctly --- src/object/ObjectRepository.cpp | 33 ++++++++++++++++++++++++++++++++- src/object_list.c | 2 +- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 1eaf17c1d6..30bf7b5a01 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -338,6 +338,19 @@ IObjectRepository * GetObjectRepository() return _objectRepository; } +Object * _loadedObjects[721] = { nullptr }; + +int GetObjectEntryIndex(uint8 objectType, uint8 entryIndex) +{ + int result = 0; + for (uint8 i = 0; i < objectType; i++) + { + result += object_entry_group_counts[i]; + } + result += entryIndex; + return result; +} + extern "C" { void object_list_load() @@ -378,10 +391,28 @@ extern "C" Memory::Copy(extendedEntry, object->GetObjectEntry(), sizeof(rct_object_entry)); extendedEntry->chunk_size = 0; - object->Load(); + int loadedObjectIndex = GetObjectEntryIndex(objectType, groupIndex); + delete _loadedObjects[loadedObjectIndex]; + _loadedObjects[loadedObjectIndex] = object; return 1; } + void reset_loaded_objects() + { + reset_type_to_ride_entry_index_map(); + + gTotalNoImages = 0xF26E; + + for (int i = 0; i < 721; i++) + { + Object * object = _loadedObjects[i]; + if (object != nullptr) + { + object->Load(); + } + } + } + void scenario_translate(scenario_index_entry * scenarioEntry, const rct_object_entry * stexObjectEntry) { rct_string_id localisedStringIds[3]; diff --git a/src/object_list.c b/src/object_list.c index 2fcf94c9cd..ada621d0a3 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -226,7 +226,7 @@ static void object_list_examine() * * rct2: 0x006A9FC0 */ -void reset_loaded_objects() +void reset_loaded_objects_old() { reset_type_to_ride_entry_index_map(); From b207f6112dfc0bf466bf8cb3d3572f3289d47646 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 15:19:43 +0100 Subject: [PATCH 020/116] fix unloading of objects --- src/object/ObjectRepository.cpp | 22 ++++++++++++++++++++++ src/object_list.c | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 30bf7b5a01..16408212bb 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -413,6 +413,28 @@ extern "C" } } + void object_unload_all() + { + for (int i = 0; i < 721; i++) + { + Object * object = _loadedObjects[i]; + if (object != nullptr) + { + object->Unload(); + delete object; + _loadedObjects[i] = nullptr; + } + } + for (int i = 0; i < OBJECT_ENTRY_GROUP_COUNT; i++) + { + for (int j = 0; j < object_entry_group_counts[i]; j++) + { + memset(&object_entry_groups[i].entries[j], 0xFF, sizeof(rct_object_entry_extended)); + object_entry_groups[i].chunks[j] = (uint8*)0xFFFFFFFF; + } + } + } + void scenario_translate(scenario_index_entry * scenarioEntry, const rct_object_entry * stexObjectEntry) { rct_string_id localisedStringIds[3]; diff --git a/src/object_list.c b/src/object_list.c index ada621d0a3..967517e92c 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -616,7 +616,7 @@ bool object_load_entries(rct_object_entry* entries) * * rct2: 0x006A9CE8 */ -void object_unload_all() +void object_unload_all_old() { int i, j; From 9b90249f5bf9d8a6592f8ec967086fc1bf031273 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 16:06:03 +0100 Subject: [PATCH 021/116] re-introduce object hash table --- src/object/ObjectRepository.cpp | 49 +++++++++++++++++++++++++------ src/object/SmallSceneryObject.cpp | 5 ++++ 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 16408212bb..91d502522e 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -14,6 +14,7 @@ *****************************************************************************/ #pragma endregion +#include #include #include "../common.h" @@ -55,10 +56,34 @@ struct QueryDirectoryResult uint32 FileDateModifiedChecksum; }; +struct ObjectEntryHash +{ + size_t operator()(const rct_object_entry &entry) const + { + uint32 hash = 5381; + for (int i = 0; i < 8; i++) + { + hash = ((hash << 5) + hash) + entry.name[i]; + } + return hash; + } +}; + +struct ObjectEntryEqual +{ + bool operator()(const rct_object_entry &lhs, const rct_object_entry &rhs) const + { + return memcmp(&lhs.name, &rhs.name, 8) == 0; + } +}; + +using ObjectEntryMap = std::unordered_map; + class ObjectRepository : public IObjectRepository { std::vector _items; QueryDirectoryResult _queryDirectoryResult; + ObjectEntryMap _itemMap; public: ~ObjectRepository() @@ -79,14 +104,10 @@ public: const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) override { - for (uint32 i = 0; i < _items.size(); i++) + auto kvp = _itemMap.find(*objectEntry); + if (kvp != _itemMap.end()) { - ObjectRepositoryItem * item = &_items[i]; - rct_object_entry * itemEntry = (rct_object_entry*)&item->ObjectEntry; - if (object_entry_compare(itemEntry, objectEntry)) - { - return item; - } + return &_items[kvp->second]; } return nullptr; } @@ -110,6 +131,7 @@ private: FreeItem(&_items[i]); } _items.clear(); + _itemMap.clear(); } void QueryDirectory() @@ -164,7 +186,7 @@ private: Memory::Copy(&item.ObjectEntry, object->GetObjectEntry(), sizeof(rct_object_entry)); item.Path = String::Duplicate(path); item.Name = String::Duplicate(object->GetName()); - _items.push_back(item); + AddItem(&item); } } @@ -187,7 +209,7 @@ private: for (uint32 i = 0; i < header.NumItems; i++) { ObjectRepositoryItem item = ReadItem(&fs); - _items.push_back(item); + AddItem(&item); } return true; } @@ -230,6 +252,15 @@ private: } } + void AddItem(ObjectRepositoryItem * item) + { + _items.push_back(*item); + size_t index = _items.size() - 1; + rct_object_entry entry; + Memory::Copy(&entry, &item->ObjectEntry, sizeof(rct_object_entry)); + _itemMap[entry] = index; + } + static ObjectRepositoryItem ReadItem(IStream * stream) { ObjectRepositoryItem item = { 0 }; diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index 055b28fa4b..8b5c95e764 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -76,6 +76,11 @@ void SmallSceneryObject::Load() _legacyType.small_scenery.scenery_tab_id = entryIndex; } } + + if (_legacyType.small_scenery.flags & SMALL_SCENERY_FLAG16) + { + _legacyType.small_scenery.var_10 = (uint32)_var10data; + } } void SmallSceneryObject::Unload() From 50b7e4222f0a98d31822e3408ce6027f11b70353 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 16:55:46 +0100 Subject: [PATCH 022/116] remove a lot of old object code --- src/drawing/sprite.c | 1 + src/localisation/language.cpp | 21 +- src/object.c | 125 ------- src/object.h | 1 - src/object/LargeSceneryObject.cpp | 2 + src/object/ObjectRepository.cpp | 29 ++ src/object/ObjectRepository.h | 1 + src/object_list.c | 558 +----------------------------- 8 files changed, 53 insertions(+), 685 deletions(-) diff --git a/src/drawing/sprite.c b/src/drawing/sprite.c index 0c16ef28cc..e1983c881a 100644 --- a/src/drawing/sprite.c +++ b/src/drawing/sprite.c @@ -194,6 +194,7 @@ uint32 gfx_object_allocate_images(const rct_g1_element * images, uint32 count) void gfx_object_free_images(uint32 baseImageId, uint32 count) { + _nextImageId = 29294; } /** diff --git a/src/localisation/language.cpp b/src/localisation/language.cpp index 70f357c162..bd87a4b628 100644 --- a/src/localisation/language.cpp +++ b/src/localisation/language.cpp @@ -14,6 +14,7 @@ *****************************************************************************/ #pragma endregion +#include #include "LanguagePack.h" extern "C" { @@ -455,17 +456,33 @@ bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_s outStringIds[2] != STR_NONE; } -static rct_string_id _nextObjectStringId = NONSTEX_BASE_STRING_ID; +static bool _availableObjectStringIdsInitialised = false; +static std::stack _availableObjectStringIds; rct_string_id language_allocate_object_string(const utf8 * target) { - rct_string_id stringId = _nextObjectStringId++; + if (!_availableObjectStringIdsInitialised) + { + _availableObjectStringIdsInitialised = true; + for (rct_string_id stringId = NONSTEX_BASE_STRING_ID + MAX_OBJECT_CACHED_STRINGS; stringId >= NONSTEX_BASE_STRING_ID; stringId--) + { + _availableObjectStringIds.push(stringId); + } + } + + rct_string_id stringId = _availableObjectStringIds.top(); + _availableObjectStringIds.pop(); _languageCurrent->SetString(stringId, target); return stringId; } void language_free_object_string(rct_string_id stringId) { + if (_languageCurrent != nullptr) + { + _languageCurrent->SetString(stringId, nullptr); + } + _availableObjectStringIds.push(stringId); } } diff --git a/src/object.c b/src/object.c index 225cf5518f..ae0978962c 100644 --- a/src/object.c +++ b/src/object.c @@ -50,131 +50,6 @@ int object_load_entry(const utf8 *path, rct_object_entry *outEntry) return 1; } -int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSize, const rct_object_entry *installedObject) -{ - uint8 objectType; - rct_object_entry openedEntry; - char path[MAX_PATH]; - SDL_RWops* rw; - - substitute_path(path, gRCT2AddressObjectDataPath, (char*)installedObject + 16); - - log_verbose("loading object, %s", path); - - rw = SDL_RWFromFile(path, "rb"); - if (rw == NULL) - return 0; - - SDL_RWread(rw, &openedEntry, sizeof(rct_object_entry), 1); - if (!object_entry_compare(&openedEntry, entry)) { - SDL_RWclose(rw); - return 0; - } - - // Get chunk size - uint8 *installedObject_pointer = (uint8*)installedObject + 16; - // Skip file name - while (*installedObject_pointer++); - - // Read chunk size - *chunkSize = *((uint32*)installedObject_pointer); - uint8 *chunk; - - if (*chunkSize == 0xFFFFFFFF) { - chunk = (uint8*)malloc(0x600000); - assert(chunk != NULL); - *chunkSize = sawyercoding_read_chunk_with_size(rw, chunk, 0x600000); - chunk = realloc(chunk, *chunkSize); - } - else { - chunk = (uint8*)malloc(*chunkSize); - *chunkSize = sawyercoding_read_chunk_with_size(rw, chunk, *chunkSize); - } - SDL_RWclose(rw); - if (chunk == NULL) { - log_error("Failed to load object from %s of size %d", path, *chunkSize); - return 0; - } - - int calculatedChecksum = object_calculate_checksum(&openedEntry, chunk, *chunkSize); - - // Calculate and check checksum - if (calculatedChecksum != openedEntry.checksum && !gConfigGeneral.allow_loading_with_incorrect_checksum) { - log_error("Object Load failed due to checksum failure: calculated checksum %d, object says %d.", calculatedChecksum, (int)openedEntry.checksum); - free(chunk); - return 0; - - } - - objectType = openedEntry.flags & 0x0F; - - if (!object_test(objectType, chunk)) { - log_error("Object Load failed due to paint failure."); - free(chunk); - return 0; - } - - if (gTotalNoImages >= 0x4726E){ - log_error("Object Load failed due to too many images loaded."); - free(chunk); - return 0; - } - - void** chunk_list = object_entry_groups[objectType].chunks; - if (groupIndex == -1) { - for (groupIndex = 0; chunk_list[groupIndex] != (void*)-1; groupIndex++) { - if (groupIndex + 1 >= object_entry_group_counts[objectType]) { - log_error("Object Load failed due to too many objects of a certain type."); - free(chunk); - return 0; - } - } - } - chunk_list[groupIndex] = chunk; - - rct_object_entry_extended* extended_entry = &object_entry_groups[objectType].entries[groupIndex]; - - memcpy(extended_entry, &openedEntry, sizeof(rct_object_entry)); - extended_entry->chunk_size = *chunkSize; - - gLastLoadedObjectChunkData = chunk; - - if (RCT2_GLOBAL(0x9ADAFD, uint8) != 0) { - object_load(objectType, chunk, groupIndex); - } - return 1; -} - -/** - * - * rct2: 0x006A985D - */ -int object_load_chunk_old(int groupIndex, rct_object_entry *entry, int* chunkSize) -{ - // Alow chunkSize to be null - int tempChunkSize; - if (chunkSize == NULL) - chunkSize = &tempChunkSize; - - RCT2_GLOBAL(0xF42B64, uint32) = groupIndex; - - if (gInstalledObjectsCount == 0) { - log_error("Object Load failed due to no items installed check."); - return 1; - } - - rct_object_entry *installedObject = object_list_find(entry); - if (installedObject == NULL) { - log_error("object not installed"); - return 0; - } - - if (object_load_file(groupIndex, entry, chunkSize, installedObject)) - return 1; - - return 0; -} - /** * * rct2: 0x006a9f42 diff --git a/src/object.h b/src/object.h index 3c9b1a3ea2..8f71595450 100644 --- a/src/object.h +++ b/src/object.h @@ -119,7 +119,6 @@ int object_load_packed(SDL_RWops* rw); void object_unload_all(); int check_object_entry(rct_object_entry *entry); -int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSize, const rct_object_entry *installedObject); int object_load_chunk(int groupIndex, rct_object_entry *entry, int* chunk_size); void object_unload_chunk(rct_object_entry *entry); int object_get_scenario_text(rct_object_entry *entry); diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index 4eb3ccf754..a3c74c8d1b 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -70,6 +70,8 @@ void LargeSceneryObject::Load() _legacyType.name = language_allocate_object_string(GetName()); _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.large_scenery.tiles = _tiles; + _legacyType.large_scenery.scenery_tab_id = 0xFF; if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) { diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 91d502522e..78a8132cd8 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -102,6 +102,21 @@ public: } } + const ObjectRepositoryItem * FindObject(const utf8 * name) override + { + rct_object_entry entry = { 0 }; + utf8 entryName[9] = { ' ' }; + String::Set(entryName, sizeof(entryName), name); + Memory::Copy(entry.name, entryName, 8); + + auto kvp = _itemMap.find(entry); + if (kvp != _itemMap.end()) + { + return &_items[kvp->second]; + } + return nullptr; + } + const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) override { auto kvp = _itemMap.find(*objectEntry); @@ -384,6 +399,20 @@ int GetObjectEntryIndex(uint8 objectType, uint8 entryIndex) extern "C" { + rct_object_entry * object_list_find(rct_object_entry * entry) + { + IObjectRepository * objRepo = GetObjectRepository(); + const ObjectRepositoryItem * item = objRepo->FindObject(entry); + return (rct_object_entry *)&item->ObjectEntry; + } + + rct_object_entry * object_list_find_by_name(const char * name) + { + IObjectRepository * objRepo = GetObjectRepository(); + const ObjectRepositoryItem * item = objRepo->FindObject(name); + return (rct_object_entry *)&item->ObjectEntry; + } + void object_list_load() { IObjectRepository * objRepo = GetObjectRepository(); diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index f64b6e6b86..93b10525a6 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -52,6 +52,7 @@ interface IObjectRepository { virtual ~IObjectRepository() { } + virtual const ObjectRepositoryItem * FindObject(const utf8 * name) abstract; virtual const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) abstract; virtual Object * LoadObject(const rct_object_entry * objectEntry) abstract; }; diff --git a/src/object_list.c b/src/object_list.c index 967517e92c..ee9b885528 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -30,18 +30,6 @@ #include "world/scenery.h" #include "world/water.h" -#define PLUGIN_VERSION 4 -#define FILTER_VERSION 1 - -typedef struct rct_plugin_header { - uint16 version; - uint32 total_files; - uint32 total_file_size; - uint32 date_modified_checksum; - uint32 object_list_size; - uint32 object_list_no_items; -} rct_plugin_header; - // 98DA00 int object_entry_group_counts[] = { 128, // rides @@ -102,11 +90,6 @@ const rct_object_entry_group object_entry_groups[] = { (void**)(gStexEntries ), (rct_object_entry_extended*)(0x00F3F03C + (720 * 20)) // scenario text 0x009ADAE4, 0xF4287C }; -static int object_list_cache_load(int totalFiles, uint64 totalFileSize, int fileDateModifiedChecksum); -static int object_list_cache_save(int fileCount, uint64 totalFileSize, int fileDateModifiedChecksum, int currentItemOffset); - -void object_list_create_hash_table(); -static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* installed_entry, const char* path, rct_object_filters* filter); static void load_object_filter(rct_object_entry* entry, uint8* chunk, rct_object_filters* filter); static rct_object_filters *_installedObjectFilters = NULL; @@ -120,82 +103,6 @@ uint32 gNumInstalledCustomObjects; void *gLastLoadedObjectChunkData; -static void get_plugin_path(utf8 *outPath) -{ - platform_get_user_directory(outPath, NULL); - strcat(outPath, "plugin.dat"); -} - -static uintptr_t object_get_length_cached(const rct_object_entry **entryCache, const size_t index) -{ - return (uintptr_t)entryCache[index + 1] - (uintptr_t)entryCache[index]; -} - -static rct_object_entry **_entryCache = NULL; - -static int object_comparator(const void *left, const void *right) -{ - const size_t leftIndex = *(const size_t *)left; - const size_t rightIndex = *(const size_t *)right; - const char *leftName = object_get_name(_entryCache[leftIndex]); - const char *rightName = object_get_name(_entryCache[rightIndex]); - return strcmp(leftName, rightName); -} - -static void object_list_sort() -{ - rct_object_entry **objectBuffer, *newBuffer, *entry, *destEntry; - rct_object_filters *newFilters = NULL, *destFilter = NULL; - int numObjects, bufferSize; - size_t entrySize; - - objectBuffer = &gInstalledObjects; - numObjects = gInstalledObjectsCount; - - - _entryCache = malloc((numObjects + 1)* sizeof(rct_object_entry*)); - size_t *sortLUT = malloc((numObjects + 1) * sizeof(size_t)); - entry = *objectBuffer; - // This loop initialises entry cache, so it doesn't have to be called 17M - // times, but only a few thousand. - int i = 0; - do { - _entryCache[i] = entry; - sortLUT[i] = i; - } while (i++ < numObjects && (entry = object_get_next(entry))); - qsort(sortLUT, numObjects, sizeof(size_t), object_comparator); - - // Get buffer size - bufferSize = (uintptr_t)entry - (uintptr_t)*objectBuffer; - - // Create new buffer - newBuffer = (rct_object_entry*)malloc(bufferSize); - destEntry = newBuffer; - if (_installedObjectFilters) { - newFilters = malloc(numObjects * sizeof(rct_object_filters)); - destFilter = newFilters; - } - - // Copy over sorted objects - for (int i = 0; i < numObjects; i++) { - entrySize = object_get_length_cached((const rct_object_entry **)_entryCache, sortLUT[i]); - memcpy(destEntry, _entryCache[sortLUT[i]], entrySize); - destEntry = (rct_object_entry*)((uintptr_t)destEntry + entrySize); - if (_installedObjectFilters) - destFilter[i] = _installedObjectFilters[sortLUT[i]]; - } - free(_entryCache); - free(sortLUT); - - // Replace old buffer - free(*objectBuffer); - *objectBuffer = newBuffer; - if (_installedObjectFilters) { - free(_installedObjectFilters); - _installedObjectFilters = newFilters; - } -} - static uint32 object_list_count_custom_objects() { uint32 numCustomObjects = 0; @@ -218,264 +125,7 @@ static uint32 object_list_count_custom_objects() static void object_list_examine() { object_list_count_custom_objects(); - object_list_sort(); - object_list_create_hash_table(); -} - -/** - * - * rct2: 0x006A9FC0 - */ -void reset_loaded_objects_old() -{ - reset_type_to_ride_entry_index_map(); - - gTotalNoImages = 0xF26E; - - for (int type = 0; type < 11; ++type){ - for (int j = 0; j < object_entry_group_counts[type]; j++){ - uint8* chunk = object_entry_groups[type].chunks[j]; - if (chunk != (uint8*)-1) - object_load(type, chunk, j); - } - } -} - -static int object_list_query_directory(int *outTotalFiles, uint64 *outTotalFileSize, int *outFileDateModifiedChecksum) -{ - int enumFileHandle, totalFiles, fileDateModifiedChecksum; - uint64 totalFileSize; - file_info enumFileInfo; - - totalFiles = 0; - totalFileSize = 0; - fileDateModifiedChecksum = 0; - - // Enumerate through each object in the directory - enumFileHandle = platform_enumerate_files_begin(gRCT2AddressObjectDataPath); - if (enumFileHandle == INVALID_HANDLE) - return 0; - - while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { - totalFiles++; - totalFileSize += enumFileInfo.size; - fileDateModifiedChecksum ^= - (uint32)(enumFileInfo.last_modified >> 32) ^ - (uint32)(enumFileInfo.last_modified & 0xFFFFFFFF); - fileDateModifiedChecksum = ror32(fileDateModifiedChecksum, 5); - } - platform_enumerate_files_end(enumFileHandle); - - *outTotalFiles = totalFiles; - *outTotalFileSize = totalFileSize; - *outFileDateModifiedChecksum = fileDateModifiedChecksum; - return 1; -} - -/** - * - * rct2: 0x006A8B40 - */ -void object_list_load_old() -{ - int enumFileHandle, totalFiles, fileDateModifiedChecksum; - uint64 totalFileSize; - file_info enumFileInfo; - - int ok = object_list_query_directory(&totalFiles, &totalFileSize, &fileDateModifiedChecksum); - if (ok != 1) { - return; - } - - // Would move this into cache load, but its used further on - totalFiles = ror32(totalFiles, 24); - totalFiles = (totalFiles & ~0xFF) | 1; - totalFiles = rol32(totalFiles, 24); - - if (object_list_cache_load(totalFiles, totalFileSize, fileDateModifiedChecksum)) { - return; - } - - // Dispose installed object list - reset_loaded_objects(); - SafeFree(gInstalledObjects); - - gInstalledObjectsCount = 0; - gInstalledObjects = (rct_object_entry*)malloc(4096); - if (gInstalledObjects == NULL) { - log_error("Failed to allocate memory for object list"); - rct2_exit_reason(835, 3162); - return; - } - - uint32 fileCount = 0; - uint32 objectCount = 0; - size_t currentEntryOffset = 0; - gNumInstalledRCT2Objects = 0; - - log_verbose("building cache of available objects..."); - - if (_installedObjectFilters) { - free(_installedObjectFilters); - _installedObjectFilters = NULL; - } - - enumFileHandle = platform_enumerate_files_begin(gRCT2AddressObjectDataPath); - if (enumFileHandle != INVALID_HANDLE) { - size_t installedObjectsCapacity = 4096; - while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) { - fileCount++; - - if ((installedObjectsCapacity - currentEntryOffset) <= 2842){ - installedObjectsCapacity += 4096; - gInstalledObjects = (rct_object_entry*)realloc(gInstalledObjects, installedObjectsCapacity); - if (gInstalledObjects == NULL) { - log_error("Failed to allocate memory for object list"); - rct2_exit_reason(835, 3162); - return; - } - } - - char path[MAX_PATH]; - substitute_path(path, gRCT2AddressObjectDataPath, enumFileInfo.path); - - rct_object_entry entry; - if (object_load_entry(path, &entry)) { - _installedObjectFilters = realloc(_installedObjectFilters, sizeof(rct_object_filters) * (objectCount + 1)); - - rct_object_entry *installedEntry = (rct_object_entry*)((size_t)gInstalledObjects + currentEntryOffset); - rct_object_filters filter; - size_t newEntrySize = install_object_entry(&entry, installedEntry, enumFileInfo.path, &filter); - if (newEntrySize != 0) { - _installedObjectFilters[objectCount] = filter; - objectCount++; - currentEntryOffset += newEntrySize; - } - } - } - platform_enumerate_files_end(enumFileHandle); - } - - reset_loaded_objects(); - - object_list_cache_save(fileCount, totalFileSize, fileDateModifiedChecksum, currentEntryOffset); - - // Reload track list - ride_list_item ride_list; - ride_list.entry_index = 0xFC; - ride_list.type = 0xFC; - // track_load_list(ride_list); - - object_list_examine(); -} - -static int object_list_cache_load(int totalFiles, uint64 totalFileSize, int fileDateModifiedChecksum) -{ - char path[MAX_PATH]; - SDL_RWops *file; - rct_plugin_header pluginHeader; - uint32 filterVersion = 0; - - log_verbose("loading object list cache (plugin.dat)"); - - get_plugin_path(path); - file = SDL_RWFromFile(path, "rb"); - if (file == NULL) { - log_verbose("Unable to load %s", path); - return 0; - } - - if (SDL_RWread(file, &pluginHeader, sizeof(rct_plugin_header), 1) == 1) { - // Check if object repository has changed in anyway - if ( - pluginHeader.version == PLUGIN_VERSION && - pluginHeader.total_files == totalFiles && - pluginHeader.total_file_size == totalFileSize && - pluginHeader.date_modified_checksum == fileDateModifiedChecksum - ) { - // Dispose installed object list - SafeFree(gInstalledObjects); - - // Read installed object list - gInstalledObjects = (rct_object_entry*)malloc(pluginHeader.object_list_size); - if (SDL_RWread(file, gInstalledObjects, pluginHeader.object_list_size, 1) == 1) { - gInstalledObjectsCount = pluginHeader.object_list_no_items; - - if (pluginHeader.object_list_no_items != (pluginHeader.total_files & 0xFFFFFF)) - log_error("Potential mismatch in file numbers. Possible corrupt file. Consider deleting plugin.dat."); - - if (SDL_RWread(file, &filterVersion, sizeof(filterVersion), 1) == 1) { - if (filterVersion == FILTER_VERSION) { - if (_installedObjectFilters != NULL) { - free(_installedObjectFilters); - } - _installedObjectFilters = malloc(sizeof(rct_object_filters) * pluginHeader.object_list_no_items); - if (SDL_RWread(file, _installedObjectFilters, sizeof(rct_object_filters) * pluginHeader.object_list_no_items, 1) == 1) { - SDL_RWclose(file); - reset_loaded_objects(); - object_list_examine(); - return 1; - } - } - } - log_info("Filter version updated... updating object list cache"); - } - } - else if (pluginHeader.version != PLUGIN_VERSION) { - log_info("Object list cache version different... updating"); - } - else if (pluginHeader.total_files != totalFiles) { - int fileCount = totalFiles - pluginHeader.total_files; - if (fileCount < 0) { - log_info("%d object removed... updating object list cache", abs(fileCount)); - } else { - log_info("%d object added... updating object list cache", fileCount); - } - } else if (pluginHeader.total_file_size != totalFileSize) { - log_info("Objects files size changed... updating object list cache"); - } else if (pluginHeader.date_modified_checksum != fileDateModifiedChecksum) { - log_info("Objects files have been updated... updating object list cache"); - } - - SDL_RWclose(file); - return 0; - } - - SDL_RWclose(file); - - log_error("loading object list cache failed"); - return 0; -} - -static int object_list_cache_save(int fileCount, uint64 totalFileSize, int fileDateModifiedChecksum, int currentItemOffset) -{ - utf8 path[MAX_PATH]; - SDL_RWops *file; - rct_plugin_header pluginHeader; - uint32 filterVersion = FILTER_VERSION; - - log_verbose("saving object list cache (plugin.dat)"); - - pluginHeader.version = PLUGIN_VERSION; - pluginHeader.total_files = fileCount | 0x01000000; - pluginHeader.total_file_size = (uint32)totalFileSize; - pluginHeader.date_modified_checksum = fileDateModifiedChecksum; - pluginHeader.object_list_size = currentItemOffset; - pluginHeader.object_list_no_items = gInstalledObjectsCount; - - get_plugin_path(path); - file = SDL_RWFromFile(path,"wb"); - if (file == NULL) { - log_error("Failed to save %s", path); - return 0; - } - - SDL_RWwrite(file, &pluginHeader, sizeof(rct_plugin_header), 1); - SDL_RWwrite(file, gInstalledObjects, pluginHeader.object_list_size, 1); - SDL_RWwrite(file, &filterVersion, sizeof(filterVersion), 1); - SDL_RWwrite(file, _installedObjectFilters, sizeof(rct_object_filters) * gInstalledObjectsCount, 1); - SDL_RWclose(file); - return 1; + // object_list_sort(); } int check_object_entry(rct_object_entry *entry) @@ -610,72 +260,6 @@ bool object_load_entries(rct_object_entry* entries) return true; } - - -/** - * - * rct2: 0x006A9CE8 - */ -void object_unload_all_old() -{ - int i, j; - - for (i = 0; i < OBJECT_ENTRY_GROUP_COUNT; i++) - for (j = 0; j < object_entry_group_counts[i]; j++) - if (object_entry_groups[i].chunks[j] != (uint8*)0xFFFFFFFF) - object_unload_chunk((rct_object_entry*)&object_entry_groups[i].entries[j]); - - reset_loaded_objects(); -} - - - -uint32 _installedObjectHashTableSize; -rct_object_entry ** _installedObjectHashTable = NULL; - -uint32 _installedObjectHashTableCollisions; - -uint32 object_get_hash_code(rct_object_entry *object) -{ - uint32 hash = 5381; - for (int i = 0; i < 8; i++) - hash = ((hash << 5) + hash) + object->name[i]; - - return hash; -} - -void object_list_create_hash_table() -{ - rct_object_entry *installedObject; - int numInstalledObjects = gInstalledObjectsCount; - - if (_installedObjectHashTable != NULL) - free(_installedObjectHashTable); - - _installedObjectHashTableSize = max(8192, numInstalledObjects * 4); - _installedObjectHashTable = calloc(_installedObjectHashTableSize, sizeof(rct_object_entry*)); - _installedObjectHashTableCollisions = 0; - - installedObject = gInstalledObjects; - for (int i = 0; i < numInstalledObjects; i++) { - uint32 hash = object_get_hash_code(installedObject); - uint32 index = hash % _installedObjectHashTableSize; - - // Find empty slot - while (_installedObjectHashTable[index] != NULL) { - _installedObjectHashTableCollisions++; - index++; - if (index >= _installedObjectHashTableSize) index = 0; - } - - // Set hash table slot - _installedObjectHashTable[index] = installedObject; - - // Next installed object - installedObject = object_get_next(installedObject); - } -} - /** * * rct2: 0x006A9DA2 @@ -701,41 +285,6 @@ int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8 return 1; } -rct_object_entry *object_list_find_by_name(const char * name) -{ - rct_object_entry entry; - memcpy(entry.name, name, 8); - - uint32 hash = object_get_hash_code(&entry); - uint32 index = hash % _installedObjectHashTableSize; - - while (_installedObjectHashTable[index] != NULL) { - if (memcmp(_installedObjectHashTable[index]->name, entry.name, 8) == 0) - return _installedObjectHashTable[index]; - - index++; - if (index >= _installedObjectHashTableSize) index = 0; - } - - return NULL; -} - -rct_object_entry *object_list_find(rct_object_entry *entry) -{ - uint32 hash = object_get_hash_code(entry); - uint32 index = hash % _installedObjectHashTableSize; - - while (_installedObjectHashTable[index] != NULL) { - if (object_entry_compare( _installedObjectHashTable[index], entry)) - return _installedObjectHashTable[index]; - - index++; - if (index >= _installedObjectHashTableSize) index = 0; - } - - return NULL; -} - rct_string_id object_get_name_string_id(rct_object_entry *entry, const void *chunk) { int objectType = entry->flags & 0x0F; @@ -763,111 +312,6 @@ rct_string_id object_get_name_string_id(rct_object_entry *entry, const void *chu } } -/** - * Installs an object_entry at the desired installed_entry address - * Returns the size of the new entry. Will return 0 on failure. - */ -static uint32 install_object_entry(rct_object_entry* entry, rct_object_entry* installed_entry, const char* path, rct_object_filters* filter){ - uint8* installed_entry_pointer = (uint8*) installed_entry; - - /** Copy all known information into the install entry **/ - memcpy(installed_entry_pointer, entry, sizeof(rct_object_entry)); - installed_entry_pointer += sizeof(rct_object_entry); - - strcpy((char *)installed_entry_pointer, path); - while (*installed_entry_pointer++); - - // Chunk size is set to unknown - *((sint32*)installed_entry_pointer) = -1; - // No unknown objects set to 0 - *(installed_entry_pointer + 4) = 0; - // No theme objects set to 0 - *((sint32*)(installed_entry_pointer + 5)) = 0; - *((uint16*)(installed_entry_pointer + 9)) = 0; - *((uint32*)(installed_entry_pointer + 11)) = 0; - - gTotalNoImages = 0xF26E; - - gInstalledObjectsCount++; - - // This is a variable used by object_load to decide if it should - // use object_paint on the entry. - RCT2_GLOBAL(0x009ADAFD, uint8) = 1; - - // Probably used by object paint. - RCT2_GLOBAL(0x009ADAF4, uint32) = 0xF42BDB; - - /** Use object_load_file to fill in missing chunk information **/ - int chunk_size; - if (!object_load_file(-1, entry, &chunk_size, installed_entry)){ - log_error("Object Load File failed. Potentially corrupt file: %.8s", entry->name); - RCT2_GLOBAL(0x009ADAF4, sint32) = -1; - RCT2_GLOBAL(0x009ADAFD, uint8) = 0; - gInstalledObjectsCount--; - return 0; - } - - // See above note - RCT2_GLOBAL(0x009ADAF4, sint32) = -1; - RCT2_GLOBAL(0x009ADAFD, uint8) = 0; - - if ((entry->flags & 0xF0) == 0x80) { - gNumInstalledRCT2Objects++; - if (gNumInstalledRCT2Objects > 772){ - log_error("Incorrect number of vanilla RCT2 objects."); - gNumInstalledRCT2Objects--; - gInstalledObjectsCount--; - object_unload_chunk(entry); - return 0; - } - } - *((sint32*)installed_entry_pointer) = chunk_size; - installed_entry_pointer += 4; - - uint8* chunk = (uint8*)gLastLoadedObjectChunkData; // Loaded in object_load - - load_object_filter(entry, chunk, filter); - - // Always extract only the vehicle type, since the track type is always displayed in the left column, to prevent duplicate track names. - rct_string_id nameStringId = object_get_name_string_id(entry, chunk); - if (nameStringId == STR_NONE) { - nameStringId = (rct_string_id)RCT2_GLOBAL(RCT2_ADDRESS_CURR_OBJECT_BASE_STRING_ID, uint32); - } - - strcpy((char *)installed_entry_pointer, language_get_string(nameStringId)); - while (*installed_entry_pointer++); - - // This is deceptive. Due to setting the total no images earlier to 0xF26E - // this is actually the no_images in this entry. - *((uint32*)installed_entry_pointer) = gTotalNoImages - 0xF26E; - installed_entry_pointer += 4; - - uint8* esi = RCT2_ADDRESS(0x00F42BDB, uint8); - uint8 num_unk_objects = *esi++; - *installed_entry_pointer++ = num_unk_objects; - if (num_unk_objects > 0) { - memcpy(installed_entry_pointer, esi, num_unk_objects * sizeof(rct_object_entry)); - installed_entry_pointer += num_unk_objects * sizeof(rct_object_entry); - esi += num_unk_objects * sizeof(rct_object_entry); - } - - uint8 no_theme_objects = *esi++; - *installed_entry_pointer++ = no_theme_objects; - if (no_theme_objects > 0) { - memcpy(installed_entry_pointer, esi, no_theme_objects * sizeof(rct_object_entry)); - installed_entry_pointer += no_theme_objects * sizeof(rct_object_entry); - } - - *((uint32*)installed_entry_pointer) = RCT2_GLOBAL(0x00F433DD, uint32); - installed_entry_pointer += 4; - - uint32 size_of_object = installed_entry_pointer - (uint8*)installed_entry; - - object_unload_chunk(entry); - - return size_of_object; -} - static void load_object_filter(rct_object_entry* entry, uint8* chunk, rct_object_filters* filter) { rct_ride_entry *rideType; From 1af6242381f6df5611344373c40186134aab0b37 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 21:20:32 +0100 Subject: [PATCH 023/116] Fix GCC by not naming field same as type --- src/object/BannerObject.cpp | 10 +++++----- src/object/EntranceObject.cpp | 10 +++++----- src/object/FootpathItemObject.cpp | 10 +++++----- src/object/FootpathObject.cpp | 10 +++++----- src/object/LargeSceneryObject.cpp | 10 +++++----- src/object/Object.h | 6 ++++-- src/object/RideObject.cpp | 18 +++++++++--------- src/object/SceneryGroupObject.cpp | 10 +++++----- src/object/SmallSceneryObject.cpp | 10 +++++----- src/object/StexObject.cpp | 12 ++++++------ src/object/WallObject.cpp | 10 +++++----- src/object/WaterObject.cpp | 8 ++++---- 12 files changed, 63 insertions(+), 61 deletions(-) diff --git a/src/object/BannerObject.cpp b/src/object/BannerObject.cpp index 76a3ef2c53..a2bbe8126d 100644 --- a/src/object/BannerObject.cpp +++ b/src/object/BannerObject.cpp @@ -39,17 +39,17 @@ void BannerObject::ReadLegacy(IStream * stream) _legacyType.banner.price = stream->ReadValue(); _legacyType.banner.scenery_tab_id = stream->ReadValue(); - StringTable.Read(stream, OBJ_STRING_ID_NAME); + GetStringTable().Read(stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); - ImageTable.Read(stream); + GetImageTable().Read(stream); } void BannerObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); _legacyType.banner.scenery_tab_id = 0xFF; if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) @@ -65,10 +65,10 @@ void BannerObject::Load() void BannerObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); } const utf8 * BannerObject::GetName() { - return StringTable.GetString(OBJ_STRING_ID_NAME); + return GetStringTable().GetString(OBJ_STRING_ID_NAME); } diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index fc9ee35a40..c5e83b3260 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -35,23 +35,23 @@ void EntranceObject::ReadLegacy(IStream * stream) _legacyType.scrolling_mode = stream->ReadValue(); _legacyType.text_height = stream->ReadValue(); - StringTable.Read(stream, OBJ_STRING_ID_NAME); - ImageTable.Read(stream); + GetStringTable().Read(stream, OBJ_STRING_ID_NAME); + GetImageTable().Read(stream); } void EntranceObject::Load() { _legacyType.string_idx = language_allocate_object_string(GetName()); - _legacyType.image_id = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.image_id = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); } void EntranceObject::Unload() { language_free_object_string(_legacyType.string_idx); - gfx_object_free_images(_legacyType.image_id, ImageTable.GetCount()); + gfx_object_free_images(_legacyType.image_id, GetImageTable().GetCount()); } const utf8 * EntranceObject::GetName() { - return StringTable.GetString(OBJ_STRING_ID_NAME); + return GetStringTable().GetString(OBJ_STRING_ID_NAME); } diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp index c765f4f3a7..bef7c82030 100644 --- a/src/object/FootpathItemObject.cpp +++ b/src/object/FootpathItemObject.cpp @@ -38,17 +38,17 @@ void FootpathItemObject::ReadLegacy(IStream * stream) _legacyType.path_bit.price = stream->ReadValue(); _legacyType.path_bit.scenery_tab_id = stream->ReadValue(); - StringTable.Read(stream, OBJ_STRING_ID_NAME); + GetStringTable().Read(stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); - ImageTable.Read(stream); + GetImageTable().Read(stream); } void FootpathItemObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); _legacyType.path_bit.scenery_tab_id = 0xFF; if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) @@ -64,10 +64,10 @@ void FootpathItemObject::Load() void FootpathItemObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); } const utf8 * FootpathItemObject::GetName() { - return StringTable.GetString(OBJ_STRING_ID_NAME); + return GetStringTable().GetString(OBJ_STRING_ID_NAME); } diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp index 55b9e726b5..2e8c2e36d0 100644 --- a/src/object/FootpathObject.cpp +++ b/src/object/FootpathObject.cpp @@ -39,24 +39,24 @@ void FootpathObject::ReadLegacy(IStream * stream) _legacyType.scrolling_mode = stream->ReadValue(); stream->Seek(1, STREAM_SEEK_BEGIN); - StringTable.Read(stream, OBJ_STRING_ID_NAME); - ImageTable.Read(stream); + GetStringTable().Read(stream, OBJ_STRING_ID_NAME); + GetImageTable().Read(stream); } void FootpathObject::Load() { _legacyType.string_idx = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); _legacyType.bridge_image = _legacyType.image + 109; } void FootpathObject::Unload() { language_free_object_string(_legacyType.string_idx); - gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); } const utf8 * FootpathObject::GetName() { - return StringTable.GetString(OBJ_STRING_ID_NAME); + return GetStringTable().GetString(OBJ_STRING_ID_NAME); } diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index a3c74c8d1b..977ae709be 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -49,7 +49,7 @@ void LargeSceneryObject::ReadLegacy(IStream * stream) _legacyType.large_scenery.var_11 = stream->ReadValue(); stream->Seek(5, STREAM_SEEK_CURRENT); - StringTable.Read(stream, OBJ_STRING_ID_NAME); + GetStringTable().Read(stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); @@ -62,13 +62,13 @@ void LargeSceneryObject::ReadLegacy(IStream * stream) _tiles = ReadTiles(stream); - ImageTable.Read(stream); + GetImageTable().Read(stream); } void LargeSceneryObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); _legacyType.large_scenery.tiles = _tiles; @@ -99,12 +99,12 @@ void LargeSceneryObject::Load() void LargeSceneryObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); } const utf8 * LargeSceneryObject::GetName() { - return StringTable.GetString(OBJ_STRING_ID_NAME); + return GetStringTable().GetString(OBJ_STRING_ID_NAME); } rct_large_scenery_tile * LargeSceneryObject::ReadTiles(IStream * stream) diff --git a/src/object/Object.h b/src/object/Object.h index adeebc0894..1e986c8302 100644 --- a/src/object/Object.h +++ b/src/object/Object.h @@ -31,10 +31,12 @@ class Object { private: rct_object_entry _objectEntry; + StringTable _stringTable; + ImageTable _imageTable; protected: - StringTable StringTable; - ImageTable ImageTable; + StringTable GetStringTable() { return _stringTable; } + ImageTable GetImageTable() { return _imageTable; } public: explicit Object(const rct_object_entry &entry); diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index 7be47fdc53..0e7cbb7e89 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -43,15 +43,15 @@ void RideObject::ReadLegacy(IStream * stream) { stream->Read(&_legacyType); - StringTable.Read(stream, OBJ_STRING_ID_NAME); - StringTable.Read(stream, OBJ_STRING_ID_DESCRIPTION); + GetStringTable().Read(stream, OBJ_STRING_ID_NAME); + GetStringTable().Read(stream, OBJ_STRING_ID_DESCRIPTION); // TODO: Move to its own function when ride construction window is merged. if (gConfigInterface.select_by_track_type) { _legacyType.enabledTrackPieces = 0xFFFFFFFFFFFFFFFF; } - StringTable.Read(stream, OBJ_STRING_ID_CAPACITY); + GetStringTable().Read(stream, OBJ_STRING_ID_CAPACITY); // Read preset colours, by default there are 32 _presetColours.count = stream->ReadValue(); @@ -75,14 +75,14 @@ void RideObject::ReadLegacy(IStream * stream) _peepLoadingPositions[i] = stream->ReadArray(numPeepLoadingPositions); } - ImageTable.Read(stream); + GetImageTable().Read(stream); } void RideObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); _legacyType.description = language_allocate_object_string(GetDescription()); - _legacyType.images_offset = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.images_offset = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); int cur_vehicle_images_offset = _legacyType.images_offset + 3; for (int i = 0; i < 4; i++) @@ -329,20 +329,20 @@ void RideObject::Unload() { language_free_object_string(_legacyType.name); language_free_object_string(_legacyType.description); - gfx_object_free_images(_legacyType.images_offset, ImageTable.GetCount()); + gfx_object_free_images(_legacyType.images_offset, GetImageTable().GetCount()); } const utf8 * RideObject::GetName() { - return StringTable.GetString(OBJ_STRING_ID_NAME); + return GetStringTable().GetString(OBJ_STRING_ID_NAME); } const utf8 * RideObject::GetDescription() { - return StringTable.GetString(OBJ_STRING_ID_DESCRIPTION); + return GetStringTable().GetString(OBJ_STRING_ID_DESCRIPTION); } const utf8 * RideObject::GetCapacity() { - return StringTable.GetString(OBJ_STRING_ID_CAPACITY); + return GetStringTable().GetString(OBJ_STRING_ID_CAPACITY); } diff --git a/src/object/SceneryGroupObject.cpp b/src/object/SceneryGroupObject.cpp index ab9c6d555f..62ee5f2793 100644 --- a/src/object/SceneryGroupObject.cpp +++ b/src/object/SceneryGroupObject.cpp @@ -45,9 +45,9 @@ void SceneryGroupObject::ReadLegacy(IStream * stream) _legacyType.pad_109 = stream->ReadValue(); _legacyType.var_10A = stream->ReadValue(); - StringTable.Read(stream, OBJ_STRING_ID_NAME); + GetStringTable().Read(stream, OBJ_STRING_ID_NAME); ReadItems(stream); - ImageTable.Read(stream); + GetImageTable().Read(stream); _legacyType.var_107 = _numItems; } @@ -55,7 +55,7 @@ void SceneryGroupObject::ReadLegacy(IStream * stream) void SceneryGroupObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); _legacyType.entry_count = 0; for (uint32 i = 0; i < _numItems; i++) @@ -82,12 +82,12 @@ void SceneryGroupObject::Load() void SceneryGroupObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); } const utf8 * SceneryGroupObject::GetName() { - return StringTable.GetString(OBJ_STRING_ID_NAME); + return GetStringTable().GetString(OBJ_STRING_ID_NAME); } void SceneryGroupObject::ReadItems(IStream * stream) diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index 8b5c95e764..812362ba6d 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -50,7 +50,7 @@ void SmallSceneryObject::ReadLegacy(IStream * stream) _legacyType.small_scenery.var_18 = stream->ReadValue(); _legacyType.small_scenery.scenery_tab_id = 0xFF; - StringTable.Read(stream, OBJ_STRING_ID_NAME); + GetStringTable().Read(stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); @@ -59,13 +59,13 @@ void SmallSceneryObject::ReadLegacy(IStream * stream) _var10data = ReadVar10(stream); } - ImageTable.Read(stream); + GetImageTable().Read(stream); } void SmallSceneryObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); _legacyType.small_scenery.scenery_tab_id = 0xFF; if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) @@ -86,12 +86,12 @@ void SmallSceneryObject::Load() void SmallSceneryObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); } const utf8 * SmallSceneryObject::GetName() { - return StringTable.GetString(OBJ_STRING_ID_NAME); + return GetStringTable().GetString(OBJ_STRING_ID_NAME); } uint8 * SmallSceneryObject::ReadVar10(IStream * stream) diff --git a/src/object/StexObject.cpp b/src/object/StexObject.cpp index 3a8434f732..96b358a45f 100644 --- a/src/object/StexObject.cpp +++ b/src/object/StexObject.cpp @@ -37,9 +37,9 @@ void StexObject::ReadLegacy(IStream * stream) _legacyType.var_06 = stream->ReadValue(); stream->Seek(1, STREAM_SEEK_CURRENT); - StringTable.Read(stream, OBJ_STRING_ID_SCENARIO_NAME); - StringTable.Read(stream, OBJ_STRING_ID_PARK_NAME); - StringTable.Read(stream, OBJ_STRING_ID_SCENARIO_DETAILS); + GetStringTable().Read(stream, OBJ_STRING_ID_SCENARIO_NAME); + GetStringTable().Read(stream, OBJ_STRING_ID_PARK_NAME); + GetStringTable().Read(stream, OBJ_STRING_ID_SCENARIO_DETAILS); } void StexObject::Load() @@ -63,15 +63,15 @@ const utf8 * StexObject::GetName() const utf8 * StexObject::GetScenarioName() { - return StringTable.GetString(OBJ_STRING_ID_SCENARIO_NAME); + return GetStringTable().GetString(OBJ_STRING_ID_SCENARIO_NAME); } const utf8 * StexObject::GetScenarioDetails() { - return StringTable.GetString(OBJ_STRING_ID_SCENARIO_DETAILS); + return GetStringTable().GetString(OBJ_STRING_ID_SCENARIO_DETAILS); } const utf8 * StexObject::GetParkName() { - return StringTable.GetString(OBJ_STRING_ID_PARK_NAME); + return GetStringTable().GetString(OBJ_STRING_ID_PARK_NAME); } diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp index f4ca173b02..af6f2b8330 100644 --- a/src/object/WallObject.cpp +++ b/src/object/WallObject.cpp @@ -42,17 +42,17 @@ void WallObject::ReadLegacy(IStream * stream) _legacyType.wall.scenery_tab_id = stream->ReadValue(); _legacyType.wall.var_0D = stream->ReadValue(); - StringTable.Read(stream, OBJ_STRING_ID_NAME); + GetStringTable().Read(stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); - ImageTable.Read(stream); + GetImageTable().Read(stream); } void WallObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); _legacyType.small_scenery.scenery_tab_id = 0xFF; if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) @@ -68,10 +68,10 @@ void WallObject::Load() void WallObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, ImageTable.GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); } const utf8 * WallObject::GetName() { - return StringTable.GetString(OBJ_STRING_ID_NAME); + return GetStringTable().GetString(OBJ_STRING_ID_NAME); } diff --git a/src/object/WaterObject.cpp b/src/object/WaterObject.cpp index 9f87be8c5b..fb7cc38517 100644 --- a/src/object/WaterObject.cpp +++ b/src/object/WaterObject.cpp @@ -36,14 +36,14 @@ void WaterObject::ReadLegacy(IStream * stream) _legacyType.var_0A = stream->ReadValue(); _legacyType.var_0E = stream->ReadValue(); - StringTable.Read(stream, OBJ_STRING_ID_NAME); - ImageTable.Read(stream); + GetStringTable().Read(stream, OBJ_STRING_ID_NAME); + GetImageTable().Read(stream); } void WaterObject::Load() { _legacyType.string_idx = language_allocate_object_string(GetName()); - _legacyType.image_id = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount()); + _legacyType.image_id = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); _legacyType.var_06 = _legacyType.image_id + 1; _legacyType.var_0A = _legacyType.image_id + 4; @@ -61,5 +61,5 @@ void WaterObject::Unload() const utf8 * WaterObject::GetName() { - return StringTable.GetString(OBJ_STRING_ID_NAME); + return GetStringTable().GetString(OBJ_STRING_ID_NAME); } From a0d8b9ccbfd94893140cf9daf0ea3975ff852611 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 21:43:30 +0100 Subject: [PATCH 024/116] handle empty string tables --- src/object/BannerObject.cpp | 11 ++++++----- src/object/EntranceObject.cpp | 11 ++++++----- src/object/FootpathItemObject.cpp | 11 ++++++----- src/object/FootpathObject.cpp | 11 ++++++----- src/object/LargeSceneryObject.cpp | 11 ++++++----- src/object/Object.h | 4 ++-- src/object/RideObject.cpp | 21 ++++++++++++--------- src/object/SceneryGroupObject.cpp | 11 ++++++----- src/object/SmallSceneryObject.cpp | 11 ++++++----- src/object/StexObject.cpp | 15 +++++++++------ src/object/WallObject.cpp | 11 ++++++----- src/object/WaterObject.cpp | 9 +++++---- 12 files changed, 76 insertions(+), 61 deletions(-) diff --git a/src/object/BannerObject.cpp b/src/object/BannerObject.cpp index a2bbe8126d..e4f317ffe9 100644 --- a/src/object/BannerObject.cpp +++ b/src/object/BannerObject.cpp @@ -39,17 +39,17 @@ void BannerObject::ReadLegacy(IStream * stream) _legacyType.banner.price = stream->ReadValue(); _legacyType.banner.scenery_tab_id = stream->ReadValue(); - GetStringTable().Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); - GetImageTable().Read(stream); + GetImageTable()->Read(stream); } void BannerObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.banner.scenery_tab_id = 0xFF; if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) @@ -65,10 +65,11 @@ void BannerObject::Load() void BannerObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } const utf8 * BannerObject::GetName() { - return GetStringTable().GetString(OBJ_STRING_ID_NAME); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); + return name != nullptr ? name : ""; } diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index c5e83b3260..0cb83caa53 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -35,23 +35,24 @@ void EntranceObject::ReadLegacy(IStream * stream) _legacyType.scrolling_mode = stream->ReadValue(); _legacyType.text_height = stream->ReadValue(); - GetStringTable().Read(stream, OBJ_STRING_ID_NAME); - GetImageTable().Read(stream); + GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); + GetImageTable()->Read(stream); } void EntranceObject::Load() { _legacyType.string_idx = language_allocate_object_string(GetName()); - _legacyType.image_id = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); + _legacyType.image_id = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); } void EntranceObject::Unload() { language_free_object_string(_legacyType.string_idx); - gfx_object_free_images(_legacyType.image_id, GetImageTable().GetCount()); + gfx_object_free_images(_legacyType.image_id, GetImageTable()->GetCount()); } const utf8 * EntranceObject::GetName() { - return GetStringTable().GetString(OBJ_STRING_ID_NAME); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); + return name != nullptr ? name : ""; } diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp index bef7c82030..44049e931a 100644 --- a/src/object/FootpathItemObject.cpp +++ b/src/object/FootpathItemObject.cpp @@ -38,17 +38,17 @@ void FootpathItemObject::ReadLegacy(IStream * stream) _legacyType.path_bit.price = stream->ReadValue(); _legacyType.path_bit.scenery_tab_id = stream->ReadValue(); - GetStringTable().Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); - GetImageTable().Read(stream); + GetImageTable()->Read(stream); } void FootpathItemObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.path_bit.scenery_tab_id = 0xFF; if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) @@ -64,10 +64,11 @@ void FootpathItemObject::Load() void FootpathItemObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } const utf8 * FootpathItemObject::GetName() { - return GetStringTable().GetString(OBJ_STRING_ID_NAME); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); + return name != nullptr ? name : ""; } diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp index 2e8c2e36d0..50674b9536 100644 --- a/src/object/FootpathObject.cpp +++ b/src/object/FootpathObject.cpp @@ -39,24 +39,25 @@ void FootpathObject::ReadLegacy(IStream * stream) _legacyType.scrolling_mode = stream->ReadValue(); stream->Seek(1, STREAM_SEEK_BEGIN); - GetStringTable().Read(stream, OBJ_STRING_ID_NAME); - GetImageTable().Read(stream); + GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); + GetImageTable()->Read(stream); } void FootpathObject::Load() { _legacyType.string_idx = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.bridge_image = _legacyType.image + 109; } void FootpathObject::Unload() { language_free_object_string(_legacyType.string_idx); - gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } const utf8 * FootpathObject::GetName() { - return GetStringTable().GetString(OBJ_STRING_ID_NAME); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); + return name != nullptr ? name : ""; } diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index 977ae709be..240d62d0af 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -49,7 +49,7 @@ void LargeSceneryObject::ReadLegacy(IStream * stream) _legacyType.large_scenery.var_11 = stream->ReadValue(); stream->Seek(5, STREAM_SEEK_CURRENT); - GetStringTable().Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); @@ -62,13 +62,13 @@ void LargeSceneryObject::ReadLegacy(IStream * stream) _tiles = ReadTiles(stream); - GetImageTable().Read(stream); + GetImageTable()->Read(stream); } void LargeSceneryObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.large_scenery.tiles = _tiles; @@ -99,12 +99,13 @@ void LargeSceneryObject::Load() void LargeSceneryObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } const utf8 * LargeSceneryObject::GetName() { - return GetStringTable().GetString(OBJ_STRING_ID_NAME); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); + return name != nullptr ? name : ""; } rct_large_scenery_tile * LargeSceneryObject::ReadTiles(IStream * stream) diff --git a/src/object/Object.h b/src/object/Object.h index 1e986c8302..22cae75a4c 100644 --- a/src/object/Object.h +++ b/src/object/Object.h @@ -35,8 +35,8 @@ private: ImageTable _imageTable; protected: - StringTable GetStringTable() { return _stringTable; } - ImageTable GetImageTable() { return _imageTable; } + StringTable * GetStringTable() { return &_stringTable; } + ImageTable * GetImageTable() { return &_imageTable; } public: explicit Object(const rct_object_entry &entry); diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index 0e7cbb7e89..bdd04cf3c6 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -43,15 +43,15 @@ void RideObject::ReadLegacy(IStream * stream) { stream->Read(&_legacyType); - GetStringTable().Read(stream, OBJ_STRING_ID_NAME); - GetStringTable().Read(stream, OBJ_STRING_ID_DESCRIPTION); + GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(stream, OBJ_STRING_ID_DESCRIPTION); // TODO: Move to its own function when ride construction window is merged. if (gConfigInterface.select_by_track_type) { _legacyType.enabledTrackPieces = 0xFFFFFFFFFFFFFFFF; } - GetStringTable().Read(stream, OBJ_STRING_ID_CAPACITY); + GetStringTable()->Read(stream, OBJ_STRING_ID_CAPACITY); // Read preset colours, by default there are 32 _presetColours.count = stream->ReadValue(); @@ -75,14 +75,14 @@ void RideObject::ReadLegacy(IStream * stream) _peepLoadingPositions[i] = stream->ReadArray(numPeepLoadingPositions); } - GetImageTable().Read(stream); + GetImageTable()->Read(stream); } void RideObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); _legacyType.description = language_allocate_object_string(GetDescription()); - _legacyType.images_offset = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); + _legacyType.images_offset = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); int cur_vehicle_images_offset = _legacyType.images_offset + 3; for (int i = 0; i < 4; i++) @@ -329,20 +329,23 @@ void RideObject::Unload() { language_free_object_string(_legacyType.name); language_free_object_string(_legacyType.description); - gfx_object_free_images(_legacyType.images_offset, GetImageTable().GetCount()); + gfx_object_free_images(_legacyType.images_offset, GetImageTable()->GetCount()); } const utf8 * RideObject::GetName() { - return GetStringTable().GetString(OBJ_STRING_ID_NAME); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); + return name != nullptr ? name : ""; } const utf8 * RideObject::GetDescription() { - return GetStringTable().GetString(OBJ_STRING_ID_DESCRIPTION); + const utf8 * description = GetStringTable()->GetString(OBJ_STRING_ID_DESCRIPTION); + return description != nullptr ? description : ""; } const utf8 * RideObject::GetCapacity() { - return GetStringTable().GetString(OBJ_STRING_ID_CAPACITY); + const utf8 * capacity = GetStringTable()->GetString(OBJ_STRING_ID_CAPACITY); + return capacity != nullptr ? capacity : ""; } diff --git a/src/object/SceneryGroupObject.cpp b/src/object/SceneryGroupObject.cpp index 62ee5f2793..262654b01a 100644 --- a/src/object/SceneryGroupObject.cpp +++ b/src/object/SceneryGroupObject.cpp @@ -45,9 +45,9 @@ void SceneryGroupObject::ReadLegacy(IStream * stream) _legacyType.pad_109 = stream->ReadValue(); _legacyType.var_10A = stream->ReadValue(); - GetStringTable().Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); ReadItems(stream); - GetImageTable().Read(stream); + GetImageTable()->Read(stream); _legacyType.var_107 = _numItems; } @@ -55,7 +55,7 @@ void SceneryGroupObject::ReadLegacy(IStream * stream) void SceneryGroupObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.entry_count = 0; for (uint32 i = 0; i < _numItems; i++) @@ -82,12 +82,13 @@ void SceneryGroupObject::Load() void SceneryGroupObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } const utf8 * SceneryGroupObject::GetName() { - return GetStringTable().GetString(OBJ_STRING_ID_NAME); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); + return name != nullptr ? name : ""; } void SceneryGroupObject::ReadItems(IStream * stream) diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index 812362ba6d..3ca97e0625 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -50,7 +50,7 @@ void SmallSceneryObject::ReadLegacy(IStream * stream) _legacyType.small_scenery.var_18 = stream->ReadValue(); _legacyType.small_scenery.scenery_tab_id = 0xFF; - GetStringTable().Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); @@ -59,13 +59,13 @@ void SmallSceneryObject::ReadLegacy(IStream * stream) _var10data = ReadVar10(stream); } - GetImageTable().Read(stream); + GetImageTable()->Read(stream); } void SmallSceneryObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.small_scenery.scenery_tab_id = 0xFF; if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) @@ -86,12 +86,13 @@ void SmallSceneryObject::Load() void SmallSceneryObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } const utf8 * SmallSceneryObject::GetName() { - return GetStringTable().GetString(OBJ_STRING_ID_NAME); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); + return name != nullptr ? name : ""; } uint8 * SmallSceneryObject::ReadVar10(IStream * stream) diff --git a/src/object/StexObject.cpp b/src/object/StexObject.cpp index 96b358a45f..bcb8906261 100644 --- a/src/object/StexObject.cpp +++ b/src/object/StexObject.cpp @@ -37,9 +37,9 @@ void StexObject::ReadLegacy(IStream * stream) _legacyType.var_06 = stream->ReadValue(); stream->Seek(1, STREAM_SEEK_CURRENT); - GetStringTable().Read(stream, OBJ_STRING_ID_SCENARIO_NAME); - GetStringTable().Read(stream, OBJ_STRING_ID_PARK_NAME); - GetStringTable().Read(stream, OBJ_STRING_ID_SCENARIO_DETAILS); + GetStringTable()->Read(stream, OBJ_STRING_ID_SCENARIO_NAME); + GetStringTable()->Read(stream, OBJ_STRING_ID_PARK_NAME); + GetStringTable()->Read(stream, OBJ_STRING_ID_SCENARIO_DETAILS); } void StexObject::Load() @@ -63,15 +63,18 @@ const utf8 * StexObject::GetName() const utf8 * StexObject::GetScenarioName() { - return GetStringTable().GetString(OBJ_STRING_ID_SCENARIO_NAME); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_SCENARIO_NAME); + return name != nullptr ? name : ""; } const utf8 * StexObject::GetScenarioDetails() { - return GetStringTable().GetString(OBJ_STRING_ID_SCENARIO_DETAILS); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_SCENARIO_DETAILS); + return name != nullptr ? name : ""; } const utf8 * StexObject::GetParkName() { - return GetStringTable().GetString(OBJ_STRING_ID_PARK_NAME); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_PARK_NAME); + return name != nullptr ? name : ""; } diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp index af6f2b8330..5c6163fdec 100644 --- a/src/object/WallObject.cpp +++ b/src/object/WallObject.cpp @@ -42,17 +42,17 @@ void WallObject::ReadLegacy(IStream * stream) _legacyType.wall.scenery_tab_id = stream->ReadValue(); _legacyType.wall.var_0D = stream->ReadValue(); - GetStringTable().Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); - GetImageTable().Read(stream); + GetImageTable()->Read(stream); } void WallObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); + _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.small_scenery.scenery_tab_id = 0xFF; if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) @@ -68,10 +68,11 @@ void WallObject::Load() void WallObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, GetImageTable().GetCount()); + gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } const utf8 * WallObject::GetName() { - return GetStringTable().GetString(OBJ_STRING_ID_NAME); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); + return name != nullptr ? name : ""; } diff --git a/src/object/WaterObject.cpp b/src/object/WaterObject.cpp index fb7cc38517..d42fa572ad 100644 --- a/src/object/WaterObject.cpp +++ b/src/object/WaterObject.cpp @@ -36,14 +36,14 @@ void WaterObject::ReadLegacy(IStream * stream) _legacyType.var_0A = stream->ReadValue(); _legacyType.var_0E = stream->ReadValue(); - GetStringTable().Read(stream, OBJ_STRING_ID_NAME); - GetImageTable().Read(stream); + GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); + GetImageTable()->Read(stream); } void WaterObject::Load() { _legacyType.string_idx = language_allocate_object_string(GetName()); - _legacyType.image_id = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount()); + _legacyType.image_id = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.var_06 = _legacyType.image_id + 1; _legacyType.var_0A = _legacyType.image_id + 4; @@ -61,5 +61,6 @@ void WaterObject::Unload() const utf8 * WaterObject::GetName() { - return GetStringTable().GetString(OBJ_STRING_ID_NAME); + const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); + return name != nullptr ? name : ""; } From 6d80f2bc799d983eefce39981cb987024201d09d Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 21:55:14 +0100 Subject: [PATCH 025/116] handle object load exceptions --- src/object/ObjectFactory.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 6af113b9ba..ed3e1073ca 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -14,6 +14,7 @@ *****************************************************************************/ #pragma endregion +#include "../core/Console.hpp" #include "../core/FileStream.hpp" #include "../core/Memory.hpp" #include "../core/MemoryStream.h" @@ -57,7 +58,17 @@ namespace ObjectFactory bufferSize = sawyercoding_read_chunk_with_size(file, (uint8 *)buffer, bufferSize); buffer = Memory::Reallocate(buffer, bufferSize); auto ms = MemoryStream(buffer, bufferSize); - result->ReadLegacy(&ms); + try + { + result->ReadLegacy(&ms); + } + catch (Exception ex) + { + Console::Error::WriteFormat("Error reading object: '%s'", path); + Console::Error::WriteLine(); + delete result; + result = nullptr; + } } } SDL_RWclose(file); From 602a3d4775b435b353e83d0f730447275406e698 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 22:01:43 +0100 Subject: [PATCH 026/116] do not free non allocated array --- src/object/RideObject.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index bdd04cf3c6..6b094cda8d 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -36,7 +36,10 @@ enum OBJ_STRING_ID RideObject::~RideObject() { - Memory::FreeArray(_peepLoadingPositions, 4); + for (int i = 0; i < 4; i++) + { + Memory::Free(_peepLoadingPositions[i]); + } } void RideObject::ReadLegacy(IStream * stream) From 78bbfe8daf0bf932e344782507b5997d9e6c56e3 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 22:06:43 +0100 Subject: [PATCH 027/116] initialise pointers in LargeSceneryObject --- src/object/LargeSceneryObject.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/object/LargeSceneryObject.h b/src/object/LargeSceneryObject.h index 3222844175..4f0ba88384 100644 --- a/src/object/LargeSceneryObject.h +++ b/src/object/LargeSceneryObject.h @@ -28,8 +28,8 @@ class LargeSceneryObject : public Object private: rct_scenery_entry _legacyType; rct_object_entry _sceneryTabEntry; - rct_large_scenery_text * _3dFont; - rct_large_scenery_tile * _tiles; + rct_large_scenery_text * _3dFont = nullptr; + rct_large_scenery_tile * _tiles = nullptr; public: explicit LargeSceneryObject(const rct_object_entry &entry) : Object(entry) { }; From 12f48f36b52001659ed1ac1855e46de38c4b0e82 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 22:14:41 +0100 Subject: [PATCH 028/116] disable set_load_objects_fail_reason for now --- src/object_list.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/object_list.c b/src/object_list.c index ee9b885528..9d1a0e762e 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -168,6 +168,8 @@ void object_create_identifier_name(char* string_buffer, const rct_object_entry* */ void set_load_objects_fail_reason() { + return; + rct_object_entry *object; memcpy(&object, gCommonFormatArgs, sizeof(rct_object_entry*)); From 84bd948488a058e74bb88322acf248a1aabcbbe4 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 22:38:33 +0100 Subject: [PATCH 029/116] report object scan time --- src/object/ObjectRepository.cpp | 11 ++++++++++- src/object_list.c | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 78a8132cd8..a6f1c7ae9c 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -24,6 +24,7 @@ #include "../core/IStream.hpp" #include "../core/Memory.hpp" #include "../core/Path.hpp" +#include "../core/Stopwatch.hpp" #include "../core/String.hpp" #include "Object.h" #include "ObjectFactory.h" @@ -176,6 +177,11 @@ private: utf8 objectDirectory[MAX_PATH]; Path::GetDirectory(objectDirectory, sizeof(objectDirectory), gRCT2AddressObjectDataPath); + Console::WriteLine("Scanning objects..."); + + auto stopwatch = Stopwatch(); + stopwatch.Start(); + int enumFileHandle = platform_enumerate_files_begin(gRCT2AddressObjectDataPath); if (enumFileHandle != INVALID_HANDLE) { @@ -190,6 +196,9 @@ private: } platform_enumerate_files_end(enumFileHandle); } + + stopwatch.Stop(); + Console::WriteLine("Scanning complete in %.2f seconds.", stopwatch.GetElapsedMilliseconds() / 1000.0f); } void ScanObject(utf8 * path) @@ -228,7 +237,7 @@ private: } return true; } - log_info("Object repository is out of date."); + Console::WriteLine("Object repository is out of date."); return false; } catch (IOException ex) diff --git a/src/object_list.c b/src/object_list.c index 9d1a0e762e..ade4bddb87 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -247,8 +247,8 @@ bool object_load_entries(rct_object_entry* entries) // Load the obect if (!object_load_chunk(entryGroupIndex, &entries[i], NULL)) { - log_error("failed to load entry: %.8s", entries[i].name); - memcpy(gCommonFormatArgs, &entries[i], sizeof(rct_object_entry)); + // log_error("failed to load entry: %.8s", entries[i].name); + // memcpy(gCommonFormatArgs, &entries[i], sizeof(rct_object_entry)); loadFailed = true; } } From 01cd37316cf61f0fc630d4bc27fbe868de7f7315 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 23:30:44 +0100 Subject: [PATCH 030/116] prepare unpacking objects --- src/object.c | 2 +- src/object/ObjectRepository.cpp | 103 ++++++++++++++++++++++++++++++++ src/object/ObjectRepository.h | 3 + 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/src/object.c b/src/object.c index ae0978962c..0f0c4def05 100644 --- a/src/object.c +++ b/src/object.c @@ -132,7 +132,7 @@ int write_object_file(SDL_RWops *rw, rct_object_entry* entry) * * rct2: 0x006AA2B7 */ -int object_load_packed(SDL_RWops* rw) +int object_load_packed_old(SDL_RWops* rw) { object_unload_all(); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index a6f1c7ae9c..16980ca014 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -33,10 +33,12 @@ extern "C" { + #include "../config.h" #include "../localisation/localisation.h" #include "../object.h" #include "../platform/platform.h" #include "../scenario.h" + #include "../util/sawyercoding.h" } constexpr uint16 OBJECT_REPOSITORY_VERSION = 6; @@ -139,6 +141,36 @@ public: return object; } + void AddObject(const rct_object_entry * objectEntry, const void * data, size_t dataSize) override + { + char objectName[9] = { 0 }; + Memory::Copy(objectName, objectEntry->name, 8); + + int realChecksum = object_calculate_checksum(objectEntry, (const uint8 *)data, (int)dataSize); + if (realChecksum != objectEntry->checksum) + { + log_error("Checksum mismatch from packed object: %.8s", objectName); + if (!gConfigGeneral.allow_loading_with_incorrect_checksum) + { + return; + } + } + + utf8 path[MAX_PATH]; + GetPathForNewObject(path, sizeof(path), objectName); + + Console::WriteLine("Adding object: [%s]", objectName); + try + { + SaveObject(path, objectEntry, data, dataSize); + ScanObject(path); + } + catch (Exception ex) + { + Console::WriteLine("Failed saving object: [%s] to '%s'.", objectName, path); + } + } + private: void ClearItems() { @@ -374,6 +406,50 @@ private: item->ThemeObjects = nullptr; } + static void SaveObject(const utf8 * path, const rct_object_entry * entry, const void * data, size_t dataSize) + { + // TODO + // auto fs = FileStream(path, FILE_MODE_WRITE); + // fs.Write(entry, sizeof(entry)); + } + + static void GetPathForNewObject(utf8 * buffer, size_t bufferSize, const char * name) + { + char normalisedName[9] = { 0 }; + for (int i = 0; i < 8; i++) + { + if (name[i] != ' ') + { + normalisedName[i] = toupper(name[i]); + } + else + { + normalisedName[i] = '\0'; + } + } + + substitute_path(buffer, gRCT2AddressObjectDataPath, normalisedName); + char * lastCh = buffer + strlen(buffer); + strcat(buffer, ".DAT"); + + for (; platform_file_exists(buffer);) + { + for (char * ch = lastCh - 1; ; ch--) + { + if (*ch == '\\') + { + substitute_path(buffer, gRCT2AddressObjectDataPath, "00000000.DAT"); + break; + } + if (*ch < '0') *ch = '0'; + else if (*ch == '9') *ch = 'A'; + else if (*ch == 'Z') *ch = '0'; + else (*ch)++; + if (*ch != '0') break; + } + } + } + static void GetRepositoryPath(utf8 * buffer, size_t bufferSize) { platform_get_user_directory(buffer, nullptr); @@ -539,4 +615,31 @@ extern "C" } } } + + int object_load_packed(SDL_RWops * rw) + { + rct_object_entry entry; + SDL_RWread(rw, &entry, 16, 1); + + uint8 * chunk = Memory::Allocate(0x600000); + if (chunk == nullptr) + { + log_error("Failed to allocate buffer for packed object."); + return 0; + } + + uint32 chunkSize = sawyercoding_read_chunk(rw, chunk); + chunk = Memory::Reallocate(chunk, chunkSize); + if (chunk == nullptr) + { + log_error("Failed to reallocate buffer for packed object."); + return 0; + } + + IObjectRepository * objRepo = GetObjectRepository(); + objRepo->AddObject(&entry, chunk, chunkSize); + + Memory::Free(chunk); + return 1; + } } diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 93b10525a6..2d766fff21 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -55,6 +55,9 @@ interface IObjectRepository virtual const ObjectRepositoryItem * FindObject(const utf8 * name) abstract; virtual const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) abstract; virtual Object * LoadObject(const rct_object_entry * objectEntry) abstract; + virtual void AddObject(const rct_object_entry * objectEntry, + const void * data, + size_t dataSize) abstract; }; IObjectRepository * GetObjectRepository(); From 09782e980c89ed1c5f660ae62478a0ee3638c9dd Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 26 Jun 2016 23:57:24 +0100 Subject: [PATCH 031/116] implement saving of objects and fix other bugs --- src/core/MemoryStream.cpp | 2 +- src/object/ObjectFactory.cpp | 37 +++++++++++++----- src/object/ObjectRepository.cpp | 68 ++++++++++++++++++++++++--------- src/util/sawyercoding.c | 18 +++++++++ src/util/sawyercoding.h | 1 + 5 files changed, 97 insertions(+), 29 deletions(-) diff --git a/src/core/MemoryStream.cpp b/src/core/MemoryStream.cpp index 2e6d46f525..cf3855938b 100644 --- a/src/core/MemoryStream.cpp +++ b/src/core/MemoryStream.cpp @@ -69,7 +69,7 @@ MemoryStream::MemoryStream(const void * data, size_t dataSize) MemoryStream::~MemoryStream() { - if (MEMORY_ACCESS_OWNER) + if (_access & MEMORY_ACCESS_OWNER) { Memory::Free(_data); } diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index ed3e1073ca..92169a99f9 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -55,20 +55,37 @@ namespace ObjectFactory { size_t bufferSize = 0x600000; void * buffer = Memory::Allocate(bufferSize); - bufferSize = sawyercoding_read_chunk_with_size(file, (uint8 *)buffer, bufferSize); - buffer = Memory::Reallocate(buffer, bufferSize); - auto ms = MemoryStream(buffer, bufferSize); - try + if (buffer == nullptr) { - result->ReadLegacy(&ms); - } - catch (Exception ex) - { - Console::Error::WriteFormat("Error reading object: '%s'", path); - Console::Error::WriteLine(); + log_error("Unable to allocate data buffer."); delete result; result = nullptr; } + else + { + try + { + bufferSize = sawyercoding_read_chunk_with_size(file, (uint8 *)buffer, bufferSize); + if (bufferSize == SIZE_MAX) + { + throw IOException("Error decoding data."); + } + + buffer = Memory::Reallocate(buffer, bufferSize); + auto ms = MemoryStream(buffer, bufferSize); + result->ReadLegacy(&ms); + + Memory::Free(buffer); + } + catch (Exception ex) + { + Memory::Free(buffer); + Console::Error::WriteFormat("Error reading object: '%s'", path); + Console::Error::WriteLine(); + delete result; + result = nullptr; + } + } } } SDL_RWclose(file); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 16980ca014..cb6927efba 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -156,6 +156,8 @@ public: } } + // TODO append checksum match bytes + utf8 path[MAX_PATH]; GetPathForNewObject(path, sizeof(path), objectName); @@ -408,9 +410,29 @@ private: static void SaveObject(const utf8 * path, const rct_object_entry * entry, const void * data, size_t dataSize) { - // TODO - // auto fs = FileStream(path, FILE_MODE_WRITE); - // fs.Write(entry, sizeof(entry)); + uint8 objectType = entry->flags & 0x0F; + + // Encode data + sawyercoding_chunk_header chunkHeader; + chunkHeader.encoding = object_entry_group_encoding[objectType]; + chunkHeader.length = dataSize; + uint8 * encodedDataBuffer = Memory::Allocate(0x600000); + size_t encodedDataSize = sawyercoding_write_chunk_buffer(encodedDataBuffer, (uint8 *)data, chunkHeader); + + // Save to file + try + { + auto fs = FileStream(path, FILE_MODE_WRITE); + fs.Write(entry, sizeof(rct_object_entry)); + fs.Write(encodedDataBuffer, encodedDataSize); + + Memory::Free(encodedDataBuffer); + } + catch (Exception ex) + { + Memory::Free(encodedDataBuffer); + throw; + } } static void GetPathForNewObject(utf8 * buffer, size_t bufferSize, const char * name) @@ -618,28 +640,38 @@ extern "C" int object_load_packed(SDL_RWops * rw) { + IObjectRepository * objRepo = GetObjectRepository(); + rct_object_entry entry; SDL_RWread(rw, &entry, 16, 1); - uint8 * chunk = Memory::Allocate(0x600000); - if (chunk == nullptr) + // Check if we already have this object + if (objRepo->FindObject(&entry) != nullptr) { - log_error("Failed to allocate buffer for packed object."); - return 0; + sawyercoding_skip_chunk(rw); } - - uint32 chunkSize = sawyercoding_read_chunk(rw, chunk); - chunk = Memory::Reallocate(chunk, chunkSize); - if (chunk == nullptr) + else { - log_error("Failed to reallocate buffer for packed object."); - return 0; + // Read object and save to new file + uint8 * chunk = Memory::Allocate(0x600000); + if (chunk == nullptr) + { + log_error("Failed to allocate buffer for packed object."); + return 0; + } + + uint32 chunkSize = sawyercoding_read_chunk(rw, chunk); + chunk = Memory::Reallocate(chunk, chunkSize); + if (chunk == nullptr) + { + log_error("Failed to reallocate buffer for packed object."); + return 0; + } + + objRepo->AddObject(&entry, chunk, chunkSize); + + Memory::Free(chunk); } - - IObjectRepository * objRepo = GetObjectRepository(); - objRepo->AddObject(&entry, chunk, chunkSize); - - Memory::Free(chunk); return 1; } } diff --git a/src/util/sawyercoding.c b/src/util/sawyercoding.c index d9622f4d8c..2e9dbebd05 100644 --- a/src/util/sawyercoding.c +++ b/src/util/sawyercoding.c @@ -96,6 +96,20 @@ bool sawyercoding_read_chunk_safe(SDL_RWops *rw, void *dst, size_t dstLength) } } +bool sawyercoding_skip_chunk(SDL_RWops *rw) +{ + // Read chunk header + sawyercoding_chunk_header chunkHeader; + if (SDL_RWread(rw, &chunkHeader, sizeof(sawyercoding_chunk_header), 1) != 1) { + log_error("Unable to read chunk header!"); + return false; + } + + // Skip chunk data + SDL_RWseek(rw, chunkHeader.length, RW_SEEK_CUR); + return true; +} + /** * * rct2: 0x0067685F @@ -157,6 +171,10 @@ size_t sawyercoding_read_chunk_with_size(SDL_RWops* rw, uint8 *buffer, const siz } uint8* src_buffer = malloc(chunkHeader.length); + if (src_buffer == NULL) { + log_error("Unable to read chunk data!"); + return -1; + } // Read chunk data if (SDL_RWread(rw, src_buffer, chunkHeader.length, 1) != 1) { diff --git a/src/util/sawyercoding.h b/src/util/sawyercoding.h index 5160c125ce..d7bd3d07b2 100644 --- a/src/util/sawyercoding.h +++ b/src/util/sawyercoding.h @@ -50,6 +50,7 @@ enum { int sawyercoding_validate_checksum(SDL_RWops* rw); uint32 sawyercoding_calculate_checksum(const uint8* buffer, size_t length); bool sawyercoding_read_chunk_safe(SDL_RWops *rw, void *dst, size_t dstLength); +bool sawyercoding_skip_chunk(SDL_RWops *rw); size_t sawyercoding_read_chunk(SDL_RWops* rw, uint8 *buffer); size_t sawyercoding_read_chunk_with_size(SDL_RWops* rw, uint8 *buffer, const size_t buffer_size); size_t sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader); From 9e142efbd2f5099f35314c36968cde5241c81ce5 Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 27 Jun 2016 21:04:08 +0100 Subject: [PATCH 032/116] display the number of files scanned --- src/object/ObjectRepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index cb6927efba..32c9b18c24 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -211,7 +211,7 @@ private: utf8 objectDirectory[MAX_PATH]; Path::GetDirectory(objectDirectory, sizeof(objectDirectory), gRCT2AddressObjectDataPath); - Console::WriteLine("Scanning objects..."); + Console::WriteLine("Scanning %lu objects...", _queryDirectoryResult.TotalFiles); auto stopwatch = Stopwatch(); stopwatch.Start(); From 904b5923caeae5e6c43eb7d48bfcf9126b72b2ca Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 27 Jun 2016 22:02:58 +0100 Subject: [PATCH 033/116] support objdata recursive and user directory --- src/object/ObjectRepository.cpp | 176 +++++++++++++++++++++++++++----- 1 file changed, 151 insertions(+), 25 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 32c9b18c24..1d2d150e2d 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -49,6 +49,7 @@ struct ObjectRepositoryHeader uint32 TotalFiles; uint64 TotalFileSize; uint32 FileDateModifiedChecksum; + uint32 PathChecksum; uint32 NumItems; }; @@ -57,6 +58,7 @@ struct QueryDirectoryResult uint32 TotalFiles; uint64 TotalFileSize; uint32 FileDateModifiedChecksum; + uint32 PathChecksum; }; struct ObjectEntryHash @@ -97,7 +99,15 @@ public: void LoadOrConstruct() { ClearItems(); - QueryDirectory(); + + _queryDirectoryResult = { 0 }; + + utf8 path[MAX_PATH]; + GetRCT2ObjectPath(path, sizeof(path)); + QueryDirectory(&_queryDirectoryResult, path); + GetUserObjectPath(path, sizeof(path)); + QueryDirectory(&_queryDirectoryResult, path); + if (!Load()) { Construct(); @@ -184,12 +194,15 @@ private: _itemMap.clear(); } - void QueryDirectory() + void QueryDirectory(QueryDirectoryResult * result, const utf8 * directory) { - QueryDirectoryResult * result = &_queryDirectoryResult; - // Enumerate through each object in the directory - int enumFileHandle = platform_enumerate_files_begin(gRCT2AddressObjectDataPath); + utf8 * pattern = Memory::Allocate(MAX_PATH); + String::Set(pattern, MAX_PATH, directory); + Path::Append(pattern, MAX_PATH, "*.dat"); + + // Query files + int enumFileHandle = platform_enumerate_files_begin(pattern); if (enumFileHandle != INVALID_HANDLE) { file_info enumFileInfo; @@ -201,9 +214,31 @@ private: (uint32)(enumFileInfo.last_modified >> 32) ^ (uint32)(enumFileInfo.last_modified & 0xFFFFFFFF); result->FileDateModifiedChecksum = ror32(result->FileDateModifiedChecksum, 5); + result->PathChecksum += GetPathChecksum(directory, enumFileInfo.path); } platform_enumerate_files_end(enumFileHandle); } + + Memory::Free(pattern); + + // Query sub-directories + int enumDirectoryHandle = platform_enumerate_directories_begin(directory); + if (enumDirectoryHandle != INVALID_HANDLE) + { + utf8 * directoryAbs = Memory::Allocate(MAX_PATH); + utf8 * directoryRel = Memory::Allocate(MAX_PATH); + + while (platform_enumerate_directories_next(enumDirectoryHandle, directoryRel)) + { + String::Set(directoryAbs, MAX_PATH, directory); + Path::Append(directoryAbs, MAX_PATH, directoryRel); + QueryDirectory(result, directoryAbs); + } + platform_enumerate_directories_end(enumDirectoryHandle); + + Memory::Free(directoryRel); + Memory::Free(directoryAbs); + } } void Construct() @@ -216,26 +251,64 @@ private: auto stopwatch = Stopwatch(); stopwatch.Start(); - int enumFileHandle = platform_enumerate_files_begin(gRCT2AddressObjectDataPath); - if (enumFileHandle != INVALID_HANDLE) - { - file_info enumFileInfo; - while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) - { - utf8 objectPath[MAX_PATH]; - String::Set(objectPath, sizeof(objectPath), objectDirectory); - Path::Append(objectPath, sizeof(objectPath), enumFileInfo.path); - - ScanObject(objectPath); - } - platform_enumerate_files_end(enumFileHandle); - } + utf8 path[MAX_PATH]; + GetRCT2ObjectPath(path, sizeof(path)); + ScanDirectory(path); + GetUserObjectPath(path, sizeof(path)); + ScanDirectory(path); stopwatch.Stop(); Console::WriteLine("Scanning complete in %.2f seconds.", stopwatch.GetElapsedMilliseconds() / 1000.0f); } - void ScanObject(utf8 * path) + void ScanDirectory(const utf8 * directory) + { + // Enumerate through each object in the directory + utf8 * pattern = Memory::Allocate(MAX_PATH); + String::Set(pattern, MAX_PATH, directory); + Path::Append(pattern, MAX_PATH, "*.dat"); + + // Query files + int enumFileHandle = platform_enumerate_files_begin(pattern); + if (enumFileHandle != INVALID_HANDLE) + { + utf8 * pathAbs = Memory::Allocate(MAX_PATH); + + file_info enumFileInfo; + while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) + { + String::Set(pathAbs, MAX_PATH, directory); + Path::Append(pathAbs, MAX_PATH, enumFileInfo.path); + ScanObject(pathAbs); + } + platform_enumerate_files_end(enumFileHandle); + + Memory::Free(pathAbs); + } + + Memory::Free(pattern); + + // Query sub-directories + int enumDirectoryHandle = platform_enumerate_directories_begin(directory); + if (enumDirectoryHandle != INVALID_HANDLE) + { + utf8 * directoryAbs = Memory::Allocate(MAX_PATH); + utf8 * directoryRel = Memory::Allocate(MAX_PATH); + + while (platform_enumerate_directories_next(enumDirectoryHandle, directoryRel)) + { + String::Set(directoryAbs, MAX_PATH, directory); + Path::Append(directoryAbs, MAX_PATH, directoryRel); + ScanDirectory(directoryAbs); + } + platform_enumerate_directories_end(enumDirectoryHandle); + + Memory::Free(directoryRel); + Memory::Free(directoryAbs); + } + } + + void ScanObject(const utf8 * path) { Object * object = ObjectFactory::CreateObjectFromLegacyFile(path); if (object != nullptr) @@ -245,6 +318,8 @@ private: item.Path = String::Duplicate(path); item.Name = String::Duplicate(object->GetName()); AddItem(&item); + + delete object; } } @@ -261,7 +336,8 @@ private: if (header.Version == OBJECT_REPOSITORY_VERSION && header.TotalFiles == _queryDirectoryResult.TotalFiles && header.TotalFileSize == _queryDirectoryResult.TotalFileSize && - header.FileDateModifiedChecksum == _queryDirectoryResult.FileDateModifiedChecksum) + header.FileDateModifiedChecksum == _queryDirectoryResult.FileDateModifiedChecksum && + header.PathChecksum == _queryDirectoryResult.PathChecksum) { // Header matches, so the index is not out of date for (uint32 i = 0; i < header.NumItems; i++) @@ -295,6 +371,7 @@ private: header.TotalFiles = _queryDirectoryResult.TotalFiles; header.TotalFileSize = _queryDirectoryResult.TotalFileSize; header.FileDateModifiedChecksum = _queryDirectoryResult.FileDateModifiedChecksum; + header.PathChecksum = _queryDirectoryResult.PathChecksum; header.NumItems = _items.size(); fs.WriteValue(header); @@ -310,13 +387,27 @@ private: } } - void AddItem(ObjectRepositoryItem * item) + bool AddItem(ObjectRepositoryItem * item) { - _items.push_back(*item); - size_t index = _items.size() - 1; rct_object_entry entry; Memory::Copy(&entry, &item->ObjectEntry, sizeof(rct_object_entry)); - _itemMap[entry] = index; + + const ObjectRepositoryItem * conflict = FindObject(&entry); + if (conflict == nullptr) + { + _items.push_back(*item); + size_t index = _items.size() - 1; + _itemMap[entry] = index; + return true; + } + else + { + Console::Error::WriteFormat("Object conflict: '%s'", conflict->Path); + Console::Error::WriteLine(); + Console::Error::WriteFormat(" : '%s'", item->Path); + Console::Error::WriteLine(); + return false; + } } static ObjectRepositoryItem ReadItem(IStream * stream) @@ -477,6 +568,41 @@ private: platform_get_user_directory(buffer, nullptr); strcat(buffer, "objects.idx"); } + + static void GetRCT2ObjectPath(utf8 * buffer, size_t bufferSize) + { + Path::GetDirectory(buffer, bufferSize, gRCT2AddressObjectDataPath); + } + + static void GetUserObjectPath(utf8 * buffer, size_t bufferSize) + { + platform_get_user_directory(buffer, "object"); + } + + static uint32 GetPathChecksum(const utf8 * directory, const utf8 * file) + { + uint32 hashA = 0xD8430DED; + for (const utf8 * ch = directory; *ch != '\0'; ch++) + { + hashA += (*ch); + hashA += (hashA << 10); + hashA ^= (hashA >> 6); + } + + uint32 hashB = 0xAA7F8EA9; + for (const utf8 * ch = file; *ch != '\0'; ch++) + { + hashB += (*ch); + hashB += (hashB << 10); + hashB ^= (hashB >> 6); + } + + uint32 hash = hashA ^ hashB; + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; + } }; static ObjectRepository * _objectRepository = nullptr; From cf714e9a1ad7935cc32c66bd9ee21812dd8457e6 Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 27 Jun 2016 22:23:09 +0100 Subject: [PATCH 034/116] save new objects to user directory --- src/object/ObjectRepository.cpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 1d2d150e2d..dda8b85fd9 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -541,25 +541,22 @@ private: } } - substitute_path(buffer, gRCT2AddressObjectDataPath, normalisedName); - char * lastCh = buffer + strlen(buffer); - strcat(buffer, ".DAT"); + GetUserObjectPath(buffer, bufferSize); + platform_ensure_directory_exists(buffer); + + Path::Append(buffer, bufferSize, normalisedName); + String::Append(buffer, bufferSize, ".DAT"); for (; platform_file_exists(buffer);) { - for (char * ch = lastCh - 1; ; ch--) - { - if (*ch == '\\') - { - substitute_path(buffer, gRCT2AddressObjectDataPath, "00000000.DAT"); - break; - } - if (*ch < '0') *ch = '0'; - else if (*ch == '9') *ch = 'A'; - else if (*ch == 'Z') *ch = '0'; - else (*ch)++; - if (*ch != '0') break; - } + uint32 counter = 2; + utf8 counterString[8]; + snprintf(counterString, sizeof(counterString), "-%02X", counter); + + GetUserObjectPath(buffer, bufferSize); + Path::Append(buffer, bufferSize, normalisedName); + String::Append(buffer, bufferSize, counterString); + String::Append(buffer, bufferSize, ".DAT"); } } From f0844370bbd1bbfbcee31a5d2b21c26319619b9a Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 28 Jun 2016 00:16:35 +0100 Subject: [PATCH 035/116] create new FileEnumerator class --- openrct2.vcxproj | 2 + src/core/FileEnumerator.cpp | 154 ++++++++++++++++++++++++++++++++ src/core/FileEnumerator.h | 57 ++++++++++++ src/object/ObjectRepository.cpp | 123 ++++++------------------- 4 files changed, 241 insertions(+), 95 deletions(-) create mode 100644 src/core/FileEnumerator.cpp create mode 100644 src/core/FileEnumerator.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index f0f2277fe1..fe0d037877 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -42,6 +42,7 @@ + @@ -355,6 +356,7 @@ + diff --git a/src/core/FileEnumerator.cpp b/src/core/FileEnumerator.cpp new file mode 100644 index 0000000000..a2fbc4b029 --- /dev/null +++ b/src/core/FileEnumerator.cpp @@ -0,0 +1,154 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "FileEnumerator.h" +#include "Memory.hpp" +#include "Path.hpp" +#include "String.hpp" + +extern "C" +{ + #include "../platform/platform.h" +} + +FileEnumerator::FileEnumerator(const utf8 * pattern, bool recurse) +{ + _rootPath = Memory::Allocate(MAX_PATH); + Path::GetDirectory(_rootPath, MAX_PATH, pattern); + _pattern = String::Duplicate(Path::GetFileName(pattern)); + _recurse = recurse; + + _fileInfo = Memory::Allocate(); + Memory::Set(_fileInfo, 0, sizeof(file_info)); + _path = Memory::Allocate(MAX_PATH); + + _fileHandle = INVALID_HANDLE; + + Reset(); +} + +FileEnumerator::~FileEnumerator() +{ + CloseHandles(); + Memory::Free(_path); + Memory::Free(_fileInfo); + Memory::Free(_pattern); + Memory::Free(_rootPath); +} + +void FileEnumerator::Reset() +{ + CloseHandles(); + + DirectoryState directoryState; + directoryState.Directory = String::Duplicate(_rootPath); + directoryState.Handle = INVALID_HANDLE; + _directoryStack.push(directoryState); +} + +bool FileEnumerator::Next() +{ + while (true) + { + while (_fileHandle == INVALID_HANDLE) + { + if (_directoryStack.size() == 0) + { + return false; + } + + DirectoryState directoryState = _directoryStack.top(); + if (directoryState.Handle == INVALID_HANDLE) + { + // Start enumerating files for this directory + utf8 pattern[MAX_PATH]; + String::Set(pattern, sizeof(pattern), directoryState.Directory); + Path::Append(pattern, sizeof(pattern), _pattern); + + _fileHandle = platform_enumerate_files_begin(pattern); + } + else + { + // Next directory + utf8 name[MAX_PATH]; + if (platform_enumerate_directories_next(directoryState.Handle, name)) + { + DirectoryState newDirectoryState; + newDirectoryState.Handle = INVALID_HANDLE; + newDirectoryState.Directory = Memory::Allocate(MAX_PATH); + + String::Set(newDirectoryState.Directory, MAX_PATH, directoryState.Directory); + Path::Append(newDirectoryState.Directory, MAX_PATH, name); + + _directoryStack.push(newDirectoryState); + } + else + { + platform_enumerate_directories_end(directoryState.Handle); + Memory::Free(directoryState.Directory); + _directoryStack.pop(); + } + } + } + + // Next file + if (platform_enumerate_files_next(_fileHandle, _fileInfo)) + { + String::Set(_path, MAX_PATH, _directoryStack.top().Directory); + Path::Append(_path, MAX_PATH, _fileInfo->path); + return true; + } + platform_enumerate_files_end(_fileHandle); + _fileHandle = INVALID_HANDLE; + + if (_recurse) + { + // Start enumerating sub-directories + DirectoryState * directoryState = &_directoryStack.top(); + directoryState->Handle = platform_enumerate_directories_begin(directoryState->Directory); + if (directoryState->Handle == INVALID_HANDLE) + { + Memory::Free(directoryState->Directory); + _directoryStack.pop(); + } + } + else + { + Memory::Free(_directoryStack.top().Directory); + _directoryStack.pop(); + return false; + } + } +} + +void FileEnumerator::CloseHandles() +{ + if (_fileHandle != INVALID_HANDLE) + { + platform_enumerate_files_end(_fileHandle); + _fileHandle = INVALID_HANDLE; + } + while (_directoryStack.size() > 0) + { + DirectoryState directoryState = _directoryStack.top(); + if (directoryState.Handle != INVALID_HANDLE) + { + platform_enumerate_directories_end(directoryState.Handle); + } + Memory::Free(directoryState.Directory); + _directoryStack.pop(); + } +} diff --git a/src/core/FileEnumerator.h b/src/core/FileEnumerator.h new file mode 100644 index 0000000000..d39b237c14 --- /dev/null +++ b/src/core/FileEnumerator.h @@ -0,0 +1,57 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include +#include "../common.h" + +struct file_info; +class FileEnumerator +{ +private: + struct DirectoryState + { + utf8 * Directory; + int Handle; + }; + + // Enumeration options + utf8 * _rootPath; + utf8 * _pattern; + bool _recurse; + + // Enumeration state + int _fileHandle; + std::stack _directoryStack; + + // Current enumeration + file_info * _fileInfo; + utf8 * _path; + +public: + FileEnumerator(const utf8 * pattern, bool recurse); + ~FileEnumerator(); + + const file_info * GetFileInfo() const { return _fileInfo; } + const utf8 * GetPath() const { return _path; } + + void Reset(); + bool Next(); + +private: + void CloseHandles(); +}; diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index dda8b85fd9..be084925f9 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -19,6 +19,7 @@ #include "../common.h" #include "../core/Console.hpp" +#include "../core/FileEnumerator.h" #include "../core/FileStream.hpp" #include "../core/Guard.hpp" #include "../core/IStream.hpp" @@ -196,48 +197,23 @@ private: void QueryDirectory(QueryDirectoryResult * result, const utf8 * directory) { - // Enumerate through each object in the directory - utf8 * pattern = Memory::Allocate(MAX_PATH); - String::Set(pattern, MAX_PATH, directory); - Path::Append(pattern, MAX_PATH, "*.dat"); + utf8 pattern[MAX_PATH]; + String::Set(pattern, sizeof(pattern), directory); + Path::Append(pattern, sizeof(pattern), "*.dat"); - // Query files - int enumFileHandle = platform_enumerate_files_begin(pattern); - if (enumFileHandle != INVALID_HANDLE) + auto fileEnumerator = FileEnumerator(pattern, true); + while (fileEnumerator.Next()) { - file_info enumFileInfo; - while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) - { - result->TotalFiles++; - result->TotalFileSize += enumFileInfo.size; - result->FileDateModifiedChecksum ^= - (uint32)(enumFileInfo.last_modified >> 32) ^ - (uint32)(enumFileInfo.last_modified & 0xFFFFFFFF); - result->FileDateModifiedChecksum = ror32(result->FileDateModifiedChecksum, 5); - result->PathChecksum += GetPathChecksum(directory, enumFileInfo.path); - } - platform_enumerate_files_end(enumFileHandle); - } + const file_info * enumFileInfo = fileEnumerator.GetFileInfo(); + const utf8 * enumPath = fileEnumerator.GetPath(); - Memory::Free(pattern); - - // Query sub-directories - int enumDirectoryHandle = platform_enumerate_directories_begin(directory); - if (enumDirectoryHandle != INVALID_HANDLE) - { - utf8 * directoryAbs = Memory::Allocate(MAX_PATH); - utf8 * directoryRel = Memory::Allocate(MAX_PATH); - - while (platform_enumerate_directories_next(enumDirectoryHandle, directoryRel)) - { - String::Set(directoryAbs, MAX_PATH, directory); - Path::Append(directoryAbs, MAX_PATH, directoryRel); - QueryDirectory(result, directoryAbs); - } - platform_enumerate_directories_end(enumDirectoryHandle); - - Memory::Free(directoryRel); - Memory::Free(directoryAbs); + result->TotalFiles++; + result->TotalFileSize += enumFileInfo->size; + result->FileDateModifiedChecksum ^= + (uint32)(enumFileInfo->last_modified >> 32) ^ + (uint32)(enumFileInfo->last_modified & 0xFFFFFFFF); + result->FileDateModifiedChecksum = ror32(result->FileDateModifiedChecksum, 5); + result->PathChecksum += GetPathChecksum(enumPath); } } @@ -263,48 +239,15 @@ private: void ScanDirectory(const utf8 * directory) { - // Enumerate through each object in the directory - utf8 * pattern = Memory::Allocate(MAX_PATH); - String::Set(pattern, MAX_PATH, directory); - Path::Append(pattern, MAX_PATH, "*.dat"); + utf8 pattern[MAX_PATH]; + String::Set(pattern, sizeof(pattern), directory); + Path::Append(pattern, sizeof(pattern), "*.dat"); - // Query files - int enumFileHandle = platform_enumerate_files_begin(pattern); - if (enumFileHandle != INVALID_HANDLE) + auto fileEnumerator = FileEnumerator(pattern, true); + while (fileEnumerator.Next()) { - utf8 * pathAbs = Memory::Allocate(MAX_PATH); - - file_info enumFileInfo; - while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) - { - String::Set(pathAbs, MAX_PATH, directory); - Path::Append(pathAbs, MAX_PATH, enumFileInfo.path); - ScanObject(pathAbs); - } - platform_enumerate_files_end(enumFileHandle); - - Memory::Free(pathAbs); - } - - Memory::Free(pattern); - - // Query sub-directories - int enumDirectoryHandle = platform_enumerate_directories_begin(directory); - if (enumDirectoryHandle != INVALID_HANDLE) - { - utf8 * directoryAbs = Memory::Allocate(MAX_PATH); - utf8 * directoryRel = Memory::Allocate(MAX_PATH); - - while (platform_enumerate_directories_next(enumDirectoryHandle, directoryRel)) - { - String::Set(directoryAbs, MAX_PATH, directory); - Path::Append(directoryAbs, MAX_PATH, directoryRel); - ScanDirectory(directoryAbs); - } - platform_enumerate_directories_end(enumDirectoryHandle); - - Memory::Free(directoryRel); - Memory::Free(directoryAbs); + const utf8 * enumPath = fileEnumerator.GetPath(); + ScanObject(enumPath); } } @@ -576,25 +519,15 @@ private: platform_get_user_directory(buffer, "object"); } - static uint32 GetPathChecksum(const utf8 * directory, const utf8 * file) + static uint32 GetPathChecksum(const utf8 * path) { - uint32 hashA = 0xD8430DED; - for (const utf8 * ch = directory; *ch != '\0'; ch++) + uint32 hash = 0xD8430DED; + for (const utf8 * ch = path; *ch != '\0'; ch++) { - hashA += (*ch); - hashA += (hashA << 10); - hashA ^= (hashA >> 6); + hash += (*ch); + hash += (hash << 10); + hash ^= (hash >> 6); } - - uint32 hashB = 0xAA7F8EA9; - for (const utf8 * ch = file; *ch != '\0'; ch++) - { - hashB += (*ch); - hashB += (hashB << 10); - hashB ^= (hashB >> 6); - } - - uint32 hash = hashA ^ hashB; hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); From 1b4079536d15df78c592e0a491104fa0e7ed17b5 Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 28 Jun 2016 21:16:09 +0100 Subject: [PATCH 036/116] try to read objects with bad image tables --- src/core/FileStream.hpp | 19 ++++++++++++++++--- src/core/IStream.hpp | 2 ++ src/core/MemoryStream.cpp | 8 ++++++++ src/core/MemoryStream.h | 2 ++ src/object/ImageTable.cpp | 14 +++++++++++++- 5 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/core/FileStream.hpp b/src/core/FileStream.hpp index 9a0bca777d..4716222a79 100644 --- a/src/core/FileStream.hpp +++ b/src/core/FileStream.hpp @@ -37,6 +37,7 @@ private: bool _canRead; bool _canWrite; bool _disposed; + uint64 _fileSize; public: FileStream(const utf8 * path, int fileMode) @@ -64,6 +65,7 @@ public: } _disposed = false; + _fileSize = SDL_RWsize(_file); } ~FileStream() @@ -78,7 +80,7 @@ public: bool CanRead() const override { return _canRead; } bool CanWrite() const override { return _canWrite; } - uint64 GetLength() const override { return SDL_RWsize(_file); } + uint64 GetLength() const override { return _fileSize; } uint64 GetPosition() const override { return SDL_RWtell(_file); } void SetPosition(uint64 position) override @@ -103,10 +105,15 @@ public: void Read(void * buffer, uint64 length) override { - if (SDL_RWread(_file, buffer, (size_t)length, 1) != 1) + uint64 remainingBytes = GetLength() - GetPosition(); + if (length <= remainingBytes) { - throw IOException("Attempted to read past end of file."); + if (SDL_RWread(_file, buffer, (size_t)length, 1) == 1) + { + return; + } } + throw IOException("Attempted to read past end of file."); } void Write(const void * buffer, uint64 length) override @@ -116,4 +123,10 @@ public: throw IOException("Unable to write to file."); } } + + uint64 TryRead(void * buffer, uint64 length) override + { + size_t readBytes = SDL_RWread(_file, buffer, 1, (size_t)length); + return readBytes; + } }; diff --git a/src/core/IStream.hpp b/src/core/IStream.hpp index 697cadfe75..4bf2e3e878 100644 --- a/src/core/IStream.hpp +++ b/src/core/IStream.hpp @@ -47,6 +47,8 @@ interface IStream virtual void Read(void * buffer, uint64 length) abstract; virtual void Write(const void * buffer, uint64 length) abstract; + virtual uint64 TryRead(void * buffer, uint64 length) abstract; + /////////////////////////////////////////////////////////////////////////// // Helper methods /////////////////////////////////////////////////////////////////////////// diff --git a/src/core/MemoryStream.cpp b/src/core/MemoryStream.cpp index cf3855938b..35364fab0f 100644 --- a/src/core/MemoryStream.cpp +++ b/src/core/MemoryStream.cpp @@ -149,6 +149,14 @@ void MemoryStream::Read(void * buffer, uint64 length) _position = (void*)((uintptr_t)_position + length); } +uint64 MemoryStream::TryRead(void * buffer, uint64 length) +{ + uint64 remainingBytes = GetLength() - GetPosition(); + uint64 bytesToRead = Math::Min(length, remainingBytes); + Read(buffer, bytesToRead); + return bytesToRead; +} + void MemoryStream::Write(const void * buffer, uint64 length) { uint64 position = GetPosition(); diff --git a/src/core/MemoryStream.h b/src/core/MemoryStream.h index c7a2a0763b..82a2fcfe5e 100644 --- a/src/core/MemoryStream.h +++ b/src/core/MemoryStream.h @@ -63,6 +63,8 @@ public: void Read(void * buffer, uint64 length) override; void Write(const void * buffer, uint64 length) override; + uint64 TryRead(void * buffer, uint64 length) override; + private: void EnsureCapacity(size_t capacity); }; diff --git a/src/object/ImageTable.cpp b/src/object/ImageTable.cpp index ebd877dbd7..1b4ec16fa8 100644 --- a/src/object/ImageTable.cpp +++ b/src/object/ImageTable.cpp @@ -14,6 +14,7 @@ *****************************************************************************/ #pragma endregion +#include "../core/Console.hpp" #include "../core/IStream.hpp" #include "../core/Memory.hpp" #include "ImageTable.h" @@ -53,5 +54,16 @@ void ImageTable::Read(IStream * stream) } // Read g1 element data - stream->Read(_data, _dataSize); + size_t readBytes = (size_t)stream->TryRead(_data, _dataSize); + + // If data is shorter than expected (some custom objects are unfortunately like that) + size_t unreadBytes = _dataSize - readBytes; + if (unreadBytes > 0) + { + void * ptr = (void*)(((uintptr_t)_data) + readBytes); + Memory::Set(ptr, 0, unreadBytes); + + Console::Error::WriteFormat("Warning: Image table size shorter than expected."); + Console::Error::WriteLine(); + } } From 202b754d8d0747648c27a1f922c96539f977932e Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 28 Jun 2016 21:44:39 +0100 Subject: [PATCH 037/116] fix ride type to ride entry map --- src/object/ObjectRepository.cpp | 4 ++-- src/rct2/S6Exporter.cpp | 2 +- src/ride/ride.c | 36 +++++++++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index be084925f9..46b1b849e7 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -622,8 +622,6 @@ extern "C" void reset_loaded_objects() { - reset_type_to_ride_entry_index_map(); - gTotalNoImages = 0xF26E; for (int i = 0; i < 721; i++) @@ -634,6 +632,8 @@ extern "C" object->Load(); } } + + reset_type_to_ride_entry_index_map(); } void object_unload_all() diff --git a/src/rct2/S6Exporter.cpp b/src/rct2/S6Exporter.cpp index 3bbc8cfd92..e83d988234 100644 --- a/src/rct2/S6Exporter.cpp +++ b/src/rct2/S6Exporter.cpp @@ -508,7 +508,7 @@ extern "C" } delete s6exporter; - reset_loaded_objects(); + // reset_loaded_objects(); gfx_invalidate_screen(); if (result && !(flags & S6_SAVE_FLAG_AUTOMATIC)) diff --git a/src/ride/ride.c b/src/ride/ride.c index f77c559b06..3f4cead7f8 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -250,8 +250,40 @@ rct_ride_entry *get_ride_entry_by_ride(rct_ride *ride) * * rct2: 0x006DED68 */ -void reset_type_to_ride_entry_index_map(){ - memset(gTypeToRideEntryIndexMap, 0xFF, 91); +void reset_type_to_ride_entry_index_map() +{ + uint8 maxRideEntries = 128; + uint8 maxRideTypes = 91; + size_t stride = maxRideEntries + 1; + uint8 * entryTypeTable = malloc(maxRideTypes * stride); + memset(entryTypeTable, 0xFF, maxRideTypes * stride); + + for (uint8 i = 0; i < maxRideEntries; i++) { + rct_ride_entry * rideEntry = get_ride_entry(i); + if (rideEntry == (rct_ride_entry *)-1) { + continue; + } + for (uint8 j = 0; j < 3; j++) { + uint8 rideType = rideEntry->ride_type[j]; + if (rideType < maxRideTypes) { + uint8 * entryArray = &entryTypeTable[rideType * stride]; + uint8 * nextEntry = memchr(entryArray, 0xFF, stride); + *nextEntry = i; + } + } + } + + uint8 * dst = gTypeToRideEntryIndexMap; + for (uint8 i = 0; i < maxRideTypes; i++) { + uint8 * entryArray = &entryTypeTable[i * stride]; + uint8 * entry = entryArray; + while (*entry != 0xFF) { + *dst++ = *entry++; + } + *dst++ = 0xFF; + } + + free(entryTypeTable); } uint8 *get_ride_entry_indices_for_ride_type(uint8 rideType) From 33d0bebad9ab1b6f1790519ccdc6e09e2524628c Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 28 Jun 2016 22:30:00 +0100 Subject: [PATCH 038/116] fix file / directory enumeration --- src/core/FileEnumerator.cpp | 16 ++++++++++------ src/platform/windows.c | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/core/FileEnumerator.cpp b/src/core/FileEnumerator.cpp index a2fbc4b029..c934d779c3 100644 --- a/src/core/FileEnumerator.cpp +++ b/src/core/FileEnumerator.cpp @@ -79,6 +79,7 @@ bool FileEnumerator::Next() Path::Append(pattern, sizeof(pattern), _pattern); _fileHandle = platform_enumerate_files_begin(pattern); + break; } else { @@ -105,14 +106,17 @@ bool FileEnumerator::Next() } // Next file - if (platform_enumerate_files_next(_fileHandle, _fileInfo)) + if (_fileHandle != INVALID_HANDLE) { - String::Set(_path, MAX_PATH, _directoryStack.top().Directory); - Path::Append(_path, MAX_PATH, _fileInfo->path); - return true; + if (platform_enumerate_files_next(_fileHandle, _fileInfo)) + { + String::Set(_path, MAX_PATH, _directoryStack.top().Directory); + Path::Append(_path, MAX_PATH, _fileInfo->path); + return true; + } + platform_enumerate_files_end(_fileHandle); + _fileHandle = INVALID_HANDLE; } - platform_enumerate_files_end(_fileHandle); - _fileHandle = INVALID_HANDLE; if (_recurse) { diff --git a/src/platform/windows.c b/src/platform/windows.c index 262ee21903..f329066b81 100644 --- a/src/platform/windows.c +++ b/src/platform/windows.c @@ -417,7 +417,7 @@ bool platform_enumerate_directories_next(int handle, utf8 *path) if (enumFileInfo->handle == NULL) { fileHandle = FindFirstFileW(enumFileInfo->pattern, &enumFileInfo->data); - if (fileHandle != 0) { + if (fileHandle != INVALID_HANDLE_VALUE) { enumFileInfo->handle = fileHandle; } else { return false; From 6c7bc9b158f61e5c6871721a9d5eccaf2c22ec52 Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 28 Jun 2016 23:24:49 +0100 Subject: [PATCH 039/116] add methods to get object repo items --- src/object/ObjectRepository.cpp | 26 ++++++++++++++++++++++++-- src/object/ObjectRepository.h | 26 +++++++++++++++++++++----- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 46b1b849e7..52fb222d5f 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -116,7 +116,17 @@ public: } } - const ObjectRepositoryItem * FindObject(const utf8 * name) override + const size_t GetNumObjects() const override + { + return _items.size(); + } + + const ObjectRepositoryItem * GetObjects() const override + { + return _items.data(); + } + + const ObjectRepositoryItem * FindObject(const utf8 * name) const override { rct_object_entry entry = { 0 }; utf8 entryName[9] = { ' ' }; @@ -131,7 +141,7 @@ public: return nullptr; } - const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) override + const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) const override { auto kvp = _itemMap.find(*objectEntry); if (kvp != _itemMap.end()) @@ -730,4 +740,16 @@ extern "C" } return 1; } + + size_t object_repository_get_items_count() + { + IObjectRepository * objectRepository = GetObjectRepository(); + return objectRepository->GetNumObjects(); + } + + const ObjectRepositoryItem * object_repository_get_items() + { + IObjectRepository * objectRepository = GetObjectRepository(); + return objectRepository->GetObjects(); + } } diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 2d766fff21..ded9a2a9a8 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -18,12 +18,16 @@ #include "../common.h" +#ifdef __cplusplus extern "C" { +#endif #include "../object.h" +#ifdef __cplusplus } +#endif -struct ObjectRepositoryItem +typedef struct ObjectRepositoryItem { rct_object_entry_extended ObjectEntry; utf8 * Path; @@ -46,14 +50,19 @@ struct ObjectRepositoryItem uint8 RideType[3]; }; }; -}; +} ObjectRepositoryItem; + +#ifdef __cplusplus interface IObjectRepository { virtual ~IObjectRepository() { } - - virtual const ObjectRepositoryItem * FindObject(const utf8 * name) abstract; - virtual const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) abstract; + + virtual const size_t GetNumObjects() const abstract; + virtual const ObjectRepositoryItem * GetObjects() const abstract; + virtual const ObjectRepositoryItem * FindObject(const utf8 * name) const abstract; + virtual const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) const abstract; + virtual Object * LoadObject(const rct_object_entry * objectEntry) abstract; virtual void AddObject(const rct_object_entry * objectEntry, const void * data, @@ -61,3 +70,10 @@ interface IObjectRepository }; IObjectRepository * GetObjectRepository(); + +#else + +size_t object_repository_get_items_count(); +const ObjectRepositoryItem * object_repository_get_items(); + +#endif From 995bbffb8419de47edc52efb82d13b4d899eaacc Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 29 Jun 2016 18:47:15 +0100 Subject: [PATCH 040/116] trim string entries --- src/core/String.cpp | 43 ++++++++++++++++++++++++++++++++++++++ src/core/String.hpp | 2 ++ src/object/StringTable.cpp | 9 ++++++-- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/core/String.cpp b/src/core/String.cpp index 3a2a6df7f4..edc22e9b3b 100644 --- a/src/core/String.cpp +++ b/src/core/String.cpp @@ -14,6 +14,8 @@ *****************************************************************************/ #pragma endregion +#include + extern "C" { #include "../localisation/localisation.h" @@ -218,4 +220,45 @@ namespace String { return utf8_write_codepoint(dst, codepoint); } + + utf8 * Trim(utf8 * str) + { + utf8 * firstNonWhitespace = nullptr; + utf8 * lastNonWhitespace = nullptr; + + codepoint_t codepoint; + utf8 * ch = str; + utf8 * nextCh; + while ((codepoint = GetNextCodepoint(ch, &nextCh)) != '\0') + { + if (codepoint <= WCHAR_MAX && !iswspace((wchar_t)codepoint)) + { + if (firstNonWhitespace == nullptr) + { + firstNonWhitespace = ch; + } + lastNonWhitespace = ch; + } + ch = nextCh; + } + + if (firstNonWhitespace != nullptr && + firstNonWhitespace != str) + { + size_t newStringSize = ch - firstNonWhitespace; +#if DEBUG + size_t currentStringSize = String::SizeOf(str); + assert(newStringSize < currentStringSize); +#endif + + Memory::Copy(str, firstNonWhitespace, newStringSize); + str[newStringSize] = '\0'; + } + else + { + *ch = '\0'; + } + + return str; + } } diff --git a/src/core/String.hpp b/src/core/String.hpp index ce734bc818..5a140dc1d2 100644 --- a/src/core/String.hpp +++ b/src/core/String.hpp @@ -64,4 +64,6 @@ namespace String codepoint_t GetNextCodepoint(utf8 * ptr, utf8 * * nextPtr = nullptr); codepoint_t GetNextCodepoint(const utf8 * ptr, const utf8 * * nextPtr = nullptr); utf8 * WriteCodepoint(utf8 * dst, codepoint_t codepoint); + + utf8 * Trim(utf8 * str); } diff --git a/src/object/StringTable.cpp b/src/object/StringTable.cpp index 4939aefb21..b5c46e36f9 100644 --- a/src/object/StringTable.cpp +++ b/src/object/StringTable.cpp @@ -52,13 +52,18 @@ void StringTable::Read(IStream * stream, uint8 id) StringTableEntry entry; entry.Id = id; entry.LanguageId = languageId; - entry.Text = stream->ReadString(); - if (StringIsBlank(entry.Text)) + char * win1252 = stream->ReadString(); + if (StringIsBlank(win1252)) { entry.LanguageId = RCT2_LANGUAGE_ID_BLANK; } + entry.Text = win1252_to_utf8_alloc(win1252); + Memory::Free(win1252); + + String::Trim(entry.Text); + _strings.push_back(entry); } Sort(); From 840179299c748ab7fee913d7a0c5fb80e353eb0f Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 29 Jun 2016 21:34:59 +0100 Subject: [PATCH 041/116] scrap object exetended and add sort ability Not yet sure if we need to sort object repository, but add code for it anyway. --- src/object.h | 13 +++++++---- src/object/ObjectRepository.cpp | 41 +++++++++++++++++++++++---------- src/object/ObjectRepository.h | 18 +++++++-------- 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/object.h b/src/object.h index 8f71595450..9319408c0a 100644 --- a/src/object.h +++ b/src/object.h @@ -67,10 +67,15 @@ assert_struct_size(rct_object_entry, 0x10); * size: 0x14 */ typedef struct rct_object_entry_extended { - uint32 flags; - char name[8]; - uint32 checksum; - uint32 chunk_size; + union { + rct_object_entry entry; + struct { + uint32 flags; + char name[8]; + uint32 checksum; + uint32 chunk_size; + }; + }; } rct_object_entry_extended; assert_struct_size(rct_object_entry_extended, 0x14); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 52fb222d5f..ec175fccfc 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -14,6 +14,7 @@ *****************************************************************************/ #pragma endregion +#include #include #include @@ -114,6 +115,8 @@ public: Construct(); Save(); } + + // SortItems(); } const size_t GetNumObjects() const override @@ -267,7 +270,7 @@ private: if (object != nullptr) { ObjectRepositoryItem item = { 0 }; - Memory::Copy(&item.ObjectEntry, object->GetObjectEntry(), sizeof(rct_object_entry)); + item.ObjectEntry = *object->GetObjectEntry(); item.Path = String::Duplicate(path); item.Name = String::Duplicate(object->GetName()); AddItem(&item); @@ -340,17 +343,31 @@ private: } } + void SortItems() + { + std::sort(_items.begin(), _items.end(), [](const ObjectRepositoryItem &a, + const ObjectRepositoryItem &b) -> bool + { + return strcmp(a.Name, b.Name) < 0; + }); + + // Rebuild item map + _itemMap.clear(); + for (size_t i = 0; i < _items.size(); i++) + { + rct_object_entry entry = _items[i].ObjectEntry; + _itemMap[entry] = i; + } + } + bool AddItem(ObjectRepositoryItem * item) { - rct_object_entry entry; - Memory::Copy(&entry, &item->ObjectEntry, sizeof(rct_object_entry)); - - const ObjectRepositoryItem * conflict = FindObject(&entry); + const ObjectRepositoryItem * conflict = FindObject(&item->ObjectEntry); if (conflict == nullptr) { _items.push_back(*item); size_t index = _items.size() - 1; - _itemMap[entry] = index; + _itemMap[item->ObjectEntry] = index; return true; } else @@ -367,17 +384,17 @@ private: { ObjectRepositoryItem item = { 0 }; - item.ObjectEntry = stream->ReadValue(); + item.ObjectEntry = stream->ReadValue(); item.Path = stream->ReadString(); item.NumImages = stream->ReadValue(); item.Name = stream->ReadString(); item.ChunkSize = stream->ReadValue(); item.NumRequiredObjects = stream->ReadValue(); - item.RequiredObjects = Memory::AllocateArray(item.NumRequiredObjects); + item.RequiredObjects = Memory::AllocateArray(item.NumRequiredObjects); for (uint16 i = 0; i < item.NumRequiredObjects; i++) { - item.RequiredObjects[i] = stream->ReadValue(); + item.RequiredObjects[i] = stream->ReadValue(); } switch (item.ObjectEntry.flags & 0x0F) { @@ -394,10 +411,10 @@ private: break; case OBJECT_TYPE_SCENERY_SETS: item.NumThemeObjects = stream->ReadValue(); - item.ThemeObjects = Memory::AllocateArray(item.NumThemeObjects); + item.ThemeObjects = Memory::AllocateArray(item.NumThemeObjects); for (uint16 i = 0; i < item.NumThemeObjects; i++) { - item.ThemeObjects[i] = stream->ReadValue(); + item.ThemeObjects[i] = stream->ReadValue(); } break; } @@ -434,7 +451,7 @@ private: stream->WriteValue(item.NumThemeObjects); for (uint16 i = 0; i < item.NumThemeObjects; i++) { - stream->WriteValue(item.ThemeObjects[i]); + stream->WriteValue(item.ThemeObjects[i]); } break; } diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index ded9a2a9a8..6e9e414944 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -29,19 +29,19 @@ extern "C" typedef struct ObjectRepositoryItem { - rct_object_entry_extended ObjectEntry; - utf8 * Path; - uint32 NumImages; - utf8 * Name; - size_t ChunkSize; - uint16 NumRequiredObjects; - rct_object_entry_extended * RequiredObjects; + rct_object_entry ObjectEntry; + utf8 * Path; + uint32 NumImages; + utf8 * Name; + size_t ChunkSize; + uint16 NumRequiredObjects; + rct_object_entry * RequiredObjects; union { struct { - uint16 NumThemeObjects; - rct_object_entry_extended * ThemeObjects; + uint16 NumThemeObjects; + rct_object_entry * ThemeObjects; }; struct { From db304cdfcbb9382964ba3a8914f3711fc6e3227c Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 29 Jun 2016 22:15:38 +0100 Subject: [PATCH 042/116] fix filtering on object selection --- src/object/Object.h | 3 + src/object/ObjectRepository.cpp | 1 + src/object/ObjectRepository.h | 2 + src/object/RideObject.cpp | 30 +++++--- src/object/RideObject.h | 2 + src/rct1.c | 2 +- src/rct1.h | 2 +- src/windows/editor_object_selection.c | 103 +++++++++++++------------- 8 files changed, 84 insertions(+), 61 deletions(-) diff --git a/src/object/Object.h b/src/object/Object.h index 22cae75a4c..690660bbb6 100644 --- a/src/object/Object.h +++ b/src/object/Object.h @@ -26,6 +26,7 @@ extern "C" } interface IStream; +struct ObjectRepositoryItem; class Object { @@ -52,4 +53,6 @@ public: virtual uint8 GetObjectType() { return _objectEntry.flags & 0x0F; } virtual const utf8 * GetName() abstract; + + virtual void SetRepositoryItem(ObjectRepositoryItem * item) const { } }; diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index ec175fccfc..2e9f360351 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -273,6 +273,7 @@ private: item.ObjectEntry = *object->GetObjectEntry(); item.Path = String::Duplicate(path); item.Name = String::Duplicate(object->GetName()); + object->SetRepositoryItem(&item); AddItem(&item); delete object; diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 6e9e414944..cfc59dcdb1 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -54,6 +54,8 @@ typedef struct ObjectRepositoryItem #ifdef __cplusplus +class Object; + interface IObjectRepository { virtual ~IObjectRepository() { } diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index 6b094cda8d..fd0369a60d 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -17,6 +17,7 @@ #include "../core/IStream.hpp" #include "../core/Memory.hpp" #include "../core/Util.hpp" +#include "ObjectRepository.h" #include "RideObject.h" extern "C" @@ -317,15 +318,6 @@ void RideObject::Load() } } } - - // TODO sort out this filter stuff - int di = _legacyType.ride_type[0] | (_legacyType.ride_type[1] << 8) | (_legacyType.ride_type[2] << 16); - if ((_legacyType.flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) && - !rideTypeShouldLoseSeparateFlag(&_legacyType)) - { - di |= 0x1000000; - } - RCT2_GLOBAL(0xF433DD, uint32) = di; } void RideObject::Unload() @@ -352,3 +344,23 @@ const utf8 * RideObject::GetCapacity() const utf8 * capacity = GetStringTable()->GetString(OBJ_STRING_ID_CAPACITY); return capacity != nullptr ? capacity : ""; } + +void RideObject::SetRepositoryItem(ObjectRepositoryItem * item) const +{ + for (int i = 0; i < 3; i++) + { + item->RideType[i] = _legacyType.ride_type[i]; + } + for (int i = 0; i < 2; i++) + { + item->RideCategory[i] = _legacyType.category[i]; + } + + uint8 flags = 0; + if ((_legacyType.flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) && + !rideTypeShouldLoseSeparateFlag(&_legacyType)) + { + flags |= 0x1000000; + } + item->RideFlags = flags; +} diff --git a/src/object/RideObject.h b/src/object/RideObject.h index 8e286e9a8a..75ed233556 100644 --- a/src/object/RideObject.h +++ b/src/object/RideObject.h @@ -44,6 +44,8 @@ public: const utf8 * GetDescription(); const utf8 * GetCapacity(); + void SetRepositoryItem(ObjectRepositoryItem * item) const; + private: }; diff --git a/src/rct1.c b/src/rct1.c index 04c2356359..cab41bb427 100644 --- a/src/rct1.c +++ b/src/rct1.c @@ -78,7 +78,7 @@ bool rct1_read_sv4(const char *path, rct1_s4 *s4) return success; } -bool rideTypeShouldLoseSeparateFlag(rct_ride_entry *rideEntry) +bool rideTypeShouldLoseSeparateFlag(const rct_ride_entry *rideEntry) { if (!gConfigInterface.select_by_track_type) { return false; diff --git a/src/rct1.h b/src/rct1.h index 4ae06a295e..8c07cdc058 100644 --- a/src/rct1.h +++ b/src/rct1.h @@ -745,7 +745,7 @@ bool rct1_read_sv4(const char *path, rct1_s4 *s4); void rct1_import_s4(rct1_s4 *s4); void rct1_fix_landscape(); int vehicle_preference_compare(uint8 rideType, const char * a, const char * b); -bool rideTypeShouldLoseSeparateFlag(rct_ride_entry *rideEntry); +bool rideTypeShouldLoseSeparateFlag(const rct_ride_entry *rideEntry); bool rct1_load_saved_game(const char *path); bool rct1_load_scenario(const char *path); diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 36b9a6dd4a..d16581242b 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -27,6 +27,7 @@ #include "../management/research.h" #include "../object.h" #include "../object_list.h" +#include "../object/ObjectRepository.h" #include "../rct1.h" #include "../ride/ride.h" #include "../ride/ride_data.h" @@ -224,9 +225,9 @@ static int get_object_from_object_selection(uint8 object_type, int y, uint8 *obj static void window_editor_object_selection_manage_tracks(); static void editor_load_selected_objects(); static bool filter_selected(uint8* objectFlags); -static bool filter_string(rct_object_entry *entry, rct_object_filters *filter); -static bool filter_source(rct_object_entry *entry); -static bool filter_chunks(rct_object_entry *entry, rct_object_filters *filter); +static bool filter_string(const ObjectRepositoryItem * item); +static bool filter_source(const ObjectRepositoryItem * item); +static bool filter_chunks(const ObjectRepositoryItem * item); static void filter_update_counts(); void reset_selected_object_count_and_size(); @@ -282,6 +283,7 @@ enum { }; typedef struct list_item { + const ObjectRepositoryItem * repositoryItem; rct_object_entry *entry; rct_object_filters *filter; uint8 *flags; @@ -305,8 +307,8 @@ static int visible_list_sort_ride_name(const void *rawA, const void *rawB) list_item *a = (list_item*)rawA; list_item *b = (list_item*)rawB; - const char *nameA = object_get_name(a->entry); - const char *nameB = object_get_name(b->entry); + const char *nameA = a->repositoryItem->Name; + const char *nameB = b->repositoryItem->Name; return strcmp(nameA, nameB); } @@ -315,8 +317,8 @@ static int visible_list_sort_ride_type(const void *rawA, const void *rawB) list_item *a = (list_item*)rawA; list_item *b = (list_item*)rawB; - const char *rideTypeA = language_get_string(2 + a->filter->ride.ride_type); - const char *rideTypeB = language_get_string(2 + b->filter->ride.ride_type); + const char *rideTypeA = language_get_string(2 + a->repositoryItem->RideType[0]); + const char *rideTypeB = language_get_string(2 + b->repositoryItem->RideType[0]); int result = strcmp(rideTypeA, rideTypeB); if (result != 0) return result; @@ -326,31 +328,32 @@ static int visible_list_sort_ride_type(const void *rawA, const void *rawB) static void visible_list_refresh(rct_window *w) { - int numObjects = gInstalledObjectsCount; + int numObjects = (int)object_repository_get_items_count(); visible_list_dispose(); _listItems = malloc(numObjects * sizeof(list_item)); _numListItems = 0; list_item *currentListItem = &_listItems[0]; - rct_object_entry *entry = gInstalledObjects; + const ObjectRepositoryItem *items = object_repository_get_items(); uint8 *itemFlags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); for (int i = 0; i < numObjects; i++) { - rct_object_filters *filter = get_object_filter(i); - int type = entry->flags & 0x0F; - if (type == w->selected_tab && !(*itemFlags & OBJECT_SELECTION_FLAG_6) - && filter_source(entry) - && filter_string(entry, filter) - && filter_chunks(entry, filter) - && filter_selected(itemFlags)) { - currentListItem->entry = entry; - currentListItem->filter = filter; - currentListItem->flags = itemFlags; - currentListItem++; - _numListItems++; + const ObjectRepositoryItem * item = &items[i]; + uint8 objectType = item->ObjectEntry.flags & 0x0F; + if (objectType == w->selected_tab && !(*itemFlags & OBJECT_SELECTION_FLAG_6) && + filter_source(item) && + filter_string(item) && + filter_chunks(item) && + filter_selected(itemFlags) + ) { + rct_object_filters * filter = calloc(1, sizeof(rct_object_filters)); + currentListItem->repositoryItem = item; + currentListItem->entry = (rct_object_entry *)&item->ObjectEntry; + currentListItem->filter = filter; + currentListItem->flags = itemFlags; + currentListItem++; + _numListItems++; } - - entry = object_get_next(entry); itemFlags++; } @@ -1534,13 +1537,13 @@ static void window_editor_object_selection_scrollpaint(rct_window *w, rct_drawpi if (ridePage) { // Draw ride type - strcpy(buffer, language_get_string(2 + listItem->filter->ride.ride_type)); + strcpy(buffer, language_get_string(2 + listItem->repositoryItem->RideType[0])); gfx_draw_string(dpi, bufferWithColour, colour, x, y); x = w->widgets[WIDX_LIST_SORT_RIDE].left - w->widgets[WIDX_LIST].left; } // Draw text - strcpy(buffer, object_get_name(listItem->entry)); + strcpy(buffer, listItem->repositoryItem->Name); if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) { while (*buffer != 0 && *buffer != 9) buffer++; @@ -2115,26 +2118,26 @@ static bool filter_selected(uint8* objectFlag) { } } -static bool filter_string(rct_object_entry *entry, rct_object_filters *filter) +static bool filter_string(const ObjectRepositoryItem * item) { // Nothing to search for if (_filter_string[0] == '\0') return true; // Object doesn't have a name - char *name = object_get_name(entry); - if (name[0] == '\0') + utf8 *name = item->Name; + if (name == NULL || name[0] == '\0') return false; // Get ride type - const char *ride_type = language_get_string(2 + filter->ride.ride_type); + const char *rideTypeName = language_get_string(2 + item->RideType[0]); // Get object name (ride/vehicle for rides) and type name (rides only) char name_lower[MAX_PATH]; char type_lower[MAX_PATH]; char filter_lower[sizeof(_filter_string)]; safe_strcpy(name_lower, name, MAX_PATH); - safe_strcpy(type_lower, ride_type, MAX_PATH); + safe_strcpy(type_lower, rideTypeName, MAX_PATH); safe_strcpy(filter_lower, _filter_string, sizeof(_filter_string)); // Make use of lowercase characters only @@ -2145,30 +2148,30 @@ static bool filter_string(rct_object_entry *entry, rct_object_filters *filter) for (int i = 0; filter_lower[i] != '\0'; i++) filter_lower[i] = (char)tolower(filter_lower[i]); - return strstr(name_lower, filter_lower) != NULL || (((entry->flags & 0x0F) == OBJECT_TYPE_RIDE) && strstr(type_lower, filter_lower) != NULL); + return strstr(name_lower, filter_lower) != NULL || (((item->ObjectEntry.flags & 0x0F) == OBJECT_TYPE_RIDE) && strstr(type_lower, filter_lower) != NULL); } -static bool filter_source(rct_object_entry *entry) +static bool filter_source(const ObjectRepositoryItem * item) { if (_FILTER_ALL) return true; - uint8 source = (entry->flags & 0xF0) >> 4; + uint8 source = (item->ObjectEntry.flags & 0xF0) >> 4; return (_FILTER_RCT2 && source == 8) || (_FILTER_WW && source == 1) || (_FILTER_TT && source == 2) || (_FILTER_CUSTOM && source != 8 && source != 1 && source != 2); } -static bool filter_chunks(rct_object_entry *entry, rct_object_filters *filter) +static bool filter_chunks(const ObjectRepositoryItem * item) { - switch (entry->flags & 0x0F) { + switch (item->ObjectEntry.flags & 0x0F) { case OBJECT_TYPE_RIDE: if(!gConfigInterface.select_by_track_type) { - if (_filter_flags & (1 << (filter->ride.category[0] + 5))) + if (_filter_flags & (1 << (item->RideCategory[0] + 5))) return true; - if (_filter_flags & (1 << (filter->ride.category[1] + 5))) + if (_filter_flags & (1 << (item->RideCategory[1] + 5))) return true; } else { - if (_filter_flags & (1 << (gRideCategories[filter->ride.ride_type] + 5))) + if (_filter_flags & (1 << (gRideCategories[item->RideType[0]] + 5))) return true; } return false; @@ -2179,23 +2182,23 @@ static bool filter_chunks(rct_object_entry *entry, rct_object_filters *filter) static void filter_update_counts() { if (!_FILTER_ALL || strlen(_filter_string) > 0) { - rct_object_entry *installed_entry = gInstalledObjects; - rct_object_filters *filter; uint8 *objectFlag = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - uint8 type; for (int i = 0; i < 11; i++) { _filter_object_counts[i] = 0; } - for (uint32 i = 0; i < gInstalledObjectsCount; i++) { - filter = get_object_filter(i); - type = installed_entry->flags & 0xF; - if (filter_source(installed_entry) - && filter_string(installed_entry, filter) - && filter_chunks(installed_entry, filter) - && filter_selected(objectFlag)) { - _filter_object_counts[type]++; + + size_t numObjects = object_repository_get_items_count(); + const ObjectRepositoryItem * items = object_repository_get_items(); + for (size_t i = 0; i < numObjects; i++) { + const ObjectRepositoryItem * item = &items[i]; + if (filter_source(item) && + filter_string(item) && + filter_chunks(item) && + filter_selected(objectFlag) + ) { + uint8 objectType = item->ObjectEntry.flags & 0xF; + _filter_object_counts[objectType]++; } - installed_entry = object_get_next(installed_entry); objectFlag++; } } From 343623c81577793ca0807b8803124d5fc6b3b468 Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 29 Jun 2016 22:58:38 +0100 Subject: [PATCH 043/116] move more code from old object list to new repository --- src/object.h | 4 +- src/object/ObjectRepository.cpp | 7 +- src/object/ObjectRepository.h | 1 + src/object_list.c | 2 +- src/windows/editor_object_selection.c | 264 +++++++------------------- 5 files changed, 82 insertions(+), 196 deletions(-) diff --git a/src/object.h b/src/object.h index 9319408c0a..8c154b410d 100644 --- a/src/object.h +++ b/src/object.h @@ -124,7 +124,7 @@ int object_load_packed(SDL_RWops* rw); void object_unload_all(); int check_object_entry(rct_object_entry *entry); -int object_load_chunk(int groupIndex, rct_object_entry *entry, int* chunk_size); +int object_load_chunk(int groupIndex, const rct_object_entry *entry, int* chunk_size); void object_unload_chunk(rct_object_entry *entry); int object_get_scenario_text(rct_object_entry *entry); void object_free_scenario_text(); @@ -134,7 +134,7 @@ int object_calculate_checksum(const rct_object_entry *entry, const uint8 *data, rct_object_entry *object_get_next(const rct_object_entry *entry); int write_object_file(SDL_RWops* rw, rct_object_entry* entry); void reset_loaded_objects(); -int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index); +int find_object_in_entry_group(const rct_object_entry* entry, uint8* entry_type, uint8* entry_index); void object_create_identifier_name(char* string_buffer, const rct_object_entry* object); rct_object_entry *object_list_find_by_name(const char *name); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 2e9f360351..9da3034c7a 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -609,7 +609,7 @@ extern "C" IObjectRepository * objRepo = GetObjectRepository(); } - int object_load_chunk(int groupIndex, rct_object_entry * entry, int * chunkSize) + int object_load_chunk(int groupIndex, const rct_object_entry * entry, int * chunkSize) { IObjectRepository * objRepo = GetObjectRepository(); Object * object = objRepo->LoadObject(entry); @@ -664,6 +664,11 @@ extern "C" reset_type_to_ride_entry_index_map(); } + void object_repository_unload(size_t itemIndex) + { + // TODO + } + void object_unload_all() { for (int i = 0; i < 721; i++) diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index cfc59dcdb1..01310b1c6b 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -77,5 +77,6 @@ IObjectRepository * GetObjectRepository(); size_t object_repository_get_items_count(); const ObjectRepositoryItem * object_repository_get_items(); +void object_repository_unload(size_t itemIndex); #endif diff --git a/src/object_list.c b/src/object_list.c index ade4bddb87..627ac04996 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -268,7 +268,7 @@ bool object_load_entries(rct_object_entry* entries) * bl = entry_index * ecx = entry_type */ -int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index){ +int find_object_in_entry_group(const rct_object_entry* entry, uint8* entry_type, uint8* entry_index){ *entry_type = entry->flags & 0xF; rct_object_entry_group entry_group = object_entry_groups[*entry_type]; diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index d16581242b..8d478a8532 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -445,63 +445,38 @@ void window_editor_object_selection_open() * * rct2: 0x006ABCD1 */ -static void setup_track_manager_objects(){ +static void setup_track_manager_objects() +{ uint8 ride_list[128] = { 0 }; uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - rct_object_entry* installedObject = gInstalledObjects; - uint16 num_objects = 0; - for (int i = gInstalledObjectsCount; i > 0; --i){ - uint8 object_type = installedObject->flags & 0xF; + int numObjects = object_repository_get_items_count(); + const ObjectRepositoryItem * items = object_repository_get_items(); + for (int i = numObjects; i > 0; --i) { + const ObjectRepositoryItem * item = &items[i]; + uint8 object_type = item->ObjectEntry.flags & 0xF; if (object_type == OBJECT_TYPE_RIDE){ *selection_flags |= OBJECT_SELECTION_FLAG_6; - uint8* pos = (uint8*)installedObject; - // Skip sizeof(rct_object_entry) - pos += 16; - - // Skip filename - while (*pos++); - - // Skip no of images - pos += 4; - - // Skip name - while (*pos++); - - // Skip size of chunk - pos += 4; - - // Skip required objects - pos += *pos * 16 + 1; - - // Skip theme objects - pos += *pos * 16 + 1; - - for (uint8 j = 0; j < 3; j++){ - uint8 ride_type = pos[j]; + for (uint8 j = 0; j < 3; j++) { + uint8 ride_type = item->RideType[j]; if (ride_type == 0xFF) continue; if (!ride_type_has_flag(ride_type, RIDE_TYPE_FLAG_HAS_TRACK)) continue; - if (pos[3] & (1 << 0)){ + if (item->RideType[3] & (1 << 0)) { *selection_flags &= ~OBJECT_SELECTION_FLAG_6; - } - else if (ride_list[ride_type] & (1 << 0)){ + } else if (ride_list[ride_type] & (1 << 0)) { continue; - } - else{ + } else { ride_list[ride_type] |= (1 << 0); *selection_flags &= ~OBJECT_SELECTION_FLAG_6; } - num_objects++; break; } } - - installedObject = object_get_next(installedObject); selection_flags++; } } @@ -510,40 +485,19 @@ static void setup_track_manager_objects(){ * * rct2: 0x006ABC1E */ -static void setup_track_designer_objects(){ +static void setup_track_designer_objects() +{ uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - rct_object_entry* installedObject = gInstalledObjects; - uint16 num_objects = 0; - - for (int i = gInstalledObjectsCount; i > 0; --i){ - uint8 object_type = installedObject->flags & 0xF; + int numObjects = object_repository_get_items_count(); + const ObjectRepositoryItem * items = object_repository_get_items(); + for (int i = numObjects; i > 0; --i) { + const ObjectRepositoryItem * item = &items[i]; + uint8 object_type = item->ObjectEntry.flags & 0xF; if (object_type == OBJECT_TYPE_RIDE){ *selection_flags |= OBJECT_SELECTION_FLAG_6; - uint8* pos = (uint8*)installedObject; - // Skip sizeof(rct_object_entry) - pos += 16; - - // Skip filename - while (*pos++); - - // Skip no of images - pos += 4; - - // Skip name - while (*pos++); - - // Skip size of chunk - pos += 4; - - // Skip required objects - pos += *pos * 16 + 1; - - // Skip theme objects - pos += *pos * 16 + 1; - - for (uint8 j = 0; j < 3; j++){ - uint8 ride_type = pos[j]; + for (uint8 j = 0; j < 3; j++) { + uint8 ride_type = item->RideType[j]; if (ride_type == 0xFF) continue; @@ -551,12 +505,9 @@ static void setup_track_designer_objects(){ continue; *selection_flags &= ~OBJECT_SELECTION_FLAG_6; - num_objects++; break; } } - - installedObject = object_get_next(installedObject); selection_flags++; } } @@ -647,13 +598,15 @@ static void setup_in_use_selection_flags(){ } uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - rct_object_entry* installedObject = gInstalledObjects; - for (int i = gInstalledObjectsCount; i > 0; --i){ + int numObjects = (int)object_repository_get_items_count(); + const ObjectRepositoryItem * items = object_repository_get_items(); + for (int i = numObjects; i > 0; --i) { + const ObjectRepositoryItem * item = &items[i]; *selection_flags &= ~OBJECT_SELECTION_FLAG_IN_USE; uint8 entry_type, entry_index; - if (find_object_in_entry_group(installedObject, &entry_type, &entry_index)){ + if (find_object_in_entry_group(&item->ObjectEntry, &entry_type, &entry_index)) { if (RCT2_ADDRESS(0x0098DA38, uint8*)[entry_type][entry_index] & (1 << 0)){ *selection_flags |= OBJECT_SELECTION_FLAG_IN_USE | @@ -663,7 +616,6 @@ static void setup_in_use_selection_flags(){ *selection_flags |= OBJECT_SELECTION_FLAG_SELECTED; } } - installedObject = object_get_next(installedObject); selection_flags++; } } @@ -672,29 +624,27 @@ static void setup_in_use_selection_flags(){ * * rct2: 0x006AB211 */ -static int sub_6AB211(){ - uint32 total_objects = gInstalledObjectsCount; +static int sub_6AB211() +{ + int numObjects = (int)object_repository_get_items_count(); - RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) = malloc(total_objects); + RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) = malloc(numObjects); if (RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) == NULL){ log_error("Failed to allocate memory for object flag list."); return 0; } - memset(RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*), 0, total_objects); + memset(RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*), 0, numObjects); for (uint8 object_type = 0; object_type < 11; object_type++){ RCT2_ADDRESS(0x00F433F7, uint16)[object_type] = 0; RCT2_ADDRESS(0x00F433E1, uint16)[object_type] = 0; } - rct_object_entry* installedObject = gInstalledObjects; - - for (int i = gInstalledObjectsCount; i > 0; --i){ - uint8 object_type = installedObject->flags & 0xF; + const ObjectRepositoryItem * items = object_repository_get_items(); + for (int i = numObjects; i > 0; --i) { + uint8 object_type = items[i].ObjectEntry.flags & 0xF; RCT2_ADDRESS(0x00F433E1, uint16)[object_type]++; - - installedObject = object_get_next(installedObject); } if (gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER){ @@ -734,7 +684,7 @@ static void editor_object_flags_free() * * rct2: 0x00685791 */ -void remove_selected_objects_from_research(rct_object_entry* installedObject){ +void remove_selected_objects_from_research(const rct_object_entry* installedObject){ uint8 entry_type, entry_index; if (!find_object_in_entry_group(installedObject, &entry_type, &entry_index)) return; @@ -754,17 +704,18 @@ void remove_selected_objects_from_research(rct_object_entry* installedObject){ * * rct2: 0x006ABB66 */ -void unload_unselected_objects(){ +void unload_unselected_objects() +{ uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - rct_object_entry* installedObject = gInstalledObjects; - for (int i = gInstalledObjectsCount; i > 0; --i){ + int numItems = object_repository_get_items_count(); + const ObjectRepositoryItem * items = object_repository_get_items(); + for (int i = numItems; i > 0; --i) { if (!(*selection_flags & OBJECT_SELECTION_FLAG_SELECTED)){ - remove_selected_objects_from_research(installedObject); - object_unload_chunk(installedObject); + remove_selected_objects_from_research(&items[i].ObjectEntry); + object_repository_unload(i); } selection_flags++; - installedObject = object_get_next(installedObject); } } @@ -1618,84 +1569,34 @@ static void window_editor_object_selection_select_required_objects() * * rct2: 0x006AA770 */ -void reset_selected_object_count_and_size(){ - for (uint8 object_type = 0; object_type < 11; object_type++){ +void reset_selected_object_count_and_size() +{ + for (uint8 object_type = 0; object_type < 11; object_type++) { RCT2_ADDRESS(0x00F433F7, uint16)[object_type] = 0; } - - uint32 total_object_size = 0; - - uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - rct_object_entry* installedObject = gInstalledObjects; - - for (int i = gInstalledObjectsCount; i > 0; --i){ - uint8 object_type = installedObject->flags & 0xF; - - if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED){ - uint8* pos = (uint8*)installedObject; - // Skip sizeof(rct_object_entry) - pos += 16; - - // Skip filename - while (*pos++); - - // Skip no of images - pos += 4; - - // Skip name - while (*pos++); - - uint32 size_of_chunk = *((uint32*)pos); - RCT2_ADDRESS(0x00F433F7, uint16)[object_type]++; - total_object_size += size_of_chunk; - } - selection_flags++; - installedObject = object_get_next(installedObject); - } - - RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE, uint32) = total_object_size; } /** * * rct2: 0x006AB863 */ -void set_required_object_flags(rct_object_entry* required_object){ +void set_required_object_flags(rct_object_entry* required_object) +{ uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - rct_object_entry* installedObject = gInstalledObjects; - - for (int i = gInstalledObjectsCount; i > 0; --i){ - if (object_entry_compare(required_object, installedObject)){ + int numObjects = (int)object_repository_get_items_count(); + const ObjectRepositoryItem * items = object_repository_get_items(); + for (int i = numObjects; i > 0; --i) { + const ObjectRepositoryItem * item = &items[i]; + if (object_entry_compare(required_object, &item->ObjectEntry)) { *selection_flags |= OBJECT_SELECTION_FLAG_REQUIRED; - uint8* pos = (uint8*)installedObject; - // Skip sizeof(rct_object_entry) - pos += 16; - - // Skip filename - while (*pos++); - - // Skip no of images - pos += 4; - - // Skip name - while (*pos++); - - // Skip size of chunk - pos += 4; - - uint8 no_required_objects = *pos++; - - required_object = (rct_object_entry*)pos; - for (; no_required_objects > 0; no_required_objects--){ - set_required_object_flags(required_object); - required_object++; + uint16 no_required_objects = item->NumRequiredObjects; + for (; no_required_objects > 0; no_required_objects--) { + set_required_object_flags(&item->RequiredObjects[i]); } return; } - selection_flags++; - installedObject = object_get_next(installedObject); } } @@ -1703,46 +1604,29 @@ void set_required_object_flags(rct_object_entry* required_object){ * * rct2: 0x006AB923 */ -void reset_required_object_flags(){ +void reset_required_object_flags() +{ + int numObjects = (int)object_repository_get_items_count(); + const ObjectRepositoryItem * items = object_repository_get_items(); + uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - for (int i = gInstalledObjectsCount; i > 0; --i){ + for (int i = numObjects; i > 0; --i) { *selection_flags &= ~OBJECT_SELECTION_FLAG_REQUIRED; selection_flags++; } selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - rct_object_entry* installedObject = gInstalledObjects; - for (int i = gInstalledObjectsCount; i > 0; --i){ + for (int i = numObjects; i > 0; --i){ + const ObjectRepositoryItem * item = &items[i]; if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED){ - uint8* pos = (uint8*)installedObject; - // Skip sizeof(rct_object_entry) - pos += 16; - - // Skip filename - while (*pos++); - - // Skip no of images - pos += 4; - - // Skip name - while (*pos++); - - // Skip size of chunk - pos += 4; - - uint8 no_required_objects = *pos++; - - rct_object_entry* required_object = (rct_object_entry*)pos; + uint16 no_required_objects = item->NumRequiredObjects; for (; no_required_objects > 0; no_required_objects--){ - set_required_object_flags(required_object); - required_object++; + set_required_object_flags(&item->RequiredObjects[i]); } - } selection_flags++; - installedObject = object_get_next(installedObject); } } @@ -2024,24 +1908,22 @@ static void window_editor_object_selection_manage_tracks() static void editor_load_selected_objects() { uint8 *selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - rct_object_entry *installed_entry = gInstalledObjects; - if (gInstalledObjectsCount == 0) - return; - - for (int i = gInstalledObjectsCount; i != 0; i--, selection_flags++) { + int numObjects = (int)object_repository_get_items_count(); + const ObjectRepositoryItem * items = object_repository_get_items(); + for (int i = numObjects; i != 0; i--, selection_flags++) { if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED) { uint8 entry_index, entry_type; - if (!find_object_in_entry_group(installed_entry, &entry_type, &entry_index)){ + if (!find_object_in_entry_group(&items[i].ObjectEntry, &entry_type, &entry_index)) { int chunk_size; - if (!object_load_chunk(-1, installed_entry, &chunk_size)) { - log_error("Failed to load entry %.8s", installed_entry->name); + if (!object_load_chunk(-1, &items[i].ObjectEntry, &chunk_size)) { + log_error("Failed to load entry %.8s", items->Name); } // For in game use (cheat) if (!(gScreenFlags & SCREEN_FLAGS_EDITOR)) { // Defaults selected items to researched. - if (find_object_in_entry_group(installed_entry, &entry_type, &entry_index)) { + if (find_object_in_entry_group(&items[i].ObjectEntry, &entry_type, &entry_index)) { if (entry_type == OBJECT_TYPE_RIDE) { rct_ride_entry* rideType = get_ride_entry(entry_index); research_insert(1, 0x10000 | (rideType->ride_type[0] << 8) | entry_index, rideType->category[0]); @@ -2053,8 +1935,6 @@ static void editor_load_selected_objects() } } } - - installed_entry = object_get_next(installed_entry); } } From d1dc6b528dabd1d4beefd8e81d76f3b05023aa30 Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 30 Jun 2016 18:53:49 +0100 Subject: [PATCH 044/116] Add Memory::Copy overlap check and Memory::Move --- src/core/Memory.hpp | 20 ++++++++++++++++---- src/core/String.cpp | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/core/Memory.hpp b/src/core/Memory.hpp index 4cebdd192a..761bd6b801 100644 --- a/src/core/Memory.hpp +++ b/src/core/Memory.hpp @@ -16,10 +16,8 @@ #pragma once -extern "C" -{ - #include "../common.h" -} +#include "../common.h" +#include "Guard.hpp" /** * Utility methods for memory management. Typically helpers and wrappers around the C standard library. @@ -80,9 +78,23 @@ namespace Memory T * Copy(T * dst, const T * src, size_t size) { if (size == 0) return (T*)dst; +#ifdef DEBUG + uintptr_t srcBegin = (uintptr_t)src; + uintptr_t srcEnd = srcBegin + size; + uintptr_t dstBegin = (uintptr_t)dst; + uintptr_t dstEnd = dstBegin + size; + Guard::Assert(srcEnd <= dstBegin || srcBegin >= dstEnd, "Source overlaps destination, try using Memory::Move."); +#endif return (T*)memcpy((void*)dst, (const void*)src, size); } + template + T * Move(T * dst, const T * src, size_t size) + { + if (size == 0) return (T*)dst; + return (T*)memmove((void*)dst, (const void*)src, size); + } + template T * Duplicate(const T * src, size_t size) { diff --git a/src/core/String.cpp b/src/core/String.cpp index edc22e9b3b..aea62f553a 100644 --- a/src/core/String.cpp +++ b/src/core/String.cpp @@ -251,7 +251,7 @@ namespace String assert(newStringSize < currentStringSize); #endif - Memory::Copy(str, firstNonWhitespace, newStringSize); + Memory::Move(str, firstNonWhitespace, newStringSize); str[newStringSize] = '\0'; } else From 554d445db48d48a2bcc28087ea3662a0ee35977b Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 30 Jun 2016 21:07:32 +0100 Subject: [PATCH 045/116] migrate more of object selection --- src/object/ObjectRepository.cpp | 6 + src/object/ObjectRepository.h | 1 + src/windows/editor_object_selection.c | 192 ++++++++------------------ 3 files changed, 66 insertions(+), 133 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 9da3034c7a..30f269653f 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -775,4 +775,10 @@ extern "C" IObjectRepository * objectRepository = GetObjectRepository(); return objectRepository->GetObjects(); } + + const ObjectRepositoryItem * object_repository_find_object_by_entry(const rct_object_entry * entry) + { + IObjectRepository * objectRepository = GetObjectRepository(); + return objectRepository->FindObject(entry); + } } diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 01310b1c6b..6856645014 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -77,6 +77,7 @@ IObjectRepository * GetObjectRepository(); size_t object_repository_get_items_count(); const ObjectRepositoryItem * object_repository_get_items(); +const ObjectRepositoryItem * object_repository_find_object_by_entry(const rct_object_entry * entry); void object_repository_unload(size_t itemIndex); #endif diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 8d478a8532..3f1b46236b 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -221,7 +221,7 @@ static void window_editor_object_selection_set_pressed_tab(rct_window *w); static void window_editor_object_selection_select_default_objects(); static void window_editor_object_selection_select_required_objects(); static int window_editor_object_selection_select_object(uint8 bh, int flags, rct_object_entry *entry); -static int get_object_from_object_selection(uint8 object_type, int y, uint8 *object_selection_flags, rct_object_entry **installed_entry); +static int get_object_from_object_selection(uint8 object_type, int y); static void window_editor_object_selection_manage_tracks(); static void editor_load_selected_objects(); static bool filter_selected(uint8* objectFlags); @@ -972,9 +972,10 @@ static void window_editor_object_selection_scroll_mousedown(rct_window *w, int s // when windows attempt to draw objects that don't exist any more window_close_all_except_class(WC_EDITOR_OBJECT_SELECTION); - uint8 object_selection_flags; - rct_object_entry* installed_entry; - int selected_object = get_object_from_object_selection((w->selected_tab & 0xFF), y, &object_selection_flags, &installed_entry); + int selected_object = get_object_from_object_selection((w->selected_tab & 0xFF), y); + + list_item * listItem = &_listItems[selected_object]; + uint8 object_selection_flags = *listItem->flags; if (selected_object == -1 || (object_selection_flags & OBJECT_SELECTION_FLAG_6)) return; @@ -984,7 +985,7 @@ static void window_editor_object_selection_scroll_mousedown(rct_window *w, int s if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) { - if (!window_editor_object_selection_select_object(0, 1, installed_entry)) + if (!window_editor_object_selection_select_object(0, 1, listItem->entry)) return; // Close any other open windows such as options/colour schemes to prevent a crash. @@ -1002,7 +1003,7 @@ static void window_editor_object_selection_scroll_mousedown(rct_window *w, int s ebx = 7; RCT2_GLOBAL(0xF43411, uint8) = 0; - if (!window_editor_object_selection_select_object(0, ebx, installed_entry)) { + if (!window_editor_object_selection_select_object(0, ebx, listItem->entry)) { rct_string_id error_title = ebx & 1 ? STR_UNABLE_TO_SELECT_THIS_OBJECT : STR_UNABLE_TO_DE_SELECT_THIS_OBJECT; @@ -1029,26 +1030,24 @@ static void window_editor_object_selection_scroll_mousedown(rct_window *w, int s */ static void window_editor_object_selection_scroll_mouseover(rct_window *w, int scrollIndex, int x, int y) { - rct_object_entry *installedEntry; - int selectedObject; - uint8 objectSelectionFlags; - - selectedObject = get_object_from_object_selection( - w->selected_tab & 0xFF, y, &objectSelectionFlags, &installedEntry - ); - if (objectSelectionFlags & OBJECT_SELECTION_FLAG_6) + int selectedObject = get_object_from_object_selection(w->selected_tab & 0xFF, y); + list_item * listItem = &_listItems[selectedObject]; + uint8 objectSelectionFlags = *listItem->flags; + if (objectSelectionFlags & OBJECT_SELECTION_FLAG_6) { selectedObject = -1; + } - if (selectedObject == w->selected_list_item) - return; + if (selectedObject != w->selected_list_item) { + w->selected_list_item = selectedObject; + w->object_entry = listItem->entry; + object_free_scenario_text(); + if (selectedObject != -1) { + // Load object - w->selected_list_item = selectedObject; - w->object_entry = installedEntry; - object_free_scenario_text(); - if (selectedObject != -1) - object_get_scenario_text(installedEntry); + } - window_invalidate(w); + window_invalidate(w); + } } /** @@ -1648,42 +1647,19 @@ void set_object_selection_error(uint8 is_master_object, rct_string_id error_msg) */ static int window_editor_object_selection_select_object(uint8 bh, int flags, rct_object_entry *entry) { - uint8* selection_flags; - //if (bh == 0){ - // // Unsure what this does?? - // uint16 total_objects = 0; - // for (uint8 i = 0; i < 11; ++i){ - // total_objects += RCT2_ADDRESS(0x00F433E1, uint16)[i]; - // } - - // selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - // for (; total_objects != 0; total_objects--, selection_flags++){ - // uint8 select_flag = *selection_flags & ~OBJECT_SELECTION_FLAG_2; - // if (select_flag & OBJECT_SELECTION_FLAG_SELECTED){ - // select_flag |= OBJECT_SELECTION_FLAG_2; - // } - // } - //} - - selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - // There was previously a check to make sure the object list had an item - rct_object_entry* installedObject = gInstalledObjects; - - uint8 not_found = 1; - for (int i = gInstalledObjectsCount; i > 0; --i){ - if (object_entry_compare(entry, installedObject)){ - not_found = 0; - break; - } - - installedObject = object_get_next(installedObject); - selection_flags++; - } - if (not_found){ + int numObjects = (int)object_repository_get_items_count(); + const ObjectRepositoryItem * item = object_repository_find_object_by_entry(entry); + if (item == NULL) { set_object_selection_error(bh, 3169); return 0; } + uint8 * selection_flags; + selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + for (int i = numObjects; i > 0; --i) { + selection_flags++; + } + if (!(flags & 1)){ if (!(*selection_flags & OBJECT_SELECTION_FLAG_SELECTED)) { @@ -1705,132 +1681,85 @@ static int window_editor_object_selection_select_object(uint8 bh, int flags, rct return 0; } - uint8* pos = (uint8*)installedObject; - // Skip sizeof(rct_object_entry) - pos += 16; - - // Skip filename - while (*pos++); - - // Skip no of images - pos += 4; - - // Skip name - while (*pos++); - - uint32 size_of_chunk = *((uint32*)pos); - // Skip size of chunk - pos += 4; - - // Skip required objects - pos += *pos * 16 + 1; - - uint8 no_theme_objects = *pos++; - - if (no_theme_objects != 0 && flags&(1 << 2)){ - rct_object_entry* theme_object = (rct_object_entry*)pos; - for (; no_theme_objects > 0; no_theme_objects--){ + uint16 numThemeObjects = item->NumThemeObjects; + if (numThemeObjects != 0 && flags & (1 << 2)) { + rct_object_entry* theme_object = item->ThemeObjects; + for (; numThemeObjects > 0; numThemeObjects--) { window_editor_object_selection_select_object(++bh, flags, theme_object); theme_object++; } } - RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE, uint32) -= size_of_chunk; - uint8 object_type = installedObject->flags & 0xF; + uint8 object_type = item->ObjectEntry.flags & 0xF; RCT2_ADDRESS(0x00F433F7, uint16)[object_type]--; *selection_flags &= ~OBJECT_SELECTION_FLAG_SELECTED; - if (bh == 0){ + if (bh == 0) { reset_required_object_flags(); } return 1; - } - else{ - if (bh == 0){ - if (flags & (1 << 3)){ + } else { + if (bh == 0) { + if (flags & (1 << 3)) { *selection_flags |= OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED; } } - if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED){ - if (bh == 0){ + if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED) { + if (bh == 0) { reset_required_object_flags(); } return 1; } - uint8 object_type = installedObject->flags & 0xF; + uint8 object_type = item->ObjectEntry.flags & 0xF; uint16 no_objects = object_entry_group_counts[object_type]; - if (gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER){ + if (gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) { no_objects = 4; } - if (no_objects <= RCT2_ADDRESS(0x00F433F7, uint16)[object_type]){ + if (no_objects <= RCT2_ADDRESS(0x00F433F7, uint16)[object_type]) { set_object_selection_error(bh, 3171); return 0; } - uint8* pos = (uint8*)installedObject; - // Skip sizeof(rct_object_entry) - pos += 16; - - // Skip filename - while (*pos++); - - // Skip no of images - pos += 4; - - // Skip name - while (*pos++); - - uint32 size_of_chunk = *((uint32*)pos); - // Skip size of chunk - pos += 4; - - uint8 num_required_objects = *pos++; - rct_object_entry* required_objects = (rct_object_entry*)pos; - for (; num_required_objects != 0; num_required_objects--){ - if (!window_editor_object_selection_select_object(++bh, flags, required_objects)){ - if (bh != 0){ + uint16 numRequiredObjects = item->NumRequiredObjects; + rct_object_entry * required_objects = item->RequiredObjects; + for (; numRequiredObjects != 0; numRequiredObjects--) { + if (!window_editor_object_selection_select_object(++bh, flags, required_objects)) { + if (bh != 0) { reset_selected_object_count_and_size(); } return 0; } required_objects++; } - pos = (uint8*)required_objects; - uint8 num_theme_objects = *pos++; - rct_object_entry* theme_object = (rct_object_entry*)pos; - for (; num_theme_objects != 0; num_theme_objects--){ - if (flags & (1 << 2)){ - if (!window_editor_object_selection_select_object(++bh, flags, theme_object)){ + uint16 numThemeObjects = item->NumThemeObjects; + rct_object_entry * theme_object = item->RequiredObjects; + for (; numThemeObjects != 0; numThemeObjects--) { + if (flags & (1 << 2)) { + if (!window_editor_object_selection_select_object(++bh, flags, theme_object)) { RCT2_GLOBAL(0x00F43411, uint8) |= 1; } } theme_object++; } - if (bh != 0 && !(flags&(1 << 1))){ - object_create_identifier_name((char*)0x009BC95A, installedObject); + if (bh != 0 && !(flags & (1 << 1))) { + object_create_identifier_name((char*)0x009BC95A, &item->ObjectEntry); set_format_arg(0, uint32, 0x009BC95A); set_object_selection_error(bh, 3172); return 0; } - if (RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE, uint32) + size_of_chunk > 0x40000){ - set_object_selection_error(bh, 3170); - return 0; - } - - if (no_objects <= RCT2_ADDRESS(0x00F433F7, uint16)[object_type]){ + if (no_objects <= RCT2_ADDRESS(0x00F433F7, uint16)[object_type]) { set_object_selection_error(bh, 3171); return 0; } - RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_OBJECTS_FILE_SIZE, uint32) += size_of_chunk; RCT2_ADDRESS(0x00F433F7, uint16)[object_type]++; *selection_flags |= OBJECT_SELECTION_FLAG_SELECTED; - if (bh == 0){ + if (bh == 0) { reset_required_object_flags(); } return 1; @@ -1845,15 +1774,12 @@ static int window_editor_object_selection_select_object(uint8 bh, int flags, rct * * rct2: 0x006AA703 */ -static int get_object_from_object_selection(uint8 object_type, int y, uint8 *object_selection_flags, rct_object_entry **installed_entry) +static int get_object_from_object_selection(uint8 object_type, int y) { int listItemIndex = y / 12; if (listItemIndex < 0 || listItemIndex >= _numListItems) return -1; - list_item *listItem = &_listItems[listItemIndex]; - *object_selection_flags = *listItem->flags; - *installed_entry = listItem->entry; return listItemIndex; } From f6d6d935808f94958724c1c086b14288dc714e9d Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 30 Jun 2016 21:55:18 +0100 Subject: [PATCH 046/116] fix highlight object in object selection --- src/object/BannerObject.cpp | 2 +- src/object/BannerObject.h | 2 +- src/object/EntranceObject.cpp | 2 +- src/object/EntranceObject.h | 2 +- src/object/FootpathItemObject.cpp | 2 +- src/object/FootpathItemObject.h | 2 +- src/object/FootpathObject.cpp | 2 +- src/object/FootpathObject.h | 2 +- src/object/LargeSceneryObject.cpp | 2 +- src/object/LargeSceneryObject.h | 2 +- src/object/Object.h | 9 +- src/object/ObjectRepository.cpp | 31 ++++++ src/object/ObjectRepository.h | 4 + src/object/RideObject.cpp | 6 +- src/object/RideObject.h | 6 +- src/object/SceneryGroupObject.cpp | 2 +- src/object/SceneryGroupObject.h | 2 +- src/object/SmallSceneryObject.cpp | 2 +- src/object/SmallSceneryObject.h | 2 +- src/object/StexObject.cpp | 8 +- src/object/StexObject.h | 8 +- src/object/StringTable.cpp | 2 +- src/object/StringTable.h | 2 +- src/object/WallObject.cpp | 2 +- src/object/WallObject.h | 2 +- src/object/WaterObject.cpp | 2 +- src/object/WaterObject.h | 2 +- src/windows/editor_object_selection.c | 133 +++++++++----------------- 28 files changed, 121 insertions(+), 124 deletions(-) diff --git a/src/object/BannerObject.cpp b/src/object/BannerObject.cpp index e4f317ffe9..2eb25d1cbc 100644 --- a/src/object/BannerObject.cpp +++ b/src/object/BannerObject.cpp @@ -68,7 +68,7 @@ void BannerObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } -const utf8 * BannerObject::GetName() +const utf8 * BannerObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); return name != nullptr ? name : ""; diff --git a/src/object/BannerObject.h b/src/object/BannerObject.h index afb701f560..dfc4bd1558 100644 --- a/src/object/BannerObject.h +++ b/src/object/BannerObject.h @@ -38,5 +38,5 @@ public: void Load() override; void Unload() override; - const utf8 * GetName() override; + const utf8 * GetName() const override; }; diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index 0cb83caa53..dc9cfcc9ab 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -51,7 +51,7 @@ void EntranceObject::Unload() gfx_object_free_images(_legacyType.image_id, GetImageTable()->GetCount()); } -const utf8 * EntranceObject::GetName() +const utf8 * EntranceObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); return name != nullptr ? name : ""; diff --git a/src/object/EntranceObject.h b/src/object/EntranceObject.h index 08091cbcd5..781984cf55 100644 --- a/src/object/EntranceObject.h +++ b/src/object/EntranceObject.h @@ -37,5 +37,5 @@ public: void Load() override; void Unload() override; - const utf8 * GetName() override; + const utf8 * GetName() const override; }; diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp index 44049e931a..e4f2e3c6b5 100644 --- a/src/object/FootpathItemObject.cpp +++ b/src/object/FootpathItemObject.cpp @@ -67,7 +67,7 @@ void FootpathItemObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } -const utf8 * FootpathItemObject::GetName() +const utf8 * FootpathItemObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); return name != nullptr ? name : ""; diff --git a/src/object/FootpathItemObject.h b/src/object/FootpathItemObject.h index 83ed82bd55..00f947b453 100644 --- a/src/object/FootpathItemObject.h +++ b/src/object/FootpathItemObject.h @@ -38,5 +38,5 @@ public: void Load() override; void Unload() override; - const utf8 * GetName() override; + const utf8 * GetName() const override; }; diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp index 50674b9536..752a8d1f0a 100644 --- a/src/object/FootpathObject.cpp +++ b/src/object/FootpathObject.cpp @@ -56,7 +56,7 @@ void FootpathObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } -const utf8 * FootpathObject::GetName() +const utf8 * FootpathObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); return name != nullptr ? name : ""; diff --git a/src/object/FootpathObject.h b/src/object/FootpathObject.h index 096758e66d..2f6e385081 100644 --- a/src/object/FootpathObject.h +++ b/src/object/FootpathObject.h @@ -37,5 +37,5 @@ public: void Load() override; void Unload() override; - const utf8 * GetName() override; + const utf8 * GetName() const override; }; diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index 240d62d0af..bc0ef75a27 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -102,7 +102,7 @@ void LargeSceneryObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } -const utf8 * LargeSceneryObject::GetName() +const utf8 * LargeSceneryObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); return name != nullptr ? name : ""; diff --git a/src/object/LargeSceneryObject.h b/src/object/LargeSceneryObject.h index 4f0ba88384..fa4b24bfe2 100644 --- a/src/object/LargeSceneryObject.h +++ b/src/object/LargeSceneryObject.h @@ -41,7 +41,7 @@ public: void Load() override; void Unload() override; - const utf8 * GetName() override; + const utf8 * GetName() const override; private: static rct_large_scenery_tile * ReadTiles(IStream * stream); diff --git a/src/object/Object.h b/src/object/Object.h index 690660bbb6..358342ac6c 100644 --- a/src/object/Object.h +++ b/src/object/Object.h @@ -36,8 +36,9 @@ private: ImageTable _imageTable; protected: - StringTable * GetStringTable() { return &_stringTable; } - ImageTable * GetImageTable() { return &_imageTable; } + StringTable * GetStringTable() { return &_stringTable; } + const StringTable * GetStringTable() const { return &_stringTable; } + ImageTable * GetImageTable() { return &_imageTable; } public: explicit Object(const rct_object_entry &entry); @@ -51,8 +52,8 @@ public: virtual void Load() abstract; virtual void Unload() abstract; - virtual uint8 GetObjectType() { return _objectEntry.flags & 0x0F; } - virtual const utf8 * GetName() abstract; + virtual uint8 GetObjectType() const { return _objectEntry.flags & 0x0F; } + virtual const utf8 * GetName() const abstract; virtual void SetRepositoryItem(ObjectRepositoryItem * item) const { } }; diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 30f269653f..1ff6a9cbe9 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -31,6 +31,7 @@ #include "Object.h" #include "ObjectFactory.h" #include "ObjectRepository.h" +#include "RideObject.h" #include "StexObject.h" extern "C" @@ -664,6 +665,12 @@ extern "C" reset_type_to_ride_entry_index_map(); } + void * object_repository_load_object(const rct_object_entry * objectEntry) + { + IObjectRepository * objRepository = GetObjectRepository(); + return (void *)objRepository->LoadObject(objectEntry); + } + void object_repository_unload(size_t itemIndex) { // TODO @@ -781,4 +788,28 @@ extern "C" IObjectRepository * objectRepository = GetObjectRepository(); return objectRepository->FindObject(entry); } + + void object_delete(void * object) + { + delete ((Object *)object); + } + + const utf8 * object_get_description(const void * object) + { + const Object * baseObject = (const Object *)object; + switch (baseObject->GetObjectType()) { + case OBJECT_TYPE_RIDE: + { + const RideObject * rideObject = static_cast(baseObject); + return rideObject->GetDescription(); + } + case OBJECT_TYPE_SCENARIO_TEXT: + { + const StexObject * stexObject = static_cast(baseObject); + return stexObject->GetScenarioDetails(); + } + default: + return ""; + } + } } diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 6856645014..72d1692cd2 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -78,6 +78,10 @@ IObjectRepository * GetObjectRepository(); size_t object_repository_get_items_count(); const ObjectRepositoryItem * object_repository_get_items(); const ObjectRepositoryItem * object_repository_find_object_by_entry(const rct_object_entry * entry); +void * object_repository_load_object(const rct_object_entry * objectEntry); void object_repository_unload(size_t itemIndex); +void object_delete(void * object); +const utf8 * object_get_description(const void * object); + #endif diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index fd0369a60d..02572b67f2 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -327,19 +327,19 @@ void RideObject::Unload() gfx_object_free_images(_legacyType.images_offset, GetImageTable()->GetCount()); } -const utf8 * RideObject::GetName() +const utf8 * RideObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); return name != nullptr ? name : ""; } -const utf8 * RideObject::GetDescription() +const utf8 * RideObject::GetDescription() const { const utf8 * description = GetStringTable()->GetString(OBJ_STRING_ID_DESCRIPTION); return description != nullptr ? description : ""; } -const utf8 * RideObject::GetCapacity() +const utf8 * RideObject::GetCapacity() const { const utf8 * capacity = GetStringTable()->GetString(OBJ_STRING_ID_CAPACITY); return capacity != nullptr ? capacity : ""; diff --git a/src/object/RideObject.h b/src/object/RideObject.h index 75ed233556..171c84ea54 100644 --- a/src/object/RideObject.h +++ b/src/object/RideObject.h @@ -40,9 +40,9 @@ public: void Load() override; void Unload() override; - const utf8 * GetName() override; - const utf8 * GetDescription(); - const utf8 * GetCapacity(); + const utf8 * GetName() const override; + const utf8 * GetDescription() const; + const utf8 * GetCapacity() const; void SetRepositoryItem(ObjectRepositoryItem * item) const; diff --git a/src/object/SceneryGroupObject.cpp b/src/object/SceneryGroupObject.cpp index 262654b01a..d6173d4630 100644 --- a/src/object/SceneryGroupObject.cpp +++ b/src/object/SceneryGroupObject.cpp @@ -85,7 +85,7 @@ void SceneryGroupObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } -const utf8 * SceneryGroupObject::GetName() +const utf8 * SceneryGroupObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); return name != nullptr ? name : ""; diff --git a/src/object/SceneryGroupObject.h b/src/object/SceneryGroupObject.h index 8f8b45ae48..b21685173a 100644 --- a/src/object/SceneryGroupObject.h +++ b/src/object/SceneryGroupObject.h @@ -40,7 +40,7 @@ public: void Load() override; void Unload() override; - const utf8 * GetName() override; + const utf8 * GetName() const override; private: void ReadItems(IStream * stream); diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index 3ca97e0625..d7d3ac2ecb 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -89,7 +89,7 @@ void SmallSceneryObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } -const utf8 * SmallSceneryObject::GetName() +const utf8 * SmallSceneryObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); return name != nullptr ? name : ""; diff --git a/src/object/SmallSceneryObject.h b/src/object/SmallSceneryObject.h index 5f0aa5e73f..a0bd022912 100644 --- a/src/object/SmallSceneryObject.h +++ b/src/object/SmallSceneryObject.h @@ -40,7 +40,7 @@ public: void Load() override; void Unload() override; - const utf8 * GetName() override; + const utf8 * GetName() const override; private: static uint8 * ReadVar10(IStream * stream); diff --git a/src/object/StexObject.cpp b/src/object/StexObject.cpp index bcb8906261..a7213eeec1 100644 --- a/src/object/StexObject.cpp +++ b/src/object/StexObject.cpp @@ -56,24 +56,24 @@ void StexObject::Unload() language_free_object_string(_legacyType.details); } -const utf8 * StexObject::GetName() +const utf8 * StexObject::GetName() const { return GetScenarioName(); } -const utf8 * StexObject::GetScenarioName() +const utf8 * StexObject::GetScenarioName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_SCENARIO_NAME); return name != nullptr ? name : ""; } -const utf8 * StexObject::GetScenarioDetails() +const utf8 * StexObject::GetScenarioDetails() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_SCENARIO_DETAILS); return name != nullptr ? name : ""; } -const utf8 * StexObject::GetParkName() +const utf8 * StexObject::GetParkName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_PARK_NAME); return name != nullptr ? name : ""; diff --git a/src/object/StexObject.h b/src/object/StexObject.h index 3204cc40db..a5d58032e2 100644 --- a/src/object/StexObject.h +++ b/src/object/StexObject.h @@ -37,9 +37,9 @@ public: void Load() override; void Unload() override; - const utf8 * GetName() override; + const utf8 * GetName() const override; - const utf8 * GetScenarioName(); - const utf8 * GetScenarioDetails(); - const utf8 * GetParkName(); + const utf8 * GetScenarioName() const; + const utf8 * GetScenarioDetails() const; + const utf8 * GetParkName() const; }; diff --git a/src/object/StringTable.cpp b/src/object/StringTable.cpp index b5c46e36f9..943a960e04 100644 --- a/src/object/StringTable.cpp +++ b/src/object/StringTable.cpp @@ -69,7 +69,7 @@ void StringTable::Read(IStream * stream, uint8 id) Sort(); } -const utf8 * StringTable::GetString(uint8 id) +const utf8 * StringTable::GetString(uint8 id) const { for (auto &string : _strings) { diff --git a/src/object/StringTable.h b/src/object/StringTable.h index aef6ba6d75..48ff2b1826 100644 --- a/src/object/StringTable.h +++ b/src/object/StringTable.h @@ -37,7 +37,7 @@ public: ~StringTable(); void Read(IStream * stream, uint8 id); - const utf8 * GetString(uint8 id); + const utf8 * GetString(uint8 id) const; private: void Sort(); diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp index 5c6163fdec..e8295adb0e 100644 --- a/src/object/WallObject.cpp +++ b/src/object/WallObject.cpp @@ -71,7 +71,7 @@ void WallObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } -const utf8 * WallObject::GetName() +const utf8 * WallObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); return name != nullptr ? name : ""; diff --git a/src/object/WallObject.h b/src/object/WallObject.h index af32bcaa38..5d685a5e97 100644 --- a/src/object/WallObject.h +++ b/src/object/WallObject.h @@ -38,5 +38,5 @@ public: void Load() override; void Unload() override; - const utf8 * GetName() override; + const utf8 * GetName() const override; }; diff --git a/src/object/WaterObject.cpp b/src/object/WaterObject.cpp index d42fa572ad..0f6b64429f 100644 --- a/src/object/WaterObject.cpp +++ b/src/object/WaterObject.cpp @@ -59,7 +59,7 @@ void WaterObject::Unload() language_free_object_string(_legacyType.string_idx); } -const utf8 * WaterObject::GetName() +const utf8 * WaterObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); return name != nullptr ? name : ""; diff --git a/src/object/WaterObject.h b/src/object/WaterObject.h index 147ad7f570..b288fc8b29 100644 --- a/src/object/WaterObject.h +++ b/src/object/WaterObject.h @@ -37,5 +37,5 @@ public: void Load() override; void Unload() override; - const utf8 * GetName() override; + const utf8 * GetName() const override; }; diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 3f1b46236b..9b3172ee82 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -282,6 +282,16 @@ enum { RIDE_SORT_RIDE }; +enum { + DDIX_FILTER_RCT2, + DDIX_FILTER_WW, + DDIX_FILTER_TT, + DDIX_FILTER_CUSTOM, + DDIX_FILTER_SEPERATOR, + DDIX_FILTER_SELECTED, + DDIX_FILTER_NONSELECTED, +}; + typedef struct list_item { const ObjectRepositoryItem * repositoryItem; rct_object_entry *entry; @@ -295,6 +305,7 @@ static int _numListItems = 0; static list_item *_listItems = NULL; static int _listSortType = RIDE_SORT_TYPE; static bool _listSortDescending = false; +static void * _loadedObject = NULL; static void visible_list_dispose() { @@ -865,16 +876,7 @@ static void window_editor_object_selection_resize(rct_window *w) { window_set_resize(w, 600, 400, 1200, 1000); } -enum -{ - DDIX_FILTER_RCT2, - DDIX_FILTER_WW, - DDIX_FILTER_TT, - DDIX_FILTER_CUSTOM, - DDIX_FILTER_SEPERATOR, - DDIX_FILTER_SELECTED, - DDIX_FILTER_NONSELECTED, -}; + void window_editor_object_selection_mousedown(int widgetIndex, rct_window*w, rct_widget* widget) { int num_items; @@ -973,10 +975,12 @@ static void window_editor_object_selection_scroll_mousedown(rct_window *w, int s window_close_all_except_class(WC_EDITOR_OBJECT_SELECTION); int selected_object = get_object_from_object_selection((w->selected_tab & 0xFF), y); + if (selected_object == -1) + return; list_item * listItem = &_listItems[selected_object]; uint8 object_selection_flags = *listItem->flags; - if (selected_object == -1 || (object_selection_flags & OBJECT_SELECTION_FLAG_6)) + if (object_selection_flags & OBJECT_SELECTION_FLAG_6) return; window_invalidate(w); @@ -1031,19 +1035,27 @@ static void window_editor_object_selection_scroll_mousedown(rct_window *w, int s static void window_editor_object_selection_scroll_mouseover(rct_window *w, int scrollIndex, int x, int y) { int selectedObject = get_object_from_object_selection(w->selected_tab & 0xFF, y); - list_item * listItem = &_listItems[selectedObject]; - uint8 objectSelectionFlags = *listItem->flags; - if (objectSelectionFlags & OBJECT_SELECTION_FLAG_6) { - selectedObject = -1; + if (selectedObject != -1) { + list_item * listItem = &_listItems[selectedObject]; + uint8 objectSelectionFlags = *listItem->flags; + if (objectSelectionFlags & OBJECT_SELECTION_FLAG_6) { + selectedObject = -1; + } } - if (selectedObject != w->selected_list_item) { w->selected_list_item = selectedObject; - w->object_entry = listItem->entry; - object_free_scenario_text(); - if (selectedObject != -1) { - // Load object + if (_loadedObject != NULL) { + object_delete(_loadedObject); + _loadedObject = NULL; + } + + list_item * listItem = &_listItems[selectedObject]; + if (selectedObject == -1) { + w->object_entry = NULL; + } else { + w->object_entry = listItem->entry; + _loadedObject = object_repository_load_object(listItem->entry); } window_invalidate(w); @@ -1216,8 +1228,8 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf rct_widget *widget; rct_object_entry *highlightedEntry; rct_string_id stringId; - uint8 *text, source; - char *datName, *name, *stringBuffer; + uint8 source; + char *stringBuffer; /*if (w->selected_tab == WINDOW_OBJECT_SELECTION_PAGE_RIDE_VEHICLES_ATTRACTIONS) { gfx_fill_rect_inset(dpi, @@ -1297,26 +1309,6 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf rct_stex_entry* stex_entry = gStexTempChunk; - /*gfx_fill_rect_inset(dpi, - w->x + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].left, - w->y + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].top, - w->x + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].right, - w->y + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].bottom, - w->colours[1], - 0x30 - ); - - set_format_arg(0, uint32, (uint32)&_filter_string); - gfx_draw_string_left_clipped( - dpi, - 1170, - gCommonFormatArgs, - w->colours[1], - w->x + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].left + 1, - w->y + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].top, - w->x + window_editor_object_selection_widgets[WIDX_FILTER_STRING_BUTTON].right - );*/ - // Draw sort button text widget = &w->widgets[WIDX_LIST_SORT_TYPE]; if (widget->type != WWT_EMPTY) { @@ -1329,9 +1321,11 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf gfx_draw_string_left_clipped(dpi, STR_OBJECTS_SORT_RIDE, &stringId, w->colours[1], w->x + widget->left + 1, w->y + widget->top + 1, widget->right - widget->left); } - if (w->selected_list_item == -1 || stex_entry == NULL) + if (w->selected_list_item == -1 || _loadedObject == NULL) return; + list_item *listItem = &_listItems[w->selected_list_item]; + highlightedEntry = w->object_entry; type = highlightedEntry->flags & 0x0F; @@ -1339,53 +1333,21 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf widget = &w->widgets[WIDX_PREVIEW]; x = w->x + (widget->left + widget->right) / 2 + 1; y = w->y + (widget->top + widget->bottom) / 2 + 1; - object_paint(type, stex_entry, dpi, x, y); + // object_paint(type, stex_entry, dpi, x, y); // Draw name of object x = w->x + (widget->left + widget->right) / 2 + 1; y = w->y + widget->bottom + 3; width = w->width - w->widgets[WIDX_LIST].right - 6; - // Skip object dat name - text = (uint8*)(highlightedEntry + 1); - datName = (char*)text; - do { - text++; - } while (*(text - 1) != 0); - text += 4; - name = (char*)text; - RCT2_GLOBAL(0x009BC677, uint8) = 14; - stringId = STR_PLACEHOLDER; stringBuffer = (char*)language_get_string(STR_PLACEHOLDER) + 1; - if (gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER)) { - // Skip name - do { - text++; - } while (*(text - 1) != 0); - text += 4; - text += *text * 16 + 1; - text += *text * 16 + 1; - - if (RCT2_GLOBAL(text, uint32) & 0x1000000) { - strcpy(stringBuffer, name); - } else { - int eax = *text; - if (*text == 0xFF) { - eax = *(text + 1); - if (*(text + 1) == 0xFF) - eax = *(text + 2); - } - format_string(stringBuffer, eax + 2, NULL); - } - } else { - strcpy(stringBuffer, name); - } + strcpy(stringBuffer, listItem->repositoryItem->Name); gfx_draw_string_centred_clipped(dpi, stringId, NULL, 0, x, y, width); // Draw description of object - stringId = object_desc(type, stex_entry); + strcpy(stringBuffer, object_get_description(_loadedObject)); if (stringId != STR_NONE) { x = w->x + w->widgets[WIDX_LIST].right + 4; y += 15; @@ -1411,14 +1373,13 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf if (w->selected_tab == WINDOW_OBJECT_SELECTION_PAGE_RIDE_VEHICLES_ATTRACTIONS) { y = w->y + w->height - 3 - 12 - 14 - 14; - rct_ride_entry *rideType = (rct_ride_entry*)stex_entry; for (int i = 0; i < 3; i++) { - if (rideType->ride_type[i] == 255) - continue; - - stringId = 2 + rideType->ride_type[i]; - gfx_draw_string_right(dpi, stringId, NULL, 2, w->x + w->width - 5, y); - y -= 11; + uint8 rideType = listItem->repositoryItem->RideType[i]; + if (rideType != 255) { + stringId = 2 + rideType; + gfx_draw_string_right(dpi, stringId, NULL, 2, w->x + w->width - 5, y); + y -= 11; + } } } @@ -1427,7 +1388,7 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf // Draw object dat name stringId = STR_PLACEHOLDER; - strcpy(stringBuffer, datName); + strcpy(stringBuffer, path_get_filename(listItem->repositoryItem->Path)); gfx_draw_string_right(dpi, stringId, NULL, 0, w->x + w->width - 5, w->y + w->height - 3 - 12); } From 6b353346b9eeba1514b8d1b2e9ffb204cd2493f0 Mon Sep 17 00:00:00 2001 From: Ted John Date: Fri, 1 Jul 2016 20:01:31 +0100 Subject: [PATCH 047/116] read footpath objects correctly --- src/object/FootpathObject.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp index 752a8d1f0a..198d127e0e 100644 --- a/src/object/FootpathObject.cpp +++ b/src/object/FootpathObject.cpp @@ -32,12 +32,12 @@ enum OBJ_STRING_ID void FootpathObject::ReadLegacy(IStream * stream) { _legacyType.string_idx = stream->ReadValue(); - _legacyType.image = stream->ReadValue(); + _legacyType.image = stream->ReadValue(); _legacyType.bridge_image = stream->ReadValue(); _legacyType.var_0A = stream->ReadValue(); _legacyType.flags = stream->ReadValue(); _legacyType.scrolling_mode = stream->ReadValue(); - stream->Seek(1, STREAM_SEEK_BEGIN); + stream->Seek(1, STREAM_SEEK_CURRENT); GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); GetImageTable()->Read(stream); From 8ce9a66286f65b16a63881cb7f786e3633421b99 Mon Sep 17 00:00:00 2001 From: Ted John Date: Fri, 1 Jul 2016 21:01:06 +0100 Subject: [PATCH 048/116] add better object read error logging --- src/core/Path.cpp | 2 + src/object/BannerObject.cpp | 6 +-- src/object/BannerObject.h | 2 +- src/object/EntranceObject.cpp | 6 +-- src/object/EntranceObject.h | 2 +- src/object/FootpathItemObject.cpp | 6 +-- src/object/FootpathItemObject.h | 2 +- src/object/FootpathObject.cpp | 6 +-- src/object/FootpathObject.h | 2 +- src/object/ImageTable.cpp | 72 +++++++++++++++------------- src/object/ImageTable.h | 3 +- src/object/LargeSceneryObject.cpp | 6 +-- src/object/LargeSceneryObject.h | 2 +- src/object/Object.h | 21 ++++++++- src/object/ObjectFactory.cpp | 78 +++++++++++++++++++++++++++---- src/object/RideObject.cpp | 10 ++-- src/object/RideObject.h | 2 +- src/object/SceneryGroupObject.cpp | 6 +-- src/object/SceneryGroupObject.h | 2 +- src/object/SmallSceneryObject.cpp | 6 +-- src/object/SmallSceneryObject.h | 2 +- src/object/StexObject.cpp | 8 ++-- src/object/StexObject.h | 2 +- src/object/StringTable.cpp | 43 ++++++++++------- src/object/StringTable.h | 3 +- src/object/WallObject.cpp | 6 +-- src/object/WallObject.h | 2 +- src/object/WaterObject.cpp | 6 +-- src/object/WaterObject.h | 2 +- 29 files changed, 209 insertions(+), 107 deletions(-) diff --git a/src/core/Path.cpp b/src/core/Path.cpp index 65d0e8a830..234742ec36 100644 --- a/src/core/Path.cpp +++ b/src/core/Path.cpp @@ -74,6 +74,8 @@ namespace Path utf8 * GetFileNameWithoutExtension(utf8 * buffer, size_t bufferSize, const utf8 * path) { + path = GetFileName(path); + const utf8 * lastDot = nullptr; const utf8 * ch = path; for (; *ch != '\0'; ch++) diff --git a/src/object/BannerObject.cpp b/src/object/BannerObject.cpp index 2eb25d1cbc..9f3860f079 100644 --- a/src/object/BannerObject.cpp +++ b/src/object/BannerObject.cpp @@ -29,7 +29,7 @@ enum OBJ_STRING_ID OBJ_STRING_ID_NAME, }; -void BannerObject::ReadLegacy(IStream * stream) +void BannerObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { _legacyType.name = stream->ReadValue(); _legacyType.image = stream->ReadValue(); @@ -39,11 +39,11 @@ void BannerObject::ReadLegacy(IStream * stream) _legacyType.banner.price = stream->ReadValue(); _legacyType.banner.scenery_tab_id = stream->ReadValue(); - GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); - GetImageTable()->Read(stream); + GetImageTable()->Read(context, stream); } void BannerObject::Load() diff --git a/src/object/BannerObject.h b/src/object/BannerObject.h index dfc4bd1558..ef4d417543 100644 --- a/src/object/BannerObject.h +++ b/src/object/BannerObject.h @@ -34,7 +34,7 @@ public: void * GetLegacyData() override { return &_legacyType; } - void ReadLegacy(IStream * stream) override; + void ReadLegacy(IReadObjectContext * context, IStream * stream) override; void Load() override; void Unload() override; diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index dc9cfcc9ab..00a41ea9fa 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -28,15 +28,15 @@ enum OBJ_STRING_ID OBJ_STRING_ID_NAME, }; -void EntranceObject::ReadLegacy(IStream * stream) +void EntranceObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { _legacyType.string_idx = stream->ReadValue(); _legacyType.image_id = stream->ReadValue(); _legacyType.scrolling_mode = stream->ReadValue(); _legacyType.text_height = stream->ReadValue(); - GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); - GetImageTable()->Read(stream); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); + GetImageTable()->Read(context, stream); } void EntranceObject::Load() diff --git a/src/object/EntranceObject.h b/src/object/EntranceObject.h index 781984cf55..bda8e873a8 100644 --- a/src/object/EntranceObject.h +++ b/src/object/EntranceObject.h @@ -33,7 +33,7 @@ public: void * GetLegacyData() override { return &_legacyType; } - void ReadLegacy(IStream * stream) override; + void ReadLegacy(IReadObjectContext * context, IStream * stream) override; void Load() override; void Unload() override; diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp index e4f2e3c6b5..f8d5a8c352 100644 --- a/src/object/FootpathItemObject.cpp +++ b/src/object/FootpathItemObject.cpp @@ -28,7 +28,7 @@ enum OBJ_STRING_ID OBJ_STRING_ID_NAME, }; -void FootpathItemObject::ReadLegacy(IStream * stream) +void FootpathItemObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { _legacyType.name = stream->ReadValue(); _legacyType.image = stream->ReadValue(); @@ -38,11 +38,11 @@ void FootpathItemObject::ReadLegacy(IStream * stream) _legacyType.path_bit.price = stream->ReadValue(); _legacyType.path_bit.scenery_tab_id = stream->ReadValue(); - GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); - GetImageTable()->Read(stream); + GetImageTable()->Read(context, stream); } void FootpathItemObject::Load() diff --git a/src/object/FootpathItemObject.h b/src/object/FootpathItemObject.h index 00f947b453..7da2cc9acb 100644 --- a/src/object/FootpathItemObject.h +++ b/src/object/FootpathItemObject.h @@ -34,7 +34,7 @@ public: void * GetLegacyData() override { return &_legacyType; } - void ReadLegacy(IStream * stream) override; + void ReadLegacy(IReadObjectContext * context, IStream * stream) override; void Load() override; void Unload() override; diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp index 198d127e0e..f5657dd46b 100644 --- a/src/object/FootpathObject.cpp +++ b/src/object/FootpathObject.cpp @@ -29,7 +29,7 @@ enum OBJ_STRING_ID OBJ_STRING_ID_NAME, }; -void FootpathObject::ReadLegacy(IStream * stream) +void FootpathObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { _legacyType.string_idx = stream->ReadValue(); _legacyType.image = stream->ReadValue(); @@ -39,8 +39,8 @@ void FootpathObject::ReadLegacy(IStream * stream) _legacyType.scrolling_mode = stream->ReadValue(); stream->Seek(1, STREAM_SEEK_CURRENT); - GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); - GetImageTable()->Read(stream); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); + GetImageTable()->Read(context, stream); } void FootpathObject::Load() diff --git a/src/object/FootpathObject.h b/src/object/FootpathObject.h index 2f6e385081..d0f9144ad2 100644 --- a/src/object/FootpathObject.h +++ b/src/object/FootpathObject.h @@ -33,7 +33,7 @@ public: void * GetLegacyData() override { return &_legacyType; } - void ReadLegacy(IStream * stream) override; + void ReadLegacy(IReadObjectContext * context, IStream * stream) override; void Load() override; void Unload() override; diff --git a/src/object/ImageTable.cpp b/src/object/ImageTable.cpp index 1b4ec16fa8..7d6ddb34b6 100644 --- a/src/object/ImageTable.cpp +++ b/src/object/ImageTable.cpp @@ -18,6 +18,7 @@ #include "../core/IStream.hpp" #include "../core/Memory.hpp" #include "ImageTable.h" +#include "Object.h" ImageTable::~ImageTable() { @@ -26,44 +27,51 @@ ImageTable::~ImageTable() _dataSize = 0; } -void ImageTable::Read(IStream * stream) +void ImageTable::Read(IReadObjectContext * context, IStream * stream) { - uint32 numImages = stream->ReadValue(); - uint32 imageDataSize = stream->ReadValue(); - - _dataSize = imageDataSize; - _data = Memory::Reallocate(_data, _dataSize); - - // Read g1 element headers - uintptr_t imageDataBase = (uintptr_t)_data; - for (uint32 i = 0; i < numImages; i++) + try { - rct_g1_element g1Element; + uint32 numImages = stream->ReadValue(); + uint32 imageDataSize = stream->ReadValue(); - uintptr_t imageDataOffset = (uintptr_t)stream->ReadValue(); - g1Element.offset = (uint8*)(imageDataBase + imageDataOffset); + _dataSize = imageDataSize; + _data = Memory::Reallocate(_data, _dataSize); - g1Element.width = stream->ReadValue(); - g1Element.height = stream->ReadValue(); - g1Element.x_offset = stream->ReadValue(); - g1Element.y_offset = stream->ReadValue(); - g1Element.flags = stream->ReadValue(); - g1Element.zoomed_offset = stream->ReadValue(); + // Read g1 element headers + uintptr_t imageDataBase = (uintptr_t)_data; + for (uint32 i = 0; i < numImages; i++) + { + rct_g1_element g1Element; - _entries.push_back(g1Element); + uintptr_t imageDataOffset = (uintptr_t)stream->ReadValue(); + g1Element.offset = (uint8*)(imageDataBase + imageDataOffset); + + g1Element.width = stream->ReadValue(); + g1Element.height = stream->ReadValue(); + g1Element.x_offset = stream->ReadValue(); + g1Element.y_offset = stream->ReadValue(); + g1Element.flags = stream->ReadValue(); + g1Element.zoomed_offset = stream->ReadValue(); + + _entries.push_back(g1Element); + } + + // Read g1 element data + size_t readBytes = (size_t)stream->TryRead(_data, _dataSize); + + // If data is shorter than expected (some custom objects are unfortunately like that) + size_t unreadBytes = _dataSize - readBytes; + if (unreadBytes > 0) + { + void * ptr = (void*)(((uintptr_t)_data) + readBytes); + Memory::Set(ptr, 0, unreadBytes); + + context->LogWarning(OBJECT_ERROR_BAD_IMAGE_TABLE, "Image table size shorter than expected."); + } } - - // Read g1 element data - size_t readBytes = (size_t)stream->TryRead(_data, _dataSize); - - // If data is shorter than expected (some custom objects are unfortunately like that) - size_t unreadBytes = _dataSize - readBytes; - if (unreadBytes > 0) + catch (Exception ex) { - void * ptr = (void*)(((uintptr_t)_data) + readBytes); - Memory::Set(ptr, 0, unreadBytes); - - Console::Error::WriteFormat("Warning: Image table size shorter than expected."); - Console::Error::WriteLine(); + context->LogError(OBJECT_ERROR_BAD_IMAGE_TABLE, "Bad image table."); + throw; } } diff --git a/src/object/ImageTable.h b/src/object/ImageTable.h index 788501cf44..4692254625 100644 --- a/src/object/ImageTable.h +++ b/src/object/ImageTable.h @@ -24,6 +24,7 @@ extern "C" #include "../drawing/drawing.h" } +interface IReadObjectContext; interface IStream; class ImageTable @@ -36,7 +37,7 @@ private: public: ~ImageTable(); - void Read(IStream * stream); + void Read(IReadObjectContext * context, IStream * stream); const rct_g1_element * GetImages() const { return _entries.data(); } uint32 GetCount() const { return _entries.size(); }; }; \ No newline at end of file diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index bc0ef75a27..48353256f3 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -35,7 +35,7 @@ LargeSceneryObject::~LargeSceneryObject() Memory::Free(_tiles); } -void LargeSceneryObject::ReadLegacy(IStream * stream) +void LargeSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { _legacyType.name = stream->ReadValue(); _legacyType.image = stream->ReadValue(); @@ -49,7 +49,7 @@ void LargeSceneryObject::ReadLegacy(IStream * stream) _legacyType.large_scenery.var_11 = stream->ReadValue(); stream->Seek(5, STREAM_SEEK_CURRENT); - GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); @@ -62,7 +62,7 @@ void LargeSceneryObject::ReadLegacy(IStream * stream) _tiles = ReadTiles(stream); - GetImageTable()->Read(stream); + GetImageTable()->Read(context, stream); } void LargeSceneryObject::Load() diff --git a/src/object/LargeSceneryObject.h b/src/object/LargeSceneryObject.h index fa4b24bfe2..70b75d3b21 100644 --- a/src/object/LargeSceneryObject.h +++ b/src/object/LargeSceneryObject.h @@ -37,7 +37,7 @@ public: void * GetLegacyData() override { return &_legacyType; } - void ReadLegacy(IStream * stream) override; + void ReadLegacy(IReadObjectContext * context, IStream * stream) override; void Load() override; void Unload() override; diff --git a/src/object/Object.h b/src/object/Object.h index 358342ac6c..88eb3b349a 100644 --- a/src/object/Object.h +++ b/src/object/Object.h @@ -28,6 +28,14 @@ extern "C" interface IStream; struct ObjectRepositoryItem; +interface IReadObjectContext +{ + virtual ~IReadObjectContext() { } + + virtual void LogWarning(uint32 code, const utf8 * text) abstract; + virtual void LogError(uint32 code, const utf8 * text) abstract; +}; + class Object { private: @@ -48,7 +56,7 @@ public: const rct_object_entry * GetObjectEntry() const { return &_objectEntry; } virtual void * GetLegacyData() abstract; - virtual void ReadLegacy(IStream * stream) abstract; + virtual void ReadLegacy(IReadObjectContext * context, IStream * stream) abstract; virtual void Load() abstract; virtual void Unload() abstract; @@ -57,3 +65,14 @@ public: virtual void SetRepositoryItem(ObjectRepositoryItem * item) const { } }; + +enum OBJECT_ERROR : uint32 +{ + OBJECT_ERROR_OK, + OBJECT_ERROR_UNKNOWN, + OBJECT_ERROR_BAD_ENCODING, + OBJECT_ERROR_INVALID_PROPERTY, + OBJECT_ERROR_BAD_STRING_TABLE, + OBJECT_ERROR_BAD_IMAGE_TABLE, + OBJECT_ERROR_UNEXPECTED_EOF, +}; diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 92169a99f9..4aa8eec4bb 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -18,6 +18,8 @@ #include "../core/FileStream.hpp" #include "../core/Memory.hpp" #include "../core/MemoryStream.h" +#include "../core/String.hpp" +#include "../core/Path.hpp" #include "BannerObject.h" #include "EntranceObject.h" #include "FootpathItemObject.h" @@ -38,6 +40,51 @@ extern "C" #include "../util/sawyercoding.h" } +class ReadObjectContext : public IReadObjectContext +{ +private: + utf8 * _objectName; + bool _wasWarning = false; + bool _wasError = false; + +public: + bool WasWarning() const { return _wasWarning; } + bool WasError() const { return _wasError; } + + ReadObjectContext(const utf8 * objectFileName) + { + _objectName = String::Duplicate(objectFileName); + } + + ~ReadObjectContext() override + { + Memory::Free(_objectName); + _objectName = nullptr; + } + + void LogWarning(uint32 code, const utf8 * text) override + { + _wasWarning = true; + + if (!String::IsNullOrEmpty(text)) + { + Console::Error::WriteFormat("[%s] Warning: %s", _objectName, text); + Console::Error::WriteLine(); + } + } + + void LogError(uint32 code, const utf8 * text) override + { + _wasError = true; + + if (!String::IsNullOrEmpty(text)) + { + Console::Error::WriteFormat("[%s] Error: %s", _objectName, text); + Console::Error::WriteLine(); + } + } +}; + namespace ObjectFactory { Object * CreateObjectFromLegacyFile(const utf8 * path) @@ -63,25 +110,40 @@ namespace ObjectFactory } else { + utf8 objectName[9] = { 0 }; + Memory::Copy(objectName, entry.name, 8); + + auto readContext = ReadObjectContext(objectName); try { bufferSize = sawyercoding_read_chunk_with_size(file, (uint8 *)buffer, bufferSize); if (bufferSize == SIZE_MAX) { - throw IOException("Error decoding data."); + readContext.LogError(OBJECT_ERROR_BAD_ENCODING, "Unable to decode chunk."); } - - buffer = Memory::Reallocate(buffer, bufferSize); - auto ms = MemoryStream(buffer, bufferSize); - result->ReadLegacy(&ms); - - Memory::Free(buffer); + else + { + buffer = Memory::Reallocate(buffer, bufferSize); + auto ms = MemoryStream(buffer, bufferSize); + result->ReadLegacy(&readContext, &ms); + } + } + catch (IOException ex) + { + // TODO check that ex is really EOF and not some other error + readContext.LogError(OBJECT_ERROR_UNEXPECTED_EOF, "Unexpectedly reached end of file."); } catch (Exception ex) { - Memory::Free(buffer); + readContext.LogError(OBJECT_ERROR_UNKNOWN, nullptr); + } + + Memory::Free(buffer); + if (readContext.WasError()) + { Console::Error::WriteFormat("Error reading object: '%s'", path); Console::Error::WriteLine(); + delete result; result = nullptr; } diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index 02572b67f2..482f66d2d2 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -43,19 +43,19 @@ RideObject::~RideObject() } } -void RideObject::ReadLegacy(IStream * stream) +void RideObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { stream->Read(&_legacyType); - GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); - GetStringTable()->Read(stream, OBJ_STRING_ID_DESCRIPTION); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_DESCRIPTION); // TODO: Move to its own function when ride construction window is merged. if (gConfigInterface.select_by_track_type) { _legacyType.enabledTrackPieces = 0xFFFFFFFFFFFFFFFF; } - GetStringTable()->Read(stream, OBJ_STRING_ID_CAPACITY); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_CAPACITY); // Read preset colours, by default there are 32 _presetColours.count = stream->ReadValue(); @@ -79,7 +79,7 @@ void RideObject::ReadLegacy(IStream * stream) _peepLoadingPositions[i] = stream->ReadArray(numPeepLoadingPositions); } - GetImageTable()->Read(stream); + GetImageTable()->Read(context, stream); } void RideObject::Load() diff --git a/src/object/RideObject.h b/src/object/RideObject.h index 171c84ea54..982907de96 100644 --- a/src/object/RideObject.h +++ b/src/object/RideObject.h @@ -36,7 +36,7 @@ public: void * GetLegacyData() override { return &_legacyType; } - void ReadLegacy(IStream * stream) override; + void ReadLegacy(IReadObjectContext * context, IStream * stream) override; void Load() override; void Unload() override; diff --git a/src/object/SceneryGroupObject.cpp b/src/object/SceneryGroupObject.cpp index d6173d4630..db06ad2c75 100644 --- a/src/object/SceneryGroupObject.cpp +++ b/src/object/SceneryGroupObject.cpp @@ -34,7 +34,7 @@ SceneryGroupObject::~SceneryGroupObject() Memory::Free(_items); } -void SceneryGroupObject::ReadLegacy(IStream * stream) +void SceneryGroupObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { _legacyType.name = stream->ReadValue(); _legacyType.image = stream->ReadValue(); @@ -45,9 +45,9 @@ void SceneryGroupObject::ReadLegacy(IStream * stream) _legacyType.pad_109 = stream->ReadValue(); _legacyType.var_10A = stream->ReadValue(); - GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); ReadItems(stream); - GetImageTable()->Read(stream); + GetImageTable()->Read(context, stream); _legacyType.var_107 = _numItems; } diff --git a/src/object/SceneryGroupObject.h b/src/object/SceneryGroupObject.h index b21685173a..230cc632e4 100644 --- a/src/object/SceneryGroupObject.h +++ b/src/object/SceneryGroupObject.h @@ -36,7 +36,7 @@ public: void * GetLegacyData() override { return &_legacyType; } - void ReadLegacy(IStream * stream) override; + void ReadLegacy(IReadObjectContext * context, IStream * stream) override; void Load() override; void Unload() override; diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index d7d3ac2ecb..d025bcd274 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -34,7 +34,7 @@ SmallSceneryObject::~SmallSceneryObject() Memory::Free(_var10data); } -void SmallSceneryObject::ReadLegacy(IStream * stream) +void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { _legacyType.name = stream->ReadValue(); _legacyType.image = stream->ReadValue(); @@ -50,7 +50,7 @@ void SmallSceneryObject::ReadLegacy(IStream * stream) _legacyType.small_scenery.var_18 = stream->ReadValue(); _legacyType.small_scenery.scenery_tab_id = 0xFF; - GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); @@ -59,7 +59,7 @@ void SmallSceneryObject::ReadLegacy(IStream * stream) _var10data = ReadVar10(stream); } - GetImageTable()->Read(stream); + GetImageTable()->Read(context, stream); } void SmallSceneryObject::Load() diff --git a/src/object/SmallSceneryObject.h b/src/object/SmallSceneryObject.h index a0bd022912..0420f70cc7 100644 --- a/src/object/SmallSceneryObject.h +++ b/src/object/SmallSceneryObject.h @@ -36,7 +36,7 @@ public: void * GetLegacyData() override { return &_legacyType; } - void ReadLegacy(IStream * stream) override; + void ReadLegacy(IReadObjectContext * context, IStream * stream) override; void Load() override; void Unload() override; diff --git a/src/object/StexObject.cpp b/src/object/StexObject.cpp index a7213eeec1..a535317fb2 100644 --- a/src/object/StexObject.cpp +++ b/src/object/StexObject.cpp @@ -29,7 +29,7 @@ enum OBJ_STRING_ID OBJ_STRING_ID_SCENARIO_DETAILS, }; -void StexObject::ReadLegacy(IStream * stream) +void StexObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { _legacyType.scenario_name = stream->ReadValue(); _legacyType.park_name = stream->ReadValue(); @@ -37,9 +37,9 @@ void StexObject::ReadLegacy(IStream * stream) _legacyType.var_06 = stream->ReadValue(); stream->Seek(1, STREAM_SEEK_CURRENT); - GetStringTable()->Read(stream, OBJ_STRING_ID_SCENARIO_NAME); - GetStringTable()->Read(stream, OBJ_STRING_ID_PARK_NAME); - GetStringTable()->Read(stream, OBJ_STRING_ID_SCENARIO_DETAILS); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_SCENARIO_NAME); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_PARK_NAME); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_SCENARIO_DETAILS); } void StexObject::Load() diff --git a/src/object/StexObject.h b/src/object/StexObject.h index a5d58032e2..51e6f638f5 100644 --- a/src/object/StexObject.h +++ b/src/object/StexObject.h @@ -33,7 +33,7 @@ public: void * GetLegacyData() override { return &_legacyType; } - void ReadLegacy(IStream * stream) override; + void ReadLegacy(IReadObjectContext * context, IStream * stream) override; void Load() override; void Unload() override; diff --git a/src/object/StringTable.cpp b/src/object/StringTable.cpp index 943a960e04..0f1642d40f 100644 --- a/src/object/StringTable.cpp +++ b/src/object/StringTable.cpp @@ -18,6 +18,7 @@ #include "../core/IStream.hpp" #include "../core/String.hpp" #include "../localisation/LanguagePack.h" +#include "Object.h" #include "StringTable.h" constexpr uint8 RCT2_LANGUAGE_ID_ENGLISH_UK = 0; @@ -44,27 +45,35 @@ StringTable::~StringTable() } } -void StringTable::Read(IStream * stream, uint8 id) +void StringTable::Read(IReadObjectContext * context, IStream * stream, uint8 id) { - uint8 languageId; - while ((languageId = stream->ReadValue()) != RCT2_LANGUAGE_ID_END) + try { - StringTableEntry entry; - entry.Id = id; - entry.LanguageId = languageId; - - char * win1252 = stream->ReadString(); - if (StringIsBlank(win1252)) + uint8 languageId; + while ((languageId = stream->ReadValue()) != RCT2_LANGUAGE_ID_END) { - entry.LanguageId = RCT2_LANGUAGE_ID_BLANK; + StringTableEntry entry; + entry.Id = id; + entry.LanguageId = languageId; + + char * win1252 = stream->ReadString(); + if (StringIsBlank(win1252)) + { + entry.LanguageId = RCT2_LANGUAGE_ID_BLANK; + } + + entry.Text = win1252_to_utf8_alloc(win1252); + Memory::Free(win1252); + + String::Trim(entry.Text); + + _strings.push_back(entry); } - - entry.Text = win1252_to_utf8_alloc(win1252); - Memory::Free(win1252); - - String::Trim(entry.Text); - - _strings.push_back(entry); + } + catch (Exception ex) + { + context->LogError(OBJECT_ERROR_BAD_STRING_TABLE, "Bad string table."); + throw; } Sort(); } diff --git a/src/object/StringTable.h b/src/object/StringTable.h index 48ff2b1826..38895a4c2e 100644 --- a/src/object/StringTable.h +++ b/src/object/StringTable.h @@ -19,6 +19,7 @@ #include #include "../common.h" +interface IReadObjectContext; interface IStream; struct StringTableEntry @@ -36,7 +37,7 @@ private: public: ~StringTable(); - void Read(IStream * stream, uint8 id); + void Read(IReadObjectContext * context, IStream * stream, uint8 id); const utf8 * GetString(uint8 id) const; private: diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp index e8295adb0e..a88299dab2 100644 --- a/src/object/WallObject.cpp +++ b/src/object/WallObject.cpp @@ -29,7 +29,7 @@ enum OBJ_STRING_ID OBJ_STRING_ID_NAME, }; -void WallObject::ReadLegacy(IStream * stream) +void WallObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { _legacyType.name = stream->ReadValue(); _legacyType.image = stream->ReadValue(); @@ -42,11 +42,11 @@ void WallObject::ReadLegacy(IStream * stream) _legacyType.wall.scenery_tab_id = stream->ReadValue(); _legacyType.wall.var_0D = stream->ReadValue(); - GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); _sceneryTabEntry = stream->ReadValue(); - GetImageTable()->Read(stream); + GetImageTable()->Read(context, stream); } void WallObject::Load() diff --git a/src/object/WallObject.h b/src/object/WallObject.h index 5d685a5e97..6b5e9820fc 100644 --- a/src/object/WallObject.h +++ b/src/object/WallObject.h @@ -34,7 +34,7 @@ public: void * GetLegacyData() override { return &_legacyType; } - void ReadLegacy(IStream * stream) override; + void ReadLegacy(IReadObjectContext * context, IStream * stream) override; void Load() override; void Unload() override; diff --git a/src/object/WaterObject.cpp b/src/object/WaterObject.cpp index 0f6b64429f..685484d227 100644 --- a/src/object/WaterObject.cpp +++ b/src/object/WaterObject.cpp @@ -28,7 +28,7 @@ enum OBJ_STRING_ID OBJ_STRING_ID_NAME, }; -void WaterObject::ReadLegacy(IStream * stream) +void WaterObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { _legacyType.string_idx = stream->ReadValue(); _legacyType.image_id = stream->ReadValue(); @@ -36,8 +36,8 @@ void WaterObject::ReadLegacy(IStream * stream) _legacyType.var_0A = stream->ReadValue(); _legacyType.var_0E = stream->ReadValue(); - GetStringTable()->Read(stream, OBJ_STRING_ID_NAME); - GetImageTable()->Read(stream); + GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); + GetImageTable()->Read(context, stream); } void WaterObject::Load() diff --git a/src/object/WaterObject.h b/src/object/WaterObject.h index b288fc8b29..503e71bd13 100644 --- a/src/object/WaterObject.h +++ b/src/object/WaterObject.h @@ -33,7 +33,7 @@ public: void * GetLegacyData() override { return &_legacyType; } - void ReadLegacy(IStream * stream) override; + void ReadLegacy(IReadObjectContext * context, IStream * stream) override; void Load() override; void Unload() override; From 72f7f0f329c5453345c06fbf7e2e97f73e7dccf9 Mon Sep 17 00:00:00 2001 From: Ted John Date: Fri, 1 Jul 2016 21:22:18 +0100 Subject: [PATCH 049/116] refactor object factory loading --- src/core/MemoryStream.cpp | 2 +- src/core/MemoryStream.h | 2 +- src/object/ObjectFactory.cpp | 100 ++++++++++++++++++++--------------- 3 files changed, 58 insertions(+), 46 deletions(-) diff --git a/src/core/MemoryStream.cpp b/src/core/MemoryStream.cpp index 35364fab0f..785d1e5ce4 100644 --- a/src/core/MemoryStream.cpp +++ b/src/core/MemoryStream.cpp @@ -53,7 +53,7 @@ MemoryStream::MemoryStream(size_t capacity) _position = _data; } -MemoryStream::MemoryStream(void * data, size_t dataSize, MEMORY_ACCESS access) +MemoryStream::MemoryStream(void * data, size_t dataSize, uint32 access) { _access = access; _dataCapacity = dataSize; diff --git a/src/core/MemoryStream.h b/src/core/MemoryStream.h index 82a2fcfe5e..762944075b 100644 --- a/src/core/MemoryStream.h +++ b/src/core/MemoryStream.h @@ -42,7 +42,7 @@ public: MemoryStream(); MemoryStream(const MemoryStream ©); explicit MemoryStream(size_t capacity); - MemoryStream(void * data, size_t dataSize, MEMORY_ACCESS access = MEMORY_ACCESS_READ); + MemoryStream(void * data, size_t dataSize, uint32 access = MEMORY_ACCESS_READ); MemoryStream(const void * data, size_t dataSize); virtual ~MemoryStream(); diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 4aa8eec4bb..0fa7a36fdd 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -87,6 +87,47 @@ public: namespace ObjectFactory { + void ReadObjectLegacy(Object * object, IReadObjectContext * context, IStream * stream) + { + try + { + object->ReadLegacy(context, stream); + } + catch (IOException ex) + { + // TODO check that ex is really EOF and not some other error + context->LogError(OBJECT_ERROR_UNEXPECTED_EOF, "Unexpectedly reached end of file."); + } + catch (Exception ex) + { + context->LogError(OBJECT_ERROR_UNKNOWN, nullptr); + } + } + + MemoryStream * GetDecodedChunkStream(IReadObjectContext * context, SDL_RWops * file) + { + size_t bufferSize = 0x600000; + void * buffer = Memory::Allocate(bufferSize); + if (buffer == nullptr) + { + log_error("Unable to allocate data buffer."); + return nullptr; + } + + bufferSize = sawyercoding_read_chunk_with_size(file, (uint8 *)buffer, bufferSize); + if (bufferSize == SIZE_MAX) + { + context->LogError(OBJECT_ERROR_BAD_ENCODING, "Unable to decode chunk."); + Memory::Free(buffer); + return nullptr; + } + else + { + buffer = Memory::Reallocate(buffer, bufferSize); + return new MemoryStream(buffer, bufferSize, MEMORY_ACCESS_READ | MEMORY_ACCESS_OWNER); + } + } + Object * CreateObjectFromLegacyFile(const utf8 * path) { Object * result = nullptr; @@ -100,54 +141,25 @@ namespace ObjectFactory result = CreateObject(entry); if (result != nullptr) { - size_t bufferSize = 0x600000; - void * buffer = Memory::Allocate(bufferSize); - if (buffer == nullptr) + utf8 objectName[9] = { 0 }; + Memory::Copy(objectName, entry.name, 8); + + auto readContext = ReadObjectContext(objectName); + auto chunkStream = GetDecodedChunkStream(&readContext, file); + if (chunkStream != nullptr) { - log_error("Unable to allocate data buffer."); + ReadObjectLegacy(result, &readContext, chunkStream); + delete chunkStream; + } + + if (readContext.WasError()) + { + Console::Error::WriteFormat("Error reading object: '%s'", path); + Console::Error::WriteLine(); + delete result; result = nullptr; } - else - { - utf8 objectName[9] = { 0 }; - Memory::Copy(objectName, entry.name, 8); - - auto readContext = ReadObjectContext(objectName); - try - { - bufferSize = sawyercoding_read_chunk_with_size(file, (uint8 *)buffer, bufferSize); - if (bufferSize == SIZE_MAX) - { - readContext.LogError(OBJECT_ERROR_BAD_ENCODING, "Unable to decode chunk."); - } - else - { - buffer = Memory::Reallocate(buffer, bufferSize); - auto ms = MemoryStream(buffer, bufferSize); - result->ReadLegacy(&readContext, &ms); - } - } - catch (IOException ex) - { - // TODO check that ex is really EOF and not some other error - readContext.LogError(OBJECT_ERROR_UNEXPECTED_EOF, "Unexpectedly reached end of file."); - } - catch (Exception ex) - { - readContext.LogError(OBJECT_ERROR_UNKNOWN, nullptr); - } - - Memory::Free(buffer); - if (readContext.WasError()) - { - Console::Error::WriteFormat("Error reading object: '%s'", path); - Console::Error::WriteLine(); - - delete result; - result = nullptr; - } - } } } SDL_RWclose(file); From 13a560fb1d2e6391f1364ffb8bd7d4da2723de2c Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 2 Jul 2016 10:59:50 +0100 Subject: [PATCH 050/116] fix ride type sorting and add water preview --- src/object/Object.h | 3 ++ src/object/ObjectRepository.cpp | 6 +++ src/object/ObjectRepository.h | 1 + src/object/WaterObject.cpp | 9 +++++ src/object/WaterObject.h | 2 + src/windows/editor_object_selection.c | 58 +++++++++++++++++++-------- 6 files changed, 62 insertions(+), 17 deletions(-) diff --git a/src/object/Object.h b/src/object/Object.h index 88eb3b349a..4485858988 100644 --- a/src/object/Object.h +++ b/src/object/Object.h @@ -27,6 +27,7 @@ extern "C" interface IStream; struct ObjectRepositoryItem; +struct rct_drawpixelinfo; interface IReadObjectContext { @@ -60,6 +61,8 @@ public: virtual void Load() abstract; virtual void Unload() abstract; + virtual void DrawPreview(rct_drawpixelinfo * dpi) const { } + virtual uint8 GetObjectType() const { return _objectEntry.flags & 0x0F; } virtual const utf8 * GetName() const abstract; diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 1ff6a9cbe9..2b24bc1ca4 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -812,4 +812,10 @@ extern "C" return ""; } } + + void object_draw_preview(const void * object, rct_drawpixelinfo * dpi) + { + const Object * baseObject = (const Object *)object; + baseObject->DrawPreview(dpi); + } } diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 72d1692cd2..4e1aa4e402 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -83,5 +83,6 @@ void object_repository_unload(size_t itemIndex); void object_delete(void * object); const utf8 * object_get_description(const void * object); +void object_draw_preview(const void * object, rct_drawpixelinfo * dpi); #endif diff --git a/src/object/WaterObject.cpp b/src/object/WaterObject.cpp index 685484d227..461bba8129 100644 --- a/src/object/WaterObject.cpp +++ b/src/object/WaterObject.cpp @@ -59,6 +59,15 @@ void WaterObject::Unload() language_free_object_string(_legacyType.string_idx); } +void WaterObject::DrawPreview(rct_drawpixelinfo * dpi) const +{ + // Write (no image) + int x = dpi->width / 2; + int y = dpi->height / 2; + gfx_draw_string_centred(dpi, 3326, x, y, 0, nullptr); +} + + const utf8 * WaterObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); diff --git a/src/object/WaterObject.h b/src/object/WaterObject.h index 503e71bd13..2bc4deabbc 100644 --- a/src/object/WaterObject.h +++ b/src/object/WaterObject.h @@ -37,5 +37,7 @@ public: void Load() override; void Unload() override; + void DrawPreview(rct_drawpixelinfo * dpi) const override; + const utf8 * GetName() const override; }; diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 9b3172ee82..9c41226321 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -299,6 +299,8 @@ typedef struct list_item { uint8 *flags; } list_item; +static rct_string_id get_ride_type_string_id(const ObjectRepositoryItem * item); + typedef int (*sortFunc)(const void *, const void *); static int _numListItems = 0; @@ -328,8 +330,8 @@ static int visible_list_sort_ride_type(const void *rawA, const void *rawB) list_item *a = (list_item*)rawA; list_item *b = (list_item*)rawB; - const char *rideTypeA = language_get_string(2 + a->repositoryItem->RideType[0]); - const char *rideTypeB = language_get_string(2 + b->repositoryItem->RideType[0]); + const char *rideTypeA = language_get_string(get_ride_type_string_id(a->repositoryItem)); + const char *rideTypeB = language_get_string(get_ride_type_string_id(b->repositoryItem)); int result = strcmp(rideTypeA, rideTypeB); if (result != 0) return result; @@ -1331,9 +1333,16 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf // Draw preview widget = &w->widgets[WIDX_PREVIEW]; - x = w->x + (widget->left + widget->right) / 2 + 1; - y = w->y + (widget->top + widget->bottom) / 2 + 1; - // object_paint(type, stex_entry, dpi, x, y); + { + rct_drawpixelinfo clipDPI; + x = w->x + widget->left; + y = w->y + widget->top; + int width = widget->right - widget->left; + int height = widget->bottom - widget->top; + if (clip_drawpixelinfo(&clipDPI, dpi, x, y, width, height)) { + object_draw_preview(_loadedObject, &clipDPI); + } + } // Draw name of object x = w->x + (widget->left + widget->right) / 2 + 1; @@ -1372,15 +1381,9 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf // if (w->selected_tab == WINDOW_OBJECT_SELECTION_PAGE_RIDE_VEHICLES_ATTRACTIONS) { y = w->y + w->height - 3 - 12 - 14 - 14; - - for (int i = 0; i < 3; i++) { - uint8 rideType = listItem->repositoryItem->RideType[i]; - if (rideType != 255) { - stringId = 2 + rideType; - gfx_draw_string_right(dpi, stringId, NULL, 2, w->x + w->width - 5, y); - y -= 11; - } - } + stringId = get_ride_type_string_id(listItem->repositoryItem); + gfx_draw_string_right(dpi, stringId, NULL, 2, w->x + w->width - 5, y); + y -= 11; } //stringId = highlightedEntry->checksum @@ -1448,7 +1451,8 @@ static void window_editor_object_selection_scrollpaint(rct_window *w, rct_drawpi if (ridePage) { // Draw ride type - strcpy(buffer, language_get_string(2 + listItem->repositoryItem->RideType[0])); + rct_string_id rideTypeStringId = get_ride_type_string_id(listItem->repositoryItem); + strcpy(buffer, language_get_string(rideTypeStringId)); gfx_draw_string(dpi, bufferWithColour, colour, x, y); x = w->widgets[WIDX_LIST_SORT_RIDE].left - w->widgets[WIDX_LIST].left; } @@ -1897,7 +1901,7 @@ static bool filter_string(const ObjectRepositoryItem * item) return false; // Get ride type - const char *rideTypeName = language_get_string(2 + item->RideType[0]); + const char *rideTypeName = language_get_string(get_ride_type_string_id(item)); // Get object name (ride/vehicle for rides) and type name (rides only) char name_lower[MAX_PATH]; @@ -1938,7 +1942,14 @@ static bool filter_chunks(const ObjectRepositoryItem * item) return true; } else { - if (_filter_flags & (1 << (gRideCategories[item->RideType[0]] + 5))) + uint8 rideType = 0; + for (int i = 0; i < 3; i++) { + if (item->RideType[i] != 255) { + rideType = item->RideType[i]; + break; + } + } + if (_filter_flags & (1 << (gRideCategories[get_ride_type_string_id(item)] + 5))) return true; } return false; @@ -1970,3 +1981,16 @@ static void filter_update_counts() } } } + +static rct_string_id get_ride_type_string_id(const ObjectRepositoryItem * item) +{ + rct_string_id result = STR_NONE; + for (int i = 0; i < 3; i++) { + uint8 rideType = item->RideType[i]; + if (rideType != 255) { + result = 2 + rideType; + break; + } + } + return result; +} From 52c11267bcdb8d1da0c6d8c17bc6af2d75b4e977 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 2 Jul 2016 11:35:46 +0100 Subject: [PATCH 051/116] add small scenery preview --- src/object.c | 4 +-- src/object/ObjectRepository.cpp | 8 +++-- src/object/SmallSceneryObject.cpp | 53 +++++++++++++++++++++++++++++++ src/object/SmallSceneryObject.h | 2 ++ src/paint/map_element/scenery.c | 2 +- src/windows/scenery.c | 4 +-- src/windows/top_toolbar.c | 2 +- src/world/scenery.h | 4 +-- 8 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/object.c b/src/object.c index 0f0c4def05..2c6592b8e6 100644 --- a/src/object.c +++ b/src/object.c @@ -809,7 +809,7 @@ static void object_type_small_scenery_paint(void *objectEntry, rct_drawpixelinfo } gfx_draw_sprite(&clipDPI, imageId, x, y, 0); - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG10) { + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_GLASS) { imageId = sceneryEntry->image + 0x44500004; if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) { imageId |= 0x92000000; @@ -818,7 +818,7 @@ static void object_type_small_scenery_paint(void *objectEntry, rct_drawpixelinfo gfx_draw_sprite(&clipDPI, imageId, x, y, 0); } - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG8) { + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_ANIMATED_FG) { imageId = sceneryEntry->image + 4; if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) { imageId |= 0x92000000; diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 2b24bc1ca4..d700dfd18c 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -668,7 +668,9 @@ extern "C" void * object_repository_load_object(const rct_object_entry * objectEntry) { IObjectRepository * objRepository = GetObjectRepository(); - return (void *)objRepository->LoadObject(objectEntry); + Object * object = objRepository->LoadObject(objectEntry); + object->Load(); + return (void *)object; } void object_repository_unload(size_t itemIndex) @@ -791,7 +793,9 @@ extern "C" void object_delete(void * object) { - delete ((Object *)object); + Object * baseObject = (Object *)object; + baseObject->Unload(); + delete baseObject; } const utf8 * object_get_description(const void * object) diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index d025bcd274..34d3e6111d 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -15,6 +15,7 @@ #pragma endregion #include "../core/IStream.hpp" +#include "../core/Math.hpp" #include "../core/Memory.hpp" #include "SmallSceneryObject.h" @@ -89,6 +90,58 @@ void SmallSceneryObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } +void SmallSceneryObject::DrawPreview(rct_drawpixelinfo * dpi) const +{ + // rct_drawpixelinfo clipDPI; + // if (!clip_drawpixelinfo(&clipDPI, dpi, x - 56, y - 56, 112, 112)) { + // return; + // } + + uint32 flags = _legacyType.small_scenery.flags; + uint32 imageId = _legacyType.image; + if (flags & SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR) + { + imageId |= 0x20D00000; + if (flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) + { + imageId |= 0x92000000; + } + } + + int x = dpi->width / 2; + int y = (dpi->height / 2) + (_legacyType.small_scenery.height / 2); + y = Math::Min(y, dpi->height - 16); + + if ((flags & SMALL_SCENERY_FLAG_FULL_TILE) && + (flags & SMALL_SCENERY_FLAG_VOFFSET_CENTRE)) + { + y -= 12; + } + + gfx_draw_sprite(dpi, imageId, x, y, 0); + + if (_legacyType.small_scenery.flags & SMALL_SCENERY_FLAG_HAS_GLASS) + { + imageId = _legacyType.image + 0x44500004; + if (flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) + { + imageId |= 0x92000000; + } + gfx_draw_sprite(dpi, imageId, x, y, 0); + } + + if (flags & SMALL_SCENERY_FLAG_ANIMATED_FG) + { + imageId = _legacyType.image + 4; + if (flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) + { + imageId |= 0x92000000; + } + gfx_draw_sprite(dpi, imageId, x, y, 0); + } +} + + const utf8 * SmallSceneryObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); diff --git a/src/object/SmallSceneryObject.h b/src/object/SmallSceneryObject.h index 0420f70cc7..a21a447756 100644 --- a/src/object/SmallSceneryObject.h +++ b/src/object/SmallSceneryObject.h @@ -40,6 +40,8 @@ public: void Load() override; void Unload() override; + void DrawPreview(rct_drawpixelinfo * dpi) const; + const utf8 * GetName() const override; private: diff --git a/src/paint/map_element/scenery.c b/src/paint/map_element/scenery.c index 7873700b1a..474a39a66c 100644 --- a/src/paint/map_element/scenery.c +++ b/src/paint/map_element/scenery.c @@ -130,7 +130,7 @@ void scenery_paint(uint8 direction, int height, rct_map_element* mapElement) { sub_98197C(baseImageid, x_offset, y_offset, boxlength.x, boxlength.y, boxlength.z - 1, height, boxoffset.x, boxoffset.y, boxoffset.z, get_current_rotation()); } - if (entry->small_scenery.flags & SMALL_SCENERY_FLAG10) { + if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_GLASS) { if (dword_F64EB0 == 0) { // Draw translucent overlay: int image_id = (baseImageid & 0x7FFFF) + (((mapElement->properties.scenery.colour_1 & 0x1F) + 112) << 19) + 0x40000004; diff --git a/src/windows/scenery.c b/src/windows/scenery.c index dcc3b93c81..ab95070966 100644 --- a/src/windows/scenery.c +++ b/src/windows/scenery.c @@ -986,7 +986,7 @@ void window_scenery_invalidate(rct_window *w) } else if (tabSelectedSceneryId < 0x100) { sceneryEntry = get_small_scenery_entry(tabSelectedSceneryId); - if (sceneryEntry->small_scenery.flags & (SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR | SMALL_SCENERY_FLAG10)) { + if (sceneryEntry->small_scenery.flags & (SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR | SMALL_SCENERY_FLAG_HAS_GLASS)) { window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WWT_COLOURBTN; if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) @@ -1210,7 +1210,7 @@ void window_scenery_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrol gfx_draw_sprite(&clipdpi, imageId, 0x20, spriteTop, w->colours[1]); } - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG8) { + if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_ANIMATED_FG) { imageId = (sceneryEntry->image + gWindowSceneryRotation) + 4; gfx_draw_sprite(&clipdpi, imageId, 0x20, spriteTop, w->colours[1]); } diff --git a/src/windows/top_toolbar.c b/src/windows/top_toolbar.c index 7eaf2913b0..ebcc082b6b 100644 --- a/src/windows/top_toolbar.c +++ b/src/windows/top_toolbar.c @@ -910,7 +910,7 @@ static void repaint_scenery_tool_down(sint16 x, sint16 y, sint16 widgetIndex){ // If can't repaint if (!(scenery_entry->small_scenery.flags & (SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR | - SMALL_SCENERY_FLAG10))) + SMALL_SCENERY_FLAG_HAS_GLASS))) return; gGameCommandErrorTitle = STR_CANT_REPAINT_THIS; diff --git a/src/world/scenery.h b/src/world/scenery.h index 0f46018a55..5914e695b8 100644 --- a/src/world/scenery.h +++ b/src/world/scenery.h @@ -44,9 +44,9 @@ typedef enum { SMALL_SCENERY_FLAG_ANIMATED = (1 << 4), // 0x10 SMALL_SCENERY_FLAG6 = (1 << 5), // 0x20 SMALL_SCENERY_FLAG_CAN_BE_WATERED = (1 << 6), // 0x40 - SMALL_SCENERY_FLAG8 = (1 << 7), // 0x80 + SMALL_SCENERY_FLAG_ANIMATED_FG = (1 << 7), // 0x80 SMALL_SCENERY_FLAG9 = (1 << 8), // 0x100 - SMALL_SCENERY_FLAG10 = (1 << 9), // 0x200 + SMALL_SCENERY_FLAG_HAS_GLASS = (1 << 9), // 0x200 SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR = (1 << 10), // 0x400 SMALL_SCENERY_FLAG12 = (1 << 11), // 0x800 SMALL_SCENERY_FLAG13 = (1 << 12), // 0x1000 From ebcbb085d2a6f2aaeab5bc3fe3cee5cadaa210a0 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 2 Jul 2016 12:06:29 +0100 Subject: [PATCH 052/116] add ride previews --- src/object/RideObject.cpp | 14 ++++++++++++++ src/object/RideObject.h | 2 ++ src/windows/editor_object_selection.c | 6 +++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index 482f66d2d2..e665026388 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -327,6 +327,20 @@ void RideObject::Unload() gfx_object_free_images(_legacyType.images_offset, GetImageTable()->GetCount()); } +void RideObject::DrawPreview(rct_drawpixelinfo * dpi) const +{ + uint32 imageId = _legacyType.images_offset; + if (_legacyType.ride_type[0] == 0xFF) + { + imageId++; + if (_legacyType.ride_type[1] == 0xFF) + { + imageId++; + } + } + gfx_draw_sprite(dpi, imageId, 0, 0, 0); +} + const utf8 * RideObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); diff --git a/src/object/RideObject.h b/src/object/RideObject.h index 982907de96..d3f7383229 100644 --- a/src/object/RideObject.h +++ b/src/object/RideObject.h @@ -40,6 +40,8 @@ public: void Load() override; void Unload() override; + void DrawPreview(rct_drawpixelinfo * dpi) const; + const utf8 * GetName() const override; const utf8 * GetDescription() const; const utf8 * GetCapacity() const; diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 9c41226321..03392287fb 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -1335,8 +1335,8 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf widget = &w->widgets[WIDX_PREVIEW]; { rct_drawpixelinfo clipDPI; - x = w->x + widget->left; - y = w->y + widget->top; + x = w->x + widget->left + 1; + y = w->y + widget->top + 1; int width = widget->right - widget->left; int height = widget->bottom - widget->top; if (clip_drawpixelinfo(&clipDPI, dpi, x, y, width, height)) { @@ -1949,7 +1949,7 @@ static bool filter_chunks(const ObjectRepositoryItem * item) break; } } - if (_filter_flags & (1 << (gRideCategories[get_ride_type_string_id(item)] + 5))) + if (_filter_flags & (1 << (gRideCategories[rideType] + 5))) return true; } return false; From aa62c3f03f94af0e5289e45182af6714e0132e50 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 2 Jul 2016 12:29:13 +0100 Subject: [PATCH 053/116] add drawing of other object previews --- src/object/BannerObject.cpp | 10 ++++++++++ src/object/BannerObject.h | 2 ++ src/object/EntranceObject.cpp | 11 +++++++++++ src/object/EntranceObject.h | 2 ++ src/object/FootpathItemObject.cpp | 7 +++++++ src/object/FootpathItemObject.h | 2 ++ src/object/FootpathObject.cpp | 8 ++++++++ src/object/FootpathObject.h | 2 ++ src/object/LargeSceneryObject.cpp | 9 +++++++++ src/object/LargeSceneryObject.h | 2 ++ src/object/RideObject.h | 2 +- src/object/SceneryGroupObject.cpp | 9 +++++++++ src/object/SceneryGroupObject.h | 2 ++ src/object/SmallSceneryObject.h | 2 +- src/object/StexObject.cpp | 8 ++++++++ src/object/StexObject.h | 2 ++ src/object/WallObject.cpp | 28 ++++++++++++++++++++++++++++ src/object/WallObject.h | 2 ++ src/object/WaterObject.cpp | 1 - 19 files changed, 108 insertions(+), 3 deletions(-) diff --git a/src/object/BannerObject.cpp b/src/object/BannerObject.cpp index 9f3860f079..9dfd40a799 100644 --- a/src/object/BannerObject.cpp +++ b/src/object/BannerObject.cpp @@ -68,6 +68,16 @@ void BannerObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } +void BannerObject::DrawPreview(rct_drawpixelinfo * dpi) const +{ + int x = dpi->width / 2; + int y = dpi->height / 2; + + uint32 imageId = 0x20D00000 | _legacyType.image; + gfx_draw_sprite(dpi, imageId + 0, x - 12, y + 8, 0); + gfx_draw_sprite(dpi, imageId + 1, x - 12, y + 8, 0); +} + const utf8 * BannerObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); diff --git a/src/object/BannerObject.h b/src/object/BannerObject.h index ef4d417543..933816c3b9 100644 --- a/src/object/BannerObject.h +++ b/src/object/BannerObject.h @@ -38,5 +38,7 @@ public: void Load() override; void Unload() override; + void DrawPreview(rct_drawpixelinfo * dpi) const override; + const utf8 * GetName() const override; }; diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index 00a41ea9fa..b302d1fb82 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -51,6 +51,17 @@ void EntranceObject::Unload() gfx_object_free_images(_legacyType.image_id, GetImageTable()->GetCount()); } +void EntranceObject::DrawPreview(rct_drawpixelinfo * dpi) const +{ + int x = dpi->width / 2; + int y = dpi->height / 2; + + uint32 imageId = _legacyType.image_id; + gfx_draw_sprite(dpi, imageId + 1, x - 32, y + 14, 0); + gfx_draw_sprite(dpi, imageId + 0, x + 0, y + 28, 0); + gfx_draw_sprite(dpi, imageId + 2, x + 32, y + 44, 0); +} + const utf8 * EntranceObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); diff --git a/src/object/EntranceObject.h b/src/object/EntranceObject.h index bda8e873a8..be843883b8 100644 --- a/src/object/EntranceObject.h +++ b/src/object/EntranceObject.h @@ -37,5 +37,7 @@ public: void Load() override; void Unload() override; + void DrawPreview(rct_drawpixelinfo * dpi) const override; + const utf8 * GetName() const override; }; diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp index f8d5a8c352..3895133b2c 100644 --- a/src/object/FootpathItemObject.cpp +++ b/src/object/FootpathItemObject.cpp @@ -67,6 +67,13 @@ void FootpathItemObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } +void FootpathItemObject::DrawPreview(rct_drawpixelinfo * dpi) const +{ + int x = dpi->width / 2; + int y = dpi->height / 2; + gfx_draw_sprite(dpi, _legacyType.image, x - 22, y - 24, 0); +} + const utf8 * FootpathItemObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); diff --git a/src/object/FootpathItemObject.h b/src/object/FootpathItemObject.h index 7da2cc9acb..5fe3956359 100644 --- a/src/object/FootpathItemObject.h +++ b/src/object/FootpathItemObject.h @@ -38,5 +38,7 @@ public: void Load() override; void Unload() override; + void DrawPreview(rct_drawpixelinfo * dpi) const override; + const utf8 * GetName() const override; }; diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp index f5657dd46b..9d255830a5 100644 --- a/src/object/FootpathObject.cpp +++ b/src/object/FootpathObject.cpp @@ -56,6 +56,14 @@ void FootpathObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } +void FootpathObject::DrawPreview(rct_drawpixelinfo * dpi) const +{ + int x = dpi->width / 2; + int y = dpi->height / 2; + gfx_draw_sprite(dpi, _legacyType.image + 71, x - 49, y - 17, 0); + gfx_draw_sprite(dpi, _legacyType.image + 72, x + 4, y - 17, 0); +} + const utf8 * FootpathObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); diff --git a/src/object/FootpathObject.h b/src/object/FootpathObject.h index d0f9144ad2..ef4d3638a0 100644 --- a/src/object/FootpathObject.h +++ b/src/object/FootpathObject.h @@ -37,5 +37,7 @@ public: void Load() override; void Unload() override; + void DrawPreview(rct_drawpixelinfo * dpi) const override; + const utf8 * GetName() const override; }; diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index 48353256f3..2e16535fec 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -102,6 +102,15 @@ void LargeSceneryObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } +void LargeSceneryObject::DrawPreview(rct_drawpixelinfo * dpi) const +{ + int x = dpi->width / 2; + int y = (dpi->height / 2) - 39; + + uint32 imageId = 0xB2D00000 | _legacyType.image; + gfx_draw_sprite(dpi, imageId, x, y, 0); +} + const utf8 * LargeSceneryObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); diff --git a/src/object/LargeSceneryObject.h b/src/object/LargeSceneryObject.h index 70b75d3b21..708b9f09c4 100644 --- a/src/object/LargeSceneryObject.h +++ b/src/object/LargeSceneryObject.h @@ -41,6 +41,8 @@ public: void Load() override; void Unload() override; + void DrawPreview(rct_drawpixelinfo * dpi) const override; + const utf8 * GetName() const override; private: diff --git a/src/object/RideObject.h b/src/object/RideObject.h index d3f7383229..d53b9901df 100644 --- a/src/object/RideObject.h +++ b/src/object/RideObject.h @@ -40,7 +40,7 @@ public: void Load() override; void Unload() override; - void DrawPreview(rct_drawpixelinfo * dpi) const; + void DrawPreview(rct_drawpixelinfo * dpi) const override; const utf8 * GetName() const override; const utf8 * GetDescription() const; diff --git a/src/object/SceneryGroupObject.cpp b/src/object/SceneryGroupObject.cpp index db06ad2c75..800516be23 100644 --- a/src/object/SceneryGroupObject.cpp +++ b/src/object/SceneryGroupObject.cpp @@ -85,6 +85,15 @@ void SceneryGroupObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } +void SceneryGroupObject::DrawPreview(rct_drawpixelinfo * dpi) const +{ + int x = dpi->width / 2; + int y = dpi->height / 2; + + uint32 imageId = _legacyType.image + 0x20600001; + gfx_draw_sprite(dpi, imageId, x - 15, y - 14, 0); +} + const utf8 * SceneryGroupObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); diff --git a/src/object/SceneryGroupObject.h b/src/object/SceneryGroupObject.h index 230cc632e4..29a60c8ee4 100644 --- a/src/object/SceneryGroupObject.h +++ b/src/object/SceneryGroupObject.h @@ -40,6 +40,8 @@ public: void Load() override; void Unload() override; + void DrawPreview(rct_drawpixelinfo * dpi) const override; + const utf8 * GetName() const override; private: diff --git a/src/object/SmallSceneryObject.h b/src/object/SmallSceneryObject.h index a21a447756..9e87b3a2f9 100644 --- a/src/object/SmallSceneryObject.h +++ b/src/object/SmallSceneryObject.h @@ -40,7 +40,7 @@ public: void Load() override; void Unload() override; - void DrawPreview(rct_drawpixelinfo * dpi) const; + void DrawPreview(rct_drawpixelinfo * dpi) const override; const utf8 * GetName() const override; diff --git a/src/object/StexObject.cpp b/src/object/StexObject.cpp index a535317fb2..8023b25b46 100644 --- a/src/object/StexObject.cpp +++ b/src/object/StexObject.cpp @@ -56,6 +56,14 @@ void StexObject::Unload() language_free_object_string(_legacyType.details); } +void StexObject::DrawPreview(rct_drawpixelinfo * dpi) const +{ + // Write (no image) + int x = dpi->width / 2; + int y = dpi->height / 2; + gfx_draw_string_centred(dpi, 3326, x, y, 0, nullptr); +} + const utf8 * StexObject::GetName() const { return GetScenarioName(); diff --git a/src/object/StexObject.h b/src/object/StexObject.h index 51e6f638f5..6032ef5de7 100644 --- a/src/object/StexObject.h +++ b/src/object/StexObject.h @@ -37,6 +37,8 @@ public: void Load() override; void Unload() override; + void DrawPreview(rct_drawpixelinfo * dpi) const override; + const utf8 * GetName() const override; const utf8 * GetScenarioName() const; diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp index a88299dab2..352af8d84c 100644 --- a/src/object/WallObject.cpp +++ b/src/object/WallObject.cpp @@ -71,6 +71,34 @@ void WallObject::Unload() gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); } +void WallObject::DrawPreview(rct_drawpixelinfo * dpi) const +{ + int x = dpi->width / 2; + int y = dpi->height / 2; + + x += 14; + y += (_legacyType.wall.height * 2) + 16; + + uint32 imageId = 0x20D00000 | _legacyType.image; + if (_legacyType.wall.flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) + { + imageId |= 0x92000000; + } + + gfx_draw_sprite(dpi, imageId, x, y, 0); + + if (_legacyType.wall.flags & WALL_SCENERY_FLAG2) + { + imageId = _legacyType.image + 0x44500006; + gfx_draw_sprite(dpi, imageId, x, y, 0); + } + else if (_legacyType.wall.flags & WALL_SCENERY_IS_DOOR) + { + imageId++; + gfx_draw_sprite(dpi, imageId, x, y, 0); + } +} + const utf8 * WallObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); diff --git a/src/object/WallObject.h b/src/object/WallObject.h index 6b5e9820fc..51aed22c32 100644 --- a/src/object/WallObject.h +++ b/src/object/WallObject.h @@ -38,5 +38,7 @@ public: void Load() override; void Unload() override; + void DrawPreview(rct_drawpixelinfo * dpi) const override; + const utf8 * GetName() const override; }; diff --git a/src/object/WaterObject.cpp b/src/object/WaterObject.cpp index 461bba8129..cbe669a985 100644 --- a/src/object/WaterObject.cpp +++ b/src/object/WaterObject.cpp @@ -67,7 +67,6 @@ void WaterObject::DrawPreview(rct_drawpixelinfo * dpi) const gfx_draw_string_centred(dpi, 3326, x, y, 0, nullptr); } - const utf8 * WaterObject::GetName() const { const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); From 4bed693344b53133b03e69c7c113f5d10c6dcb10 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 2 Jul 2016 14:59:13 +0100 Subject: [PATCH 054/116] fix basic object selection --- src/addresses.h | 3 +- src/editor.c | 15 -- src/editor.h | 2 + src/interface/console.c | 23 -- src/windows/editor_object_selection.c | 309 +++++++++++++------------- 5 files changed, 160 insertions(+), 192 deletions(-) diff --git a/src/addresses.h b/src/addresses.h index c1e333f428..7885109865 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -99,7 +99,6 @@ #define RCT2_ADDRESS_SCENARIO_TEXT_ENTRIES 0x009ADAE4 #define RCT2_ADDRESS_INSTALLED_OBJECT_LIST 0x009ADAE8 -#define RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST 0x009ADAEC #define RCT2_ADDRESS_TOTAL_NO_IMAGES 0x009ADAF0 #define RCT2_ADDRESS_CURRENT_SOUND_DEVICE 0x009AF280 @@ -479,6 +478,8 @@ #define RCT2_ADDRESS_RUN_INTRO_TICK_PART 0x009AC319 #define RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS 0x009AC861 +#define RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST 0x009ADAEC + #define RCT2_ADDRESS_TOOL_WINDOWNUMBER 0x009DE542 #define RCT2_ADDRESS_TOOL_WINDOWCLASS 0x009DE544 #define RCT2_ADDRESS_CURRENT_TOOL 0x009DE545 diff --git a/src/editor.c b/src/editor.c index e27861d91b..b3cd7ad155 100644 --- a/src/editor.c +++ b/src/editor.c @@ -559,21 +559,6 @@ static void editor_finalise_main_view() gfx_invalidate_screen(); } -static bool editor_check_object_group_at_least_one_selected(int objectType) -{ - uint32 numObjects = gInstalledObjectsCount; - rct_object_entry *entry = gInstalledObjects; - uint8 *objectFlag = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - for (uint32 i = 0; i < numObjects; i++) { - if ((entry->flags & 0x0F) == objectType && (*objectFlag & OBJECT_SELECTION_FLAG_SELECTED)) { - return true; - } - entry = object_get_next(entry); - objectFlag++; - } - return false; -} - /** * * rct2: 0x006AB9B8 diff --git a/src/editor.h b/src/editor.h index c7b479812a..98fb324777 100644 --- a/src/editor.h +++ b/src/editor.h @@ -42,4 +42,6 @@ void editor_open_windows_for_current_step(); bool editor_check_park(); int editor_check_object_selection(); +bool editor_check_object_group_at_least_one_selected(int objectType); + #endif diff --git a/src/interface/console.c b/src/interface/console.c index 998aa73a15..80ae721210 100644 --- a/src/interface/console.c +++ b/src/interface/console.c @@ -866,29 +866,6 @@ static int cc_twitch(const utf8 **argv, int argc) return 0; } -static void editor_load_selected_objects_console() -{ - uint8 *selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - rct_object_entry *installed_entry = gInstalledObjects; - - if (gInstalledObjectsCount == 0) - return; - - for (int i = gInstalledObjectsCount; i != 0; i--, selection_flags++) { - if (*selection_flags & 1) { - uint8 entry_index, entry_type; - if (!find_object_in_entry_group(installed_entry, &entry_type, &entry_index)){ - int chunk_size; - if (!object_load_chunk(-1, installed_entry, &chunk_size)) { - log_error("Failed to load entry %.8s", installed_entry->name); - } - } - } - - installed_entry = object_get_next(installed_entry); - } -} - static int cc_load_object(const utf8 **argv, int argc) { if (argc > 0) { utf8 path[MAX_PATH]; diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 03392287fb..23f1ecf00e 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -220,11 +220,11 @@ static void window_editor_object_set_page(rct_window *w, int page); static void window_editor_object_selection_set_pressed_tab(rct_window *w); static void window_editor_object_selection_select_default_objects(); static void window_editor_object_selection_select_required_objects(); -static int window_editor_object_selection_select_object(uint8 bh, int flags, rct_object_entry *entry); +static int window_editor_object_selection_select_object(uint8 bh, int flags, const rct_object_entry *entry); static int get_object_from_object_selection(uint8 object_type, int y); static void window_editor_object_selection_manage_tracks(); static void editor_load_selected_objects(); -static bool filter_selected(uint8* objectFlags); +static bool filter_selected(uint8 objectFlags); static bool filter_string(const ObjectRepositoryItem * item); static bool filter_source(const ObjectRepositoryItem * item); static bool filter_chunks(const ObjectRepositoryItem * item); @@ -308,6 +308,10 @@ static list_item *_listItems = NULL; static int _listSortType = RIDE_SORT_TYPE; static bool _listSortDescending = false; static void * _loadedObject = NULL; +static uint8 * _objectSelectionFlags = NULL; +static int _numSelectedObjectsForType[11]; +static int _numAvailableObjectsForType[11]; +static bool _maxObjectsWasHit; static void visible_list_dispose() { @@ -349,25 +353,24 @@ static void visible_list_refresh(rct_window *w) list_item *currentListItem = &_listItems[0]; const ObjectRepositoryItem *items = object_repository_get_items(); - uint8 *itemFlags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); for (int i = 0; i < numObjects; i++) { + uint8 selectionFlags = _objectSelectionFlags[i]; const ObjectRepositoryItem * item = &items[i]; uint8 objectType = item->ObjectEntry.flags & 0x0F; - if (objectType == w->selected_tab && !(*itemFlags & OBJECT_SELECTION_FLAG_6) && + if (objectType == w->selected_tab && !(selectionFlags & OBJECT_SELECTION_FLAG_6) && filter_source(item) && filter_string(item) && filter_chunks(item) && - filter_selected(itemFlags) + filter_selected(selectionFlags) ) { rct_object_filters * filter = calloc(1, sizeof(rct_object_filters)); currentListItem->repositoryItem = item; currentListItem->entry = (rct_object_entry *)&item->ObjectEntry; currentListItem->filter = filter; - currentListItem->flags = itemFlags; + currentListItem->flags = &_objectSelectionFlags[i]; currentListItem++; _numListItems++; } - itemFlags++; } _listItems = realloc(_listItems, _numListItems * sizeof(list_item)); @@ -461,36 +464,35 @@ void window_editor_object_selection_open() static void setup_track_manager_objects() { uint8 ride_list[128] = { 0 }; - uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); int numObjects = object_repository_get_items_count(); const ObjectRepositoryItem * items = object_repository_get_items(); - for (int i = numObjects; i > 0; --i) { + for (int i = 0; i < numObjects; i++) { + uint8 * selectionFlags = &_objectSelectionFlags[i]; const ObjectRepositoryItem * item = &items[i]; uint8 object_type = item->ObjectEntry.flags & 0xF; if (object_type == OBJECT_TYPE_RIDE){ - *selection_flags |= OBJECT_SELECTION_FLAG_6; + *selectionFlags |= OBJECT_SELECTION_FLAG_6; for (uint8 j = 0; j < 3; j++) { - uint8 ride_type = item->RideType[j]; - if (ride_type == 0xFF) + uint8 rideType = item->RideType[j]; + if (rideType == 0xFF) continue; - if (!ride_type_has_flag(ride_type, RIDE_TYPE_FLAG_HAS_TRACK)) + if (!ride_type_has_flag(rideType, RIDE_TYPE_FLAG_HAS_TRACK)) continue; if (item->RideType[3] & (1 << 0)) { - *selection_flags &= ~OBJECT_SELECTION_FLAG_6; - } else if (ride_list[ride_type] & (1 << 0)) { + *selectionFlags &= ~OBJECT_SELECTION_FLAG_6; + } else if (ride_list[rideType] & (1 << 0)) { continue; } else { - ride_list[ride_type] |= (1 << 0); - *selection_flags &= ~OBJECT_SELECTION_FLAG_6; + ride_list[rideType] |= (1 << 0); + *selectionFlags &= ~OBJECT_SELECTION_FLAG_6; } break; } } - selection_flags++; } } @@ -500,28 +502,25 @@ static void setup_track_manager_objects() */ static void setup_track_designer_objects() { - uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); int numObjects = object_repository_get_items_count(); const ObjectRepositoryItem * items = object_repository_get_items(); - for (int i = numObjects; i > 0; --i) { + for (int i = 0; i < numObjects; i++) { + uint8 * selectionFlags = &_objectSelectionFlags[i]; const ObjectRepositoryItem * item = &items[i]; - uint8 object_type = item->ObjectEntry.flags & 0xF; - if (object_type == OBJECT_TYPE_RIDE){ - *selection_flags |= OBJECT_SELECTION_FLAG_6; + uint8 objectType = item->ObjectEntry.flags & 0xF; + if (objectType == OBJECT_TYPE_RIDE){ + *selectionFlags |= OBJECT_SELECTION_FLAG_6; for (uint8 j = 0; j < 3; j++) { - uint8 ride_type = item->RideType[j]; - if (ride_type == 0xFF) - continue; - - if (!(RideData4[ride_type].flags & RIDE_TYPE_FLAG4_11)) - continue; - - *selection_flags &= ~OBJECT_SELECTION_FLAG_6; - break; + uint8 rideType = item->RideType[j]; + if (rideType != 0xFF) { + if (RideData4[rideType].flags & RIDE_TYPE_FLAG4_11) { + *selectionFlags &= ~OBJECT_SELECTION_FLAG_6; + break; + } + } } } - selection_flags++; } } @@ -529,8 +528,8 @@ static void setup_track_designer_objects() * * rct2: 0x006AA82B */ -static void setup_in_use_selection_flags(){ - +static void setup_in_use_selection_flags() +{ for (uint8 object_type = 0; object_type < 11; object_type++){ for (uint16 i = 0; i < object_entry_group_counts[object_type]; i++){ RCT2_ADDRESS(0x0098DA38, uint8*)[object_type][i] = 0; @@ -601,35 +600,32 @@ static void setup_in_use_selection_flags(){ } } while (map_element_iterator_next(&iter)); - for (uint8 ride_index = 0; ride_index < 0xFF; ride_index++){ + for (uint8 ride_index = 0; ride_index < 0xFF; ride_index++) { rct_ride* ride = get_ride(ride_index); - if (ride->type == RIDE_TYPE_NULL) - continue; - - uint8 type = ride->subtype; - RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_RIDE][type] |= (1 << 0); + if (ride->type != RIDE_TYPE_NULL) { + uint8 type = ride->subtype; + RCT2_ADDRESS(0x0098DA38, uint8*)[OBJECT_TYPE_RIDE][type] |= (1 << 0); + } } - uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - int numObjects = (int)object_repository_get_items_count(); const ObjectRepositoryItem * items = object_repository_get_items(); - for (int i = numObjects; i > 0; --i) { + for (int i = 0; i < numObjects; i++) { + uint8 *selectionFlags = &_objectSelectionFlags[i]; const ObjectRepositoryItem * item = &items[i]; - *selection_flags &= ~OBJECT_SELECTION_FLAG_IN_USE; + *selectionFlags &= ~OBJECT_SELECTION_FLAG_IN_USE; - uint8 entry_type, entry_index; - if (find_object_in_entry_group(&item->ObjectEntry, &entry_type, &entry_index)) { - if (RCT2_ADDRESS(0x0098DA38, uint8*)[entry_type][entry_index] & (1 << 0)){ - *selection_flags |= + uint8 entryType, entryIndex; + if (find_object_in_entry_group(&item->ObjectEntry, &entryType, &entryIndex)) { + if (RCT2_ADDRESS(0x0098DA38, uint8*)[entryType][entryIndex] & (1 << 0)) { + *selectionFlags |= OBJECT_SELECTION_FLAG_IN_USE | OBJECT_SELECTION_FLAG_SELECTED; } - if (RCT2_ADDRESS(0x0098DA38, uint8*)[entry_type][entry_index] & (1 << 1)){ - *selection_flags |= OBJECT_SELECTION_FLAG_SELECTED; + if (RCT2_ADDRESS(0x0098DA38, uint8*)[entryType][entryIndex] & (1 << 1)) { + *selectionFlags |= OBJECT_SELECTION_FLAG_SELECTED; } } - selection_flags++; } } @@ -640,43 +636,41 @@ static void setup_in_use_selection_flags(){ static int sub_6AB211() { int numObjects = (int)object_repository_get_items_count(); - - RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) = malloc(numObjects); - - if (RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*) == NULL){ + _objectSelectionFlags = (uint8*)calloc(numObjects, sizeof(uint8)); + if (_objectSelectionFlags == NULL){ log_error("Failed to allocate memory for object flag list."); return 0; } - memset(RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*), 0, numObjects); - for (uint8 object_type = 0; object_type < 11; object_type++){ - RCT2_ADDRESS(0x00F433F7, uint16)[object_type] = 0; - RCT2_ADDRESS(0x00F433E1, uint16)[object_type] = 0; + for (uint8 objectType = 0; objectType < 11; objectType++) { + _numSelectedObjectsForType[objectType] = 0; + _numAvailableObjectsForType[objectType] = 0; } const ObjectRepositoryItem * items = object_repository_get_items(); - for (int i = numObjects; i > 0; --i) { - uint8 object_type = items[i].ObjectEntry.flags & 0xF; - RCT2_ADDRESS(0x00F433E1, uint16)[object_type]++; + for (int i = 0; i < numObjects; i++) { + uint8 objectType = items[i].ObjectEntry.flags & 0xF; + _numAvailableObjectsForType[objectType]++; } - if (gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER){ + if (gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) { setup_track_designer_objects(); } - if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER){ + if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) { setup_track_manager_objects(); } setup_in_use_selection_flags(); reset_selected_object_count_and_size(); - if (!(gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER))){ + if (!(gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER))) { window_editor_object_selection_select_required_objects(); // To prevent it breaking in scenario mode. - if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) + if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) { window_editor_object_selection_select_default_objects(); + } } reset_required_object_flags(); @@ -690,7 +684,7 @@ static int sub_6AB211() */ static void editor_object_flags_free() { - SafeFree(RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*)); + SafeFree(_objectSelectionFlags); } /** @@ -719,16 +713,13 @@ void remove_selected_objects_from_research(const rct_object_entry* installedObje */ void unload_unselected_objects() { - uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - int numItems = object_repository_get_items_count(); const ObjectRepositoryItem * items = object_repository_get_items(); - for (int i = numItems; i > 0; --i) { - if (!(*selection_flags & OBJECT_SELECTION_FLAG_SELECTED)){ + for (int i = 0; i < numItems; i++) { + if (!(_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED)) { remove_selected_objects_from_research(&items[i].ObjectEntry); object_repository_unload(i); } - selection_flags++; } } @@ -1008,7 +999,7 @@ static void window_editor_object_selection_scroll_mousedown(rct_window *w, int s if (!(object_selection_flags & OBJECT_SELECTION_FLAG_SELECTED)) ebx = 7; - RCT2_GLOBAL(0xF43411, uint8) = 0; + _maxObjectsWasHit = false; if (!window_editor_object_selection_select_object(0, ebx, listItem->entry)) { rct_string_id error_title = ebx & 1 ? STR_UNABLE_TO_SELECT_THIS_OBJECT : @@ -1024,10 +1015,9 @@ static void window_editor_object_selection_scroll_mousedown(rct_window *w, int s window_invalidate(w); } - if (!RCT2_GLOBAL(0xF43411, uint8) & 1) - return; - - window_error_open(STR_WARNING_TOO_MANY_OBJECTS_SELECTED, STR_NOT_ALL_OBJECTS_IN_THIS_SCENERY_GROUP_COULD_BE_SELECTED); + if (_maxObjectsWasHit) { + window_error_open(STR_WARNING_TOO_MANY_OBJECTS_SELECTED, STR_NOT_ALL_OBJECTS_IN_THIS_SCENERY_GROUP_COULD_BE_SELECTED); + } } /** @@ -1299,7 +1289,7 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf x = w->x + 3; y = w->y + w->height - 13; - numSelected = RCT2_ADDRESS(0x00F433F7, uint16)[w->selected_tab]; + numSelected = _numSelectedObjectsForType[w->selected_tab]; totalSelectable = object_entry_group_counts[w->selected_tab]; if (gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) totalSelectable = 4; @@ -1508,13 +1498,11 @@ static void window_editor_object_selection_set_pressed_tab(rct_window *w) */ static void window_editor_object_selection_select_default_objects() { - int i; - - if (RCT2_GLOBAL(0x00F433F7, uint16) != 0) - return; - - for (i = 0; i < countof(DefaultSelectedObjects); i++) - window_editor_object_selection_select_object(0, 7, &DefaultSelectedObjects[i]); + if (_numSelectedObjectsForType[0] == 0) { + for (int i = 0; i < countof(DefaultSelectedObjects); i++) { + window_editor_object_selection_select_object(0, 7, &DefaultSelectedObjects[i]); + } + } } /** @@ -1535,8 +1523,17 @@ static void window_editor_object_selection_select_required_objects() */ void reset_selected_object_count_and_size() { - for (uint8 object_type = 0; object_type < 11; object_type++) { - RCT2_ADDRESS(0x00F433F7, uint16)[object_type] = 0; + for (uint8 objectType = 0; objectType < 11; objectType++) { + _numSelectedObjectsForType[objectType] = 0; + } + + int numObjects = (int)object_repository_get_items_count(); + const ObjectRepositoryItem * items = object_repository_get_items(); + for (int i = 0; i < numObjects; i++) { + uint8 objectType = items[i].ObjectEntry.flags & 0xF; + if (_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED) { + _numSelectedObjectsForType[objectType]++; + } } } @@ -1546,21 +1543,19 @@ void reset_selected_object_count_and_size() */ void set_required_object_flags(rct_object_entry* required_object) { - uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); int numObjects = (int)object_repository_get_items_count(); const ObjectRepositoryItem * items = object_repository_get_items(); - for (int i = numObjects; i > 0; --i) { + for (int i = 0; i < numObjects; i++) { const ObjectRepositoryItem * item = &items[i]; if (object_entry_compare(required_object, &item->ObjectEntry)) { - *selection_flags |= OBJECT_SELECTION_FLAG_REQUIRED; + _objectSelectionFlags[i] |= OBJECT_SELECTION_FLAG_REQUIRED; - uint16 no_required_objects = item->NumRequiredObjects; - for (; no_required_objects > 0; no_required_objects--) { - set_required_object_flags(&item->RequiredObjects[i]); + uint16 numRequiredObjects = item->NumRequiredObjects; + for (uint16 j = 0; j < numRequiredObjects; j++) { + set_required_object_flags(&item->RequiredObjects[j]); } - return; + break; } - selection_flags++; } } @@ -1573,24 +1568,19 @@ void reset_required_object_flags() int numObjects = (int)object_repository_get_items_count(); const ObjectRepositoryItem * items = object_repository_get_items(); - uint8* selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - for (int i = numObjects; i > 0; --i) { - *selection_flags &= ~OBJECT_SELECTION_FLAG_REQUIRED; - selection_flags++; + for (int i = 0; i < numObjects; i++) { + _objectSelectionFlags[i] &= ~OBJECT_SELECTION_FLAG_REQUIRED; } - selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - - for (int i = numObjects; i > 0; --i){ + for (int i = 0; i < numObjects; i++) { const ObjectRepositoryItem * item = &items[i]; - if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED){ - uint16 no_required_objects = item->NumRequiredObjects; - for (; no_required_objects > 0; no_required_objects--){ - set_required_object_flags(&item->RequiredObjects[i]); + + if (_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED) { + uint16 numRequiredObjects = item->NumRequiredObjects; + for (uint16 j = 0; j < numRequiredObjects; j++) { + set_required_object_flags(&item->RequiredObjects[j]); } } - - selection_flags++; } } @@ -1610,7 +1600,7 @@ void set_object_selection_error(uint8 is_master_object, rct_string_id error_msg) * * rct2: 0x006AB54F */ -static int window_editor_object_selection_select_object(uint8 bh, int flags, rct_object_entry *entry) +static int window_editor_object_selection_select_object(uint8 bh, int flags, const rct_object_entry *entry) { int numObjects = (int)object_repository_get_items_count(); const ObjectRepositoryItem * item = object_repository_find_object_by_entry(entry); @@ -1619,29 +1609,33 @@ static int window_editor_object_selection_select_object(uint8 bh, int flags, rct return 0; } - uint8 * selection_flags; - selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - for (int i = numObjects; i > 0; --i) { - selection_flags++; + // Get repository item index + int index = -1; + const ObjectRepositoryItem * items = object_repository_get_items(); + for (int i = 0; i < numObjects; i++) { + if (&items[i] == item) { + index = i; + } } - if (!(flags & 1)){ - if (!(*selection_flags & OBJECT_SELECTION_FLAG_SELECTED)) + uint8 * selectionFlags = &_objectSelectionFlags[index]; + if (!(flags & 1)) { + if (!(*selectionFlags & OBJECT_SELECTION_FLAG_SELECTED)) { if (bh == 0){ reset_required_object_flags(); } return 1; } - else if (*selection_flags & OBJECT_SELECTION_FLAG_IN_USE){ + else if (*selectionFlags & OBJECT_SELECTION_FLAG_IN_USE){ set_object_selection_error(bh, 3173); return 0; } - else if (*selection_flags & OBJECT_SELECTION_FLAG_REQUIRED){ + else if (*selectionFlags & OBJECT_SELECTION_FLAG_REQUIRED){ set_object_selection_error(bh, 3174); return 0; } - else if (*selection_flags & OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED){ + else if (*selectionFlags & OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED){ set_object_selection_error(bh, 3175); return 0; } @@ -1655,9 +1649,9 @@ static int window_editor_object_selection_select_object(uint8 bh, int flags, rct } } - uint8 object_type = item->ObjectEntry.flags & 0xF; - RCT2_ADDRESS(0x00F433F7, uint16)[object_type]--; - *selection_flags &= ~OBJECT_SELECTION_FLAG_SELECTED; + uint8 objectType = item->ObjectEntry.flags & 0xF; + _numSelectedObjectsForType[objectType]--; + *selectionFlags &= ~OBJECT_SELECTION_FLAG_SELECTED; if (bh == 0) { reset_required_object_flags(); } @@ -1665,48 +1659,44 @@ static int window_editor_object_selection_select_object(uint8 bh, int flags, rct } else { if (bh == 0) { if (flags & (1 << 3)) { - *selection_flags |= OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED; + *selectionFlags |= OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED; } } - if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED) { + if (*selectionFlags & OBJECT_SELECTION_FLAG_SELECTED) { if (bh == 0) { reset_required_object_flags(); } return 1; } - uint8 object_type = item->ObjectEntry.flags & 0xF; - uint16 no_objects = object_entry_group_counts[object_type]; + uint8 objectType = item->ObjectEntry.flags & 0xF; + uint16 maxObjects = object_entry_group_counts[objectType]; if (gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) { - no_objects = 4; + maxObjects = 4; } - if (no_objects <= RCT2_ADDRESS(0x00F433F7, uint16)[object_type]) { + if (maxObjects <= _numSelectedObjectsForType[objectType]) { set_object_selection_error(bh, 3171); return 0; } - uint16 numRequiredObjects = item->NumRequiredObjects; - rct_object_entry * required_objects = item->RequiredObjects; - for (; numRequiredObjects != 0; numRequiredObjects--) { - if (!window_editor_object_selection_select_object(++bh, flags, required_objects)) { + for (uint16 j = 0; j < item->NumRequiredObjects; j++) { + if (!window_editor_object_selection_select_object(++bh, flags, &item->RequiredObjects[j])) { if (bh != 0) { reset_selected_object_count_and_size(); } return 0; } - required_objects++; } - uint16 numThemeObjects = item->NumThemeObjects; - rct_object_entry * theme_object = item->RequiredObjects; - for (; numThemeObjects != 0; numThemeObjects--) { - if (flags & (1 << 2)) { - if (!window_editor_object_selection_select_object(++bh, flags, theme_object)) { - RCT2_GLOBAL(0x00F43411, uint8) |= 1; + if (objectType == OBJECT_TYPE_SCENERY_SETS) { + for (uint16 j = 0; j < item->NumThemeObjects; j++) { + if (flags & (1 << 2)) { + if (!window_editor_object_selection_select_object(++bh, flags, &item->ThemeObjects[j])) { + _maxObjectsWasHit = true; + } } } - theme_object++; } if (bh != 0 && !(flags & (1 << 1))) { @@ -1716,14 +1706,14 @@ static int window_editor_object_selection_select_object(uint8 bh, int flags, rct return 0; } - if (no_objects <= RCT2_ADDRESS(0x00F433F7, uint16)[object_type]) { + if (maxObjects <= _numSelectedObjectsForType[objectType]) { set_object_selection_error(bh, 3171); return 0; } - RCT2_ADDRESS(0x00F433F7, uint16)[object_type]++; + _numSelectedObjectsForType[objectType]++; - *selection_flags |= OBJECT_SELECTION_FLAG_SELECTED; + *selectionFlags |= OBJECT_SELECTION_FLAG_SELECTED; if (bh == 0) { reset_required_object_flags(); } @@ -1798,12 +1788,10 @@ static void window_editor_object_selection_manage_tracks() */ static void editor_load_selected_objects() { - uint8 *selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); - int numObjects = (int)object_repository_get_items_count(); const ObjectRepositoryItem * items = object_repository_get_items(); - for (int i = numObjects; i != 0; i--, selection_flags++) { - if (*selection_flags & OBJECT_SELECTION_FLAG_SELECTED) { + for (int i = 0; i < numObjects; i++) { + if (_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED) { uint8 entry_index, entry_type; if (!find_object_in_entry_group(&items[i].ObjectEntry, &entry_type, &entry_index)) { int chunk_size; @@ -1874,14 +1862,15 @@ static void window_editor_object_selection_textinput(rct_window *w, int widgetIn window_invalidate(w); } -static bool filter_selected(uint8* objectFlag) { +static bool filter_selected(uint8 objectFlag) +{ if (_FILTER_SELECTED == _FILTER_NONSELECTED) { return true; } - if (_FILTER_SELECTED && *objectFlag & OBJECT_SELECTION_FLAG_SELECTED) { + if (_FILTER_SELECTED && objectFlag & OBJECT_SELECTION_FLAG_SELECTED) { return true; } - else if (_FILTER_NONSELECTED && !(*objectFlag & OBJECT_SELECTION_FLAG_SELECTED)) { + else if (_FILTER_NONSELECTED && !(objectFlag & OBJECT_SELECTION_FLAG_SELECTED)) { return true; } else { @@ -1960,7 +1949,7 @@ static bool filter_chunks(const ObjectRepositoryItem * item) static void filter_update_counts() { if (!_FILTER_ALL || strlen(_filter_string) > 0) { - uint8 *objectFlag = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*); + uint8 *selectionFlags = _objectSelectionFlags; for (int i = 0; i < 11; i++) { _filter_object_counts[i] = 0; } @@ -1972,12 +1961,12 @@ static void filter_update_counts() if (filter_source(item) && filter_string(item) && filter_chunks(item) && - filter_selected(objectFlag) + filter_selected(*selectionFlags) ) { uint8 objectType = item->ObjectEntry.flags & 0xF; _filter_object_counts[objectType]++; } - objectFlag++; + selectionFlags++; } } } @@ -1994,3 +1983,17 @@ static rct_string_id get_ride_type_string_id(const ObjectRepositoryItem * item) } return result; } + +bool editor_check_object_group_at_least_one_selected(int objectType) +{ + int numObjects = (int)object_repository_get_items_count(); + const ObjectRepositoryItem * items = object_repository_get_items(); + + for (int i = 0; i < numObjects; i++) { + uint8 objectType = items[i].ObjectEntry.flags & 0x0F; + if (objectType == objectType && (_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED)) { + return true; + } + } + return false; +} From 7e1f948e1961a50c1f9f1a0d600d1ee4ac4ab266 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 2 Jul 2016 16:52:44 +0100 Subject: [PATCH 055/116] remove required flag (unused) and fix scenery selection --- src/object.h | 2 +- src/object/ObjectRepository.cpp | 17 +---- src/object/ObjectRepository.h | 2 - src/object/SceneryGroupObject.cpp | 13 ++++ src/object/SceneryGroupObject.h | 4 ++ src/windows/editor_object_selection.c | 100 +++----------------------- 6 files changed, 29 insertions(+), 109 deletions(-) diff --git a/src/object.h b/src/object.h index 8c154b410d..8d4177e6d2 100644 --- a/src/object.h +++ b/src/object.h @@ -40,7 +40,7 @@ typedef enum{ OBJECT_SELECTION_FLAG_SELECTED = (1 << 0), OBJECT_SELECTION_FLAG_2 = (1 << 1), OBJECT_SELECTION_FLAG_IN_USE = (1 << 2), - OBJECT_SELECTION_FLAG_REQUIRED = (1 << 3), + // OBJECT_SELECTION_FLAG_REQUIRED = (1 << 3), // Unused feature OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED = (1 << 4), OBJECT_SELECTION_FLAG_6 = (1 << 5), OBJECT_SELECTION_FLAG_7 = (1 << 6), diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index d700dfd18c..95e00a5090 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -44,7 +44,7 @@ extern "C" #include "../util/sawyercoding.h" } -constexpr uint16 OBJECT_REPOSITORY_VERSION = 6; +constexpr uint16 OBJECT_REPOSITORY_VERSION = 7; struct ObjectRepositoryHeader { @@ -391,13 +391,6 @@ private: item.NumImages = stream->ReadValue(); item.Name = stream->ReadString(); item.ChunkSize = stream->ReadValue(); - item.NumRequiredObjects = stream->ReadValue(); - - item.RequiredObjects = Memory::AllocateArray(item.NumRequiredObjects); - for (uint16 i = 0; i < item.NumRequiredObjects; i++) - { - item.RequiredObjects[i] = stream->ReadValue(); - } switch (item.ObjectEntry.flags & 0x0F) { case OBJECT_TYPE_RIDE: @@ -430,12 +423,6 @@ private: stream->WriteValue(item.NumImages); stream->WriteString(item.Name); stream->WriteValue(item.ChunkSize); - - stream->WriteValue(item.NumRequiredObjects); - for (uint16 i = 0; i < item.NumRequiredObjects; i++) - { - stream->WriteValue(item.RequiredObjects[i]); - } switch (item.ObjectEntry.flags & 0x0F) { case OBJECT_TYPE_RIDE: @@ -463,11 +450,9 @@ private: { Memory::Free(item->Path); Memory::Free(item->Name); - Memory::Free(item->RequiredObjects); Memory::Free(item->ThemeObjects); item->Path = nullptr; item->Name = nullptr; - item->RequiredObjects = nullptr; item->ThemeObjects = nullptr; } diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 4e1aa4e402..d35bff222c 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -34,8 +34,6 @@ typedef struct ObjectRepositoryItem uint32 NumImages; utf8 * Name; size_t ChunkSize; - uint16 NumRequiredObjects; - rct_object_entry * RequiredObjects; union { struct diff --git a/src/object/SceneryGroupObject.cpp b/src/object/SceneryGroupObject.cpp index 800516be23..c2d1094867 100644 --- a/src/object/SceneryGroupObject.cpp +++ b/src/object/SceneryGroupObject.cpp @@ -16,6 +16,7 @@ #include "../core/IStream.hpp" #include "../core/Memory.hpp" +#include "ObjectRepository.h" #include "SceneryGroupObject.h" extern "C" @@ -100,6 +101,18 @@ const utf8 * SceneryGroupObject::GetName() const return name != nullptr ? name : ""; } +void SceneryGroupObject::SetRepositoryItem(ObjectRepositoryItem * item) const +{ + Memory::Free(item->ThemeObjects); + + item->NumThemeObjects = _numItems; + item->ThemeObjects = Memory::AllocateArray(_numItems); + for (uint32 i = 0; i < _numItems; i++) + { + item->ThemeObjects[i] = _items[i]; + } +} + void SceneryGroupObject::ReadItems(IStream * stream) { auto items = std::vector(); diff --git a/src/object/SceneryGroupObject.h b/src/object/SceneryGroupObject.h index 29a60c8ee4..f2867bdc1b 100644 --- a/src/object/SceneryGroupObject.h +++ b/src/object/SceneryGroupObject.h @@ -23,6 +23,8 @@ extern "C" #include "../world/scenery.h" } +struct ObjectRepositoryItem; + class SceneryGroupObject : public Object { private: @@ -44,6 +46,8 @@ public: const utf8 * GetName() const override; + void SetRepositoryItem(ObjectRepositoryItem * item) const override; + private: void ReadItems(IStream * stream); }; diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 23f1ecf00e..bee24b36dc 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -231,7 +231,6 @@ static bool filter_chunks(const ObjectRepositoryItem * item); static void filter_update_counts(); void reset_selected_object_count_and_size(); -void reset_required_object_flags(); static int sub_6AB211(); static rct_object_entry RequiredSelectedObjects[] = { @@ -673,7 +672,6 @@ static int sub_6AB211() } } - reset_required_object_flags(); reset_selected_object_count_and_size(); return 1; } @@ -1420,7 +1418,7 @@ static void window_editor_object_selection_scrollpaint(rct_window *w, rct_drawpi x = 2; gCurrentFontSpriteBase = colour == 14 ? -2 : -1; colour2 = w->colours[1] & 0x7F; - if (*listItem->flags & (OBJECT_SELECTION_FLAG_IN_USE | OBJECT_SELECTION_FLAG_REQUIRED | OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED)) + if (*listItem->flags & (OBJECT_SELECTION_FLAG_IN_USE | OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED)) colour2 |= 0x40; gfx_draw_string(dpi, (char*)CheckBoxMarkString, colour2, x, y); @@ -1537,53 +1535,6 @@ void reset_selected_object_count_and_size() } } -/** - * - * rct2: 0x006AB863 - */ -void set_required_object_flags(rct_object_entry* required_object) -{ - int numObjects = (int)object_repository_get_items_count(); - const ObjectRepositoryItem * items = object_repository_get_items(); - for (int i = 0; i < numObjects; i++) { - const ObjectRepositoryItem * item = &items[i]; - if (object_entry_compare(required_object, &item->ObjectEntry)) { - _objectSelectionFlags[i] |= OBJECT_SELECTION_FLAG_REQUIRED; - - uint16 numRequiredObjects = item->NumRequiredObjects; - for (uint16 j = 0; j < numRequiredObjects; j++) { - set_required_object_flags(&item->RequiredObjects[j]); - } - break; - } - } -} - -/** - * - * rct2: 0x006AB923 - */ -void reset_required_object_flags() -{ - int numObjects = (int)object_repository_get_items_count(); - const ObjectRepositoryItem * items = object_repository_get_items(); - - for (int i = 0; i < numObjects; i++) { - _objectSelectionFlags[i] &= ~OBJECT_SELECTION_FLAG_REQUIRED; - } - - for (int i = 0; i < numObjects; i++) { - const ObjectRepositoryItem * item = &items[i]; - - if (_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED) { - uint16 numRequiredObjects = item->NumRequiredObjects; - for (uint16 j = 0; j < numRequiredObjects; j++) { - set_required_object_flags(&item->RequiredObjects[j]); - } - } - } -} - /** * Master objects are objects that are not * optional / required dependants of an @@ -1620,41 +1571,27 @@ static int window_editor_object_selection_select_object(uint8 bh, int flags, con uint8 * selectionFlags = &_objectSelectionFlags[index]; if (!(flags & 1)) { - if (!(*selectionFlags & OBJECT_SELECTION_FLAG_SELECTED)) - { - if (bh == 0){ - reset_required_object_flags(); - } + if (!(*selectionFlags & OBJECT_SELECTION_FLAG_SELECTED)) { return 1; } - else if (*selectionFlags & OBJECT_SELECTION_FLAG_IN_USE){ + else if (*selectionFlags & OBJECT_SELECTION_FLAG_IN_USE) { set_object_selection_error(bh, 3173); return 0; } - else if (*selectionFlags & OBJECT_SELECTION_FLAG_REQUIRED){ - set_object_selection_error(bh, 3174); - return 0; - } - else if (*selectionFlags & OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED){ + else if (*selectionFlags & OBJECT_SELECTION_FLAG_ALWAYS_REQUIRED) { set_object_selection_error(bh, 3175); return 0; } - uint16 numThemeObjects = item->NumThemeObjects; - if (numThemeObjects != 0 && flags & (1 << 2)) { - rct_object_entry* theme_object = item->ThemeObjects; - for (; numThemeObjects > 0; numThemeObjects--) { - window_editor_object_selection_select_object(++bh, flags, theme_object); - theme_object++; + if (flags & (1 << 2)) { + for (int j = 0; j < item->NumThemeObjects; j++) { + window_editor_object_selection_select_object(++bh, flags, &item->ThemeObjects[j]); } } uint8 objectType = item->ObjectEntry.flags & 0xF; _numSelectedObjectsForType[objectType]--; *selectionFlags &= ~OBJECT_SELECTION_FLAG_SELECTED; - if (bh == 0) { - reset_required_object_flags(); - } return 1; } else { if (bh == 0) { @@ -1663,9 +1600,6 @@ static int window_editor_object_selection_select_object(uint8 bh, int flags, con } } if (*selectionFlags & OBJECT_SELECTION_FLAG_SELECTED) { - if (bh == 0) { - reset_required_object_flags(); - } return 1; } @@ -1680,21 +1614,10 @@ static int window_editor_object_selection_select_object(uint8 bh, int flags, con return 0; } - for (uint16 j = 0; j < item->NumRequiredObjects; j++) { - if (!window_editor_object_selection_select_object(++bh, flags, &item->RequiredObjects[j])) { - if (bh != 0) { - reset_selected_object_count_and_size(); - } - return 0; - } - } - - if (objectType == OBJECT_TYPE_SCENERY_SETS) { + if (objectType == OBJECT_TYPE_SCENERY_SETS && (flags & (1 << 2))) { for (uint16 j = 0; j < item->NumThemeObjects; j++) { - if (flags & (1 << 2)) { - if (!window_editor_object_selection_select_object(++bh, flags, &item->ThemeObjects[j])) { - _maxObjectsWasHit = true; - } + if (!window_editor_object_selection_select_object(++bh, flags, &item->ThemeObjects[j])) { + _maxObjectsWasHit = true; } } } @@ -1714,9 +1637,6 @@ static int window_editor_object_selection_select_object(uint8 bh, int flags, con _numSelectedObjectsForType[objectType]++; *selectionFlags |= OBJECT_SELECTION_FLAG_SELECTED; - if (bh == 0) { - reset_required_object_flags(); - } return 1; } } From 2cade7dd13c851e2c90ed5bad048534162b31e52 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 2 Jul 2016 17:23:06 +0100 Subject: [PATCH 056/116] add object property validation --- src/object/BannerObject.cpp | 6 ++++++ src/object/FootpathItemObject.cpp | 6 ++++++ src/object/FootpathObject.cpp | 6 ++++++ src/object/LargeSceneryObject.cpp | 15 +++++++++++++++ src/object/RideObject.cpp | 14 ++++++++++++++ src/object/SmallSceneryObject.cpp | 15 +++++++++++++++ src/object/WallObject.cpp | 6 ++++++ 7 files changed, 68 insertions(+) diff --git a/src/object/BannerObject.cpp b/src/object/BannerObject.cpp index 9dfd40a799..c4cba5beaf 100644 --- a/src/object/BannerObject.cpp +++ b/src/object/BannerObject.cpp @@ -44,6 +44,12 @@ void BannerObject::ReadLegacy(IReadObjectContext * context, IStream * stream) _sceneryTabEntry = stream->ReadValue(); GetImageTable()->Read(context, stream); + + // Validate properties + if (_legacyType.large_scenery.price <= 0) + { + context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Price can not be free or negative."); + } } void BannerObject::Load() diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp index 3895133b2c..48f2916424 100644 --- a/src/object/FootpathItemObject.cpp +++ b/src/object/FootpathItemObject.cpp @@ -43,6 +43,12 @@ void FootpathItemObject::ReadLegacy(IReadObjectContext * context, IStream * stre _sceneryTabEntry = stream->ReadValue(); GetImageTable()->Read(context, stream); + + // Validate properties + if (_legacyType.large_scenery.price <= 0) + { + context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Price can not be free or negative."); + } } void FootpathItemObject::Load() diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp index 9d255830a5..2580f42f01 100644 --- a/src/object/FootpathObject.cpp +++ b/src/object/FootpathObject.cpp @@ -41,6 +41,12 @@ void FootpathObject::ReadLegacy(IReadObjectContext * context, IStream * stream) GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); GetImageTable()->Read(context, stream); + + // Validate properties + if (_legacyType.var_0A > 1) + { + context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "VAR_0A can not be greater than 1."); + } } void FootpathObject::Load() diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index 2e16535fec..cefb6828da 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -63,6 +63,21 @@ void LargeSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre _tiles = ReadTiles(stream); GetImageTable()->Read(context, stream); + + // Validate properties + if (_legacyType.large_scenery.price <= 0) + { + context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Price can not be free or negative."); + } + if (_legacyType.large_scenery.removal_price <= 0) + { + // Make sure you don't make a profit when placing then removing. + money16 reimbursement = _legacyType.large_scenery.removal_price; + if (reimbursement > _legacyType.large_scenery.price) + { + context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Sell price can not be more than buy price."); + } + } } void LargeSceneryObject::Load() diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index e665026388..f09304c610 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -80,6 +80,20 @@ void RideObject::ReadLegacy(IReadObjectContext * context, IStream * stream) } GetImageTable()->Read(context, stream); + + // Validate properties + if (_legacyType.excitement_multipler > 75) + { + context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Excitement multiplier too high."); + } + if (_legacyType.intensity_multipler > 75) + { + context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Intensity multiplier too high."); + } + if (_legacyType.nausea_multipler > 75) + { + context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Nausea multiplier too high."); + } } void RideObject::Load() diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index 34d3e6111d..13133cf1d2 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -61,6 +61,21 @@ void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre } GetImageTable()->Read(context, stream); + + // Validate properties + if (_legacyType.small_scenery.price <= 0) + { + context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Price can not be free or negative."); + } + if (_legacyType.small_scenery.removal_price <= 0) + { + // Make sure you don't make a profit when placing then removing. + money16 reimbursement = _legacyType.small_scenery.removal_price; + if (reimbursement > _legacyType.small_scenery.price) + { + context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Sell price can not be more than buy price."); + } + } } void SmallSceneryObject::Load() diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp index 352af8d84c..1182551b5d 100644 --- a/src/object/WallObject.cpp +++ b/src/object/WallObject.cpp @@ -47,6 +47,12 @@ void WallObject::ReadLegacy(IReadObjectContext * context, IStream * stream) _sceneryTabEntry = stream->ReadValue(); GetImageTable()->Read(context, stream); + + // Validate properties + if (_legacyType.large_scenery.price <= 0) + { + context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Price can not be free or negative."); + } } void WallObject::Load() From a47c039f22a495c363ae3e33ff30f5ca7e7fca43 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 2 Jul 2016 18:01:51 +0100 Subject: [PATCH 057/116] remove lots of old object code --- src/editor.c | 18 - src/object.c | 1590 ------------------------- src/object.h | 17 +- src/object/ObjectRepository.cpp | 53 +- src/object/ObjectRepository.h | 1 + src/object_list.c | 10 +- src/ride/track_design.c | 10 - src/scenario.c | 2 +- src/windows/editor_inventions_list.c | 24 +- src/windows/editor_object_selection.c | 14 +- 10 files changed, 81 insertions(+), 1658 deletions(-) diff --git a/src/editor.c b/src/editor.c index b3cd7ad155..2483101076 100644 --- a/src/editor.c +++ b/src/editor.c @@ -124,15 +124,6 @@ void editor_convert_save_to_scenario_callback(int result) s6Info->objective_arg_3 = gScenarioObjectiveNumGuests; climate_reset(gClimate); - rct_stex_entry* stex = g_stexEntries[0]; - if ((int)stex != 0xFFFFFFFF) { - object_unload_chunk((rct_object_entry*)&object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0]); - reset_loaded_objects(); - - format_string(s6Info->details, STR_NO_DETAILS_YET, NULL); - s6Info->name[0] = 0; - } - gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR; s6Info->editor_step = EDITOR_STEP_OBJECTIVE_SELECTION; s6Info->category = SCENARIO_CATEGORY_OTHER; @@ -469,15 +460,6 @@ static void editor_clear_map_for_editing() climate_reset(gClimate); - rct_stex_entry* stex = g_stexEntries[0]; - if ((int)stex != 0xFFFFFFFF) { - object_unload_chunk((rct_object_entry*)&object_entry_groups[OBJECT_TYPE_SCENARIO_TEXT].entries[0]); - reset_loaded_objects(); - - format_string(gS6Info->details, STR_NO_DETAILS_YET, NULL); - gS6Info->name[0] = 0; - } - news_item_init_queue(); } diff --git a/src/object.c b/src/object.c index 2c6592b8e6..5368758525 100644 --- a/src/object.c +++ b/src/object.c @@ -50,231 +50,6 @@ int object_load_entry(const utf8 *path, rct_object_entry *outEntry) return 1; } -/** - * - * rct2: 0x006a9f42 - * ebx: file - * ebp: entry - */ -int write_object_file(SDL_RWops *rw, rct_object_entry* entry) -{ - uint8 entryGroupIndex = 0, type = 0; - uint8* chunk = 0; - - if (!find_object_in_entry_group(entry, &type, &entryGroupIndex))return 0; - - chunk = object_entry_groups[type].chunks[entryGroupIndex]; - - object_unload(type, chunk); - - rct_object_entry_extended* installed_entry = &object_entry_groups[type].entries[entryGroupIndex]; - uint8* dst_buffer = (uint8*)malloc(0x600000); - memcpy(dst_buffer, installed_entry, sizeof(rct_object_entry)); - - uint32 size_dst = sizeof(rct_object_entry); - - sawyercoding_chunk_header chunkHeader; - // Encoding type (not used anymore) - RCT2_GLOBAL(0x9E3CBD, uint8) = object_entry_group_encoding[type]; - - chunkHeader.encoding = object_entry_group_encoding[type]; - chunkHeader.length = installed_entry->chunk_size; - - - //Check if content of object file matches the stored checksum. If it does not, then fix it. - int calculated_checksum = object_calculate_checksum(entry, chunk, installed_entry->chunk_size); - if(entry->checksum != calculated_checksum) { - //Store the current length of the header - it's the offset at which we will write the extra bytes - int salt_offset = chunkHeader.length; - /*Allocate a new chunk 11 bytes longer. - I would just realloc the old one, but realloc can move the data, leaving dangling pointers - into the old buffer. If the chunk is only referenced in one place it would be safe to realloc - it and update that reference, but I don't know the codebase well enough to know if that's the - case, so to be on the safe side I copy it*/ - uint8* new_chunk = malloc(chunkHeader.length + 11); - memcpy(new_chunk,chunk, chunkHeader.length); - //It should be safe to update these in-place because they are local - chunkHeader.length += 11; - - /*Next work out which bits need to be flipped to make the current checksum match the one in the file - The bitwise rotation compensates for the rotation performed during the checksum calculation*/ - int bits_to_flip = entry->checksum ^ ((calculated_checksum << 25) | (calculated_checksum >> 7)); - /*Each set bit encountered during encoding flips one bit of the resulting checksum (so each bit of the checksum is an XOR - of bits from the file). Here, we take each bit that should be flipped in the checksum and set one of the bits in the data - that maps to it. 11 bytes is the minimum needed to touch every bit of the checksum - with less than that, you wouldn't - always be able to make the checksum come out to the desired target*/ - new_chunk[salt_offset] = (bits_to_flip & 0x00000001) << 7; - new_chunk[salt_offset + 1] = ((bits_to_flip & 0x00200000) >> 14); - new_chunk[salt_offset + 2] = ((bits_to_flip & 0x000007F8) >> 3); - new_chunk[salt_offset + 3] = ((bits_to_flip & 0xFF000000) >> 24); - new_chunk[salt_offset + 4] = ((bits_to_flip & 0x00100000) >> 13); - new_chunk[salt_offset + 5] = (bits_to_flip & 0x00000004) >> 2; - new_chunk[salt_offset + 6] = 0; - new_chunk[salt_offset + 7] = ((bits_to_flip & 0x000FF000) >> 12); - new_chunk[salt_offset + 8] = (bits_to_flip & 0x00000002) >> 1; - new_chunk[salt_offset + 9] = (bits_to_flip & 0x00C00000) >> 22; - new_chunk[salt_offset + 10] = (bits_to_flip & 0x00000800) >> 11; - - //Write modified chunk data - size_dst += sawyercoding_write_chunk_buffer(dst_buffer + sizeof(rct_object_entry),new_chunk,chunkHeader); - free(new_chunk); - } else { - //If the checksum matches, write chunk data - size_dst += sawyercoding_write_chunk_buffer(dst_buffer + sizeof(rct_object_entry), chunk, chunkHeader); - } - - SDL_RWwrite(rw, dst_buffer, 1, size_dst); - free(dst_buffer); - return 1; -} - -/** -* -* rct2: 0x006AA2B7 -*/ -int object_load_packed_old(SDL_RWops* rw) -{ - object_unload_all(); - - rct_object_entry entry; - - SDL_RWread(rw, &entry, 16, 1); - - uint8* chunk = (uint8*)malloc(0x600000); - uint32 chunkSize = sawyercoding_read_chunk(rw, chunk); - chunk = realloc(chunk, chunkSize); - - if (chunk == NULL){ - log_error("Failed to allocate memory for packed object."); - return 0; - } - - if (object_calculate_checksum(&entry, chunk, chunkSize) != entry.checksum){ - - if(gConfigGeneral.allow_loading_with_incorrect_checksum) { - log_warning("Checksum mismatch from packed object: %.8s", entry.name); - } else { - log_error("Checksum mismatch from packed object: %.8s", entry.name); - free(chunk); - return 0; - } - } - - int type = entry.flags & 0x0F; - - if (!object_test(type, chunk)) { - log_error("Packed object failed paint test."); - free(chunk); - return 0; - } - - if (gTotalNoImages >= 0x4726E){ - log_error("Packed object has too many images."); - free(chunk); - return 0; - } - - - int entryGroupIndex = 0; - - for (; entryGroupIndex < object_entry_group_counts[type]; entryGroupIndex++){ - if (object_entry_groups[type].chunks[entryGroupIndex] == (uint8*)-1){ - break; - } - } - - if (entryGroupIndex == object_entry_group_counts[type]){ - // This should never occur. Objects are not loaded before installing a - // packed object. So there is only one object loaded at this point. - log_error("Too many objects of the same type loaded."); - free(chunk); - return 0; - } - - // Copy the entry into the relevant entry group. - object_entry_groups[type].chunks[entryGroupIndex] = chunk; - rct_object_entry_extended* extended_entry = &object_entry_groups[type].entries[entryGroupIndex]; - memcpy(extended_entry, &entry, sizeof(rct_object_entry)); - extended_entry->chunk_size = chunkSize; - - // Ensure the entry does not already exist. - rct_object_entry *installedObject = gInstalledObjects; - if (gInstalledObjectsCount){ - for (uint32 i = 0; i < gInstalledObjectsCount; ++i){ - if (object_entry_compare(&entry, installedObject)){ - object_unload_all(); - return 0; - } - installedObject = object_get_next(installedObject); - } - } - - // Convert the entry name to a upper case path name - char path[MAX_PATH]; - char objectPath[9] = { 0 }; - for (int i = 0; i < 8; ++i){ - if (entry.name[i] != ' ') - objectPath[i] = toupper(entry.name[i]); - else - objectPath[i] = '\0'; - } - - substitute_path(path, gRCT2AddressObjectDataPath, objectPath); - // Require pointer to start of filename - char* last_char = path + strlen(path); - strcat(path, ".DAT"); - - // Check that file does not exist - // Adjust filename if it does. - for (; platform_file_exists(path);){ - for (char* curr_char = last_char - 1;; --curr_char){ - if (*curr_char == '\\'){ - substitute_path(path, gRCT2AddressObjectDataPath, "00000000.DAT"); - break; - } - if (*curr_char < '0') *curr_char = '0'; - else if (*curr_char == '9') *curr_char = 'A'; - else if (*curr_char == 'Z') *curr_char = '0'; - else (*curr_char)++; - if (*curr_char != '0') break; - } - } - - // Actually write the object to the file - SDL_RWops* rw_out = SDL_RWFromFile(path, "wb"); - if (rw_out != NULL){ - uint8 result = write_object_file(rw_out, &entry); - - SDL_RWclose(rw_out); - object_unload_all(); - - return result; - } - - object_unload_all(); - return 0; -} - -/** - * - * rct2: 0x006A9CAF - */ -void object_unload_chunk(rct_object_entry *entry) -{ - uint8 object_type, object_index; - if (!find_object_in_entry_group(entry, &object_type, &object_index)){ - return; - } - - uint8* chunk = object_entry_groups[object_type].chunks[object_index]; - - object_unload(object_type, chunk); - - free(chunk); - memset(&object_entry_groups[object_type].entries[object_index], 0, sizeof(rct_object_entry_extended)); - object_entry_groups[object_type].chunks[object_index] = (uint8*)-1; -} - int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b) { // If an official object don't bother checking checksum @@ -315,1368 +90,3 @@ int object_calculate_checksum(const rct_object_entry *entry, const uint8 *data, } return (int)checksum; } - -/** - * - * rct2: 0x006A9ED1 - */ -int object_chunk_load_image_directory(uint8_t** chunk) -{ - int image_start_no = gTotalNoImages; - - // First dword of chunk is no_images - int no_images = *((uint32_t*)(*chunk)); - *chunk += 4; - // Second dword of chunk is length of image data - int length_of_data = *((uint32_t*)(*chunk)); - *chunk += 4; - - gTotalNoImages = no_images + image_start_no; - - rct_g1_element* g1_dest = &g1Elements[image_start_no]; - - // After length of data is the start of all g1 element structs - rct_g1_element_32bit* g1_source = (rct_g1_element_32bit*)(*chunk); - - // After the g1 element structs is the actual images. - uintptr_t image_offset = no_images * sizeof(rct_g1_element_32bit) + (uintptr_t)g1_source; - - for (int i = 0; i < no_images; ++i) { - g1_dest->offset = (uint8*)(g1_source->offset + image_offset); - g1_dest->width = g1_source->width; - g1_dest->height = g1_source->height; - g1_dest->x_offset = g1_source->x_offset; - g1_dest->y_offset = g1_source->y_offset; - g1_dest->flags = g1_source->flags; - g1_dest->zoomed_offset = g1_source->zoomed_offset; - g1_dest++; - - drawing_engine_invalidate_image(image_start_no + i); - g1_source++; - } - - *chunk = ((uint8*)g1_source) + length_of_data; - - return image_start_no; -} - -typedef bool (*object_load_func)(void *objectEntry, uint32 entryIndex); -typedef void (*object_unload_func)(void *objectEntry); -typedef bool (*object_test_func)(void *objectEntry); -typedef void (*object_paint_func)(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y); -typedef rct_string_id (*object_desc_func)(void *objectEntry); - -/** - * Represents addresses for virtual object functions. - */ -typedef struct object_type_vtable { - object_load_func load; - object_unload_func unload; - object_test_func test; - object_paint_func paint; - object_desc_func desc; -} object_type_vtable; - -/////////////////////////////////////////////////////////////////////////////// -// Ride (rct2: 0x006E6E2A) -/////////////////////////////////////////////////////////////////////////////// - -static bool object_type_ride_load(void *objectEntry, uint32 entryIndex) -{ - rct_ride_entry *rideEntry = (rct_ride_entry*)objectEntry; - - // After rideEntry is 3 string tables - uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + sizeof(rct_ride_entry)); - rideEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_RIDE, entryIndex, 0); - rideEntry->description = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_RIDE, entryIndex, 1); - - //TODO: Move to its own function when ride construction window is merged. - if (gConfigInterface.select_by_track_type) { - rideEntry->enabledTrackPieces = 0xFFFFFFFFFFFFFFFF; - } - - object_get_localised_text(&extendedEntryData, OBJECT_TYPE_RIDE, entryIndex, 2); - rideEntry->vehicle_preset_list = (vehicle_colour_preset_list*)extendedEntryData; - - // If Unknown struct size is 0xFF then there are 32 3 byte structures - uint8 unknown_size = *extendedEntryData++; - if (unknown_size != 0xFF) { - extendedEntryData += unknown_size * 3; - } else { - extendedEntryData += 0x60; - } - - sint8 *peep_loading_positions = (sint8*)extendedEntryData; - // Peep loading positions variable size - // 4 different vehicle subtypes are available - for (int i = 0; i < 4; i++){ - uint16 no_peep_positions = *extendedEntryData++; - // If no_peep_positions is 0xFF then no_peep_positions is a word - if (no_peep_positions == 0xFF) { - no_peep_positions = *((uint16*)extendedEntryData); - extendedEntryData += 2; - } - extendedEntryData += no_peep_positions; - } - - int images_offset = object_chunk_load_image_directory(&extendedEntryData); - rideEntry->images_offset = images_offset; - - int cur_vehicle_images_offset = images_offset + 3; - - for (int i = 0; i < 4; i++) { - rct_ride_entry_vehicle* vehicleEntry = &rideEntry->vehicles[i]; - - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT) { - int al = 1; - if (vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_SWINGING) { - al = 13; - if ((vehicleEntry->flags_b & (VEHICLE_ENTRY_FLAG_B_5 | VEHICLE_ENTRY_FLAG_B_11)) != (VEHICLE_ENTRY_FLAG_B_5 | VEHICLE_ENTRY_FLAG_B_11)) { - al = 7; - if (!(vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_5)) { - if (!(vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_11)) { - al = 5; - if (vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_9) { - al = 3; - } - } - } - } - } - vehicleEntry->var_03 = al; - // 0x6DE90B - - al = 0x20; - if (!(vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_14)) { - al = 1; - if (vehicleEntry->flags_b & VEHICLE_ENTRY_FLAG_B_7) { - if (vehicleEntry->var_11 != 6) { - al = 2; - if (!(vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_7)) { - al = 4; - } - } - } - } - if (vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_12) { - al = vehicleEntry->special_frames; - } - vehicleEntry->var_02 = al; - // 0x6DE946 - - vehicleEntry->var_16 = vehicleEntry->var_02 * vehicleEntry->var_03; - vehicleEntry->base_image_id = cur_vehicle_images_offset; - int image_index = vehicleEntry->base_image_id; - - if (vehicleEntry->car_visual != VEHICLE_VISUAL_RIVER_RAPIDS) { - int b = vehicleEntry->var_16 * 32; - - if (vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_11) b /= 2; - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_15) b /= 8; - - image_index += b; - - // Incline 25 - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_GENTLE_SLOPES) { - vehicleEntry->var_20 = image_index; - b = vehicleEntry->var_16 * 72; - if (vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_14) - b = vehicleEntry->var_16 * 16; - - image_index += b; - } - - // Incline 60 - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_STEEP_SLOPES) { - vehicleEntry->var_24 = image_index; - b = vehicleEntry->var_16 * 80; - image_index += b; - } - - // Verticle - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_VERTICAL_SLOPES) { - vehicleEntry->var_28 = image_index; - b = vehicleEntry->var_16 * 116; - image_index += b; - } - - // Unknown - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_DIAGONAL_SLOPES) { - vehicleEntry->var_2C = image_index; - b = vehicleEntry->var_16 * 24; - image_index += b; - } - - // Bank - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT_BANKED) { - vehicleEntry->var_30 = image_index; - b = vehicleEntry->var_16 * 80; - image_index += b; - } - - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_INLINE_TWISTS) { - vehicleEntry->var_34 = image_index; - b = vehicleEntry->var_16 * 40; - image_index += b; - } - - // Track half? Up/Down - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_BANKED_TRANSITIONS) { - vehicleEntry->var_38 = image_index; - b = vehicleEntry->var_16 * 128; - image_index += b; - } - - // Unknown - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_DIAGONAL_GENTLE_SLOPE_BANKED_TRANSITIONS) { - vehicleEntry->var_3C = image_index; - b = vehicleEntry->var_16 * 16; - image_index += b; - } - - // Unknown - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TRANSITIONS) { - vehicleEntry->var_40 = image_index; - b = vehicleEntry->var_16 * 16; - image_index += b; - } - - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TURNS) { - vehicleEntry->var_44 = image_index; - b = vehicleEntry->var_16 * 128; - image_index += b; - } - - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_WHILE_BANKED_TRANSITIONS) { - vehicleEntry->var_48 = image_index; - b = vehicleEntry->var_16 * 16; - image_index += b; - } - - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_CORKSCREWS) { - vehicleEntry->var_4C = image_index; - b = vehicleEntry->var_16 * 80; - image_index += b; - } - - // Unknown - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_RESTRAINT_ANIMATION) { - vehicleEntry->var_1C = image_index; - b = vehicleEntry->var_16 * 12; - image_index += b; - } - - if (vehicleEntry->sprite_flags & VEHICLE_SPRITE_FLAG_14) { - // Same offset as above??? - vehicleEntry->var_4C = image_index; - b = vehicleEntry->var_16 * 32; - image_index += b; - } - } else { - image_index += vehicleEntry->var_16 * 36; - } - // No vehicle images - vehicleEntry->no_vehicle_images = image_index - cur_vehicle_images_offset; - - // Move the offset over this vehicles images. Including peeps - cur_vehicle_images_offset = image_index + vehicleEntry->no_seating_rows * vehicleEntry->no_vehicle_images; - // 0x6DEB0D - - if (!(vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_10)) { - int num_images = cur_vehicle_images_offset - vehicleEntry->base_image_id; - if (vehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_13) { - num_images *= 2; - } - - set_vehicle_type_image_max_sizes(vehicleEntry, num_images); - } - - sint8 no_positions = *peep_loading_positions++; - if (no_positions == -1) { - // The no_positions is 16 bit skip over - peep_loading_positions += 2; - } - vehicleEntry->peep_loading_positions = peep_loading_positions; - } - } - - // 0x6DEB71 - if (RCT2_GLOBAL(0x9ADAFD, uint8) == 0) { - for (int i = 0; i < 3; i++) { - int dl = rideEntry->ride_type[i]; - if (dl == 0xFF) { - continue; - } - - uint8 *typeToRideEntryIndexMap = gTypeToRideEntryIndexMap; - while (dl >= 0) { - if (*typeToRideEntryIndexMap++ == 0xFF) { - dl--; - } - } - - typeToRideEntryIndexMap--; - uint8 previous_entry = entryIndex; - while (typeToRideEntryIndexMap < gTypeToRideEntryIndexMap + countof(gTypeToRideEntryIndexMap)){ - uint8 backup_entry = *typeToRideEntryIndexMap; - *typeToRideEntryIndexMap++ = previous_entry; - previous_entry = backup_entry; - } - } - } - - // 0x6DEBAA - if (RCT2_GLOBAL(0x9ADAF4, sint32) != 0xFFFFFFFF) { - *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; - } - - int di = rideEntry->ride_type[0] | (rideEntry->ride_type[1] << 8) | (rideEntry->ride_type[2] << 16); - - if ((rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) && !rideTypeShouldLoseSeparateFlag(rideEntry)) { - di |= 0x1000000; - } - - RCT2_GLOBAL(0xF433DD, uint32) = di; - return true; -} - -static void object_type_ride_unload(void *objectEntry) -{ - rct_ride_entry *rideEntry = (rct_ride_entry*)objectEntry; - rideEntry->name = 0; - rideEntry->description = 0; - rideEntry->images_offset = 0; - - for (int i = 0; i < 4; i++) { - rct_ride_entry_vehicle* rideVehicleEntry = &rideEntry->vehicles[i]; - - rideVehicleEntry->base_image_id = 0; - rideVehicleEntry->var_1C = 0; - rideVehicleEntry->var_20 = 0; - rideVehicleEntry->var_24 = 0; - rideVehicleEntry->var_28 = 0; - rideVehicleEntry->var_2C = 0; - rideVehicleEntry->var_30 = 0; - rideVehicleEntry->var_34 = 0; - rideVehicleEntry->var_38 = 0; - rideVehicleEntry->var_3C = 0; - rideVehicleEntry->var_40 = 0; - rideVehicleEntry->var_44 = 0; - rideVehicleEntry->var_48 = 0; - rideVehicleEntry->var_4C = 0; - rideVehicleEntry->no_vehicle_images = 0; - rideVehicleEntry->var_16 = 0; - - if (!(rideVehicleEntry->flags_a & VEHICLE_ENTRY_FLAG_A_10)) { - rideVehicleEntry->sprite_width = 0; - rideVehicleEntry->sprite_height_negative = 0; - rideVehicleEntry->sprite_height_positive = 0; - } - rideVehicleEntry->var_02 = 0; - rideVehicleEntry->var_03 = 0; - rideVehicleEntry->peep_loading_positions = 0; - } - - rideEntry->vehicle_preset_list = NULL; -} - -static bool object_type_ride_test(void *objectEntry) -{ - rct_ride_entry* rideEntry = (rct_ride_entry*)objectEntry; - if (rideEntry->excitement_multipler > 75) return false; - if (rideEntry->intensity_multipler > 75) return false; - if (rideEntry->nausea_multipler > 75) return false; - return true; -} - -static void object_type_ride_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y) -{ - rct_ride_entry *rideEntry = (rct_ride_entry*)objectEntry; - int imageId = rideEntry->images_offset; - if (rideEntry->ride_type[0] == 0xFF) { - imageId++; - if (rideEntry->ride_type[1] == 0xFF) { - imageId++; - } - } - gfx_draw_sprite(dpi, imageId, x - 56, y - 56, 0); -} - -static rct_string_id object_type_ride_desc(void *objectEntry) -{ - rct_ride_entry *rideEntry = (rct_ride_entry*)objectEntry; - - // Get description - rct_string_id stringId = rideEntry->description; - if (!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) || rideTypeShouldLoseSeparateFlag(rideEntry)) { - uint8 rideType = rideEntry->ride_type[0]; - if (rideType == 0xFF) { - rideType = rideEntry->ride_type[1]; - if (rideType == 0xFF) { - rideType = rideEntry->ride_type[2]; - } - } - stringId = 512 + rideType; - } - return stringId; -} - -static const object_type_vtable object_type_ride_vtable[] = { - object_type_ride_load, - object_type_ride_unload, - object_type_ride_test, - object_type_ride_paint, - object_type_ride_desc -}; - -/////////////////////////////////////////////////////////////////////////////// -// Small Scenery (rct2: 0x006E3466) -/////////////////////////////////////////////////////////////////////////////// - -static bool object_type_small_scenery_load(void *objectEntry, uint32 entryIndex) -{ - rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry; - uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + (size_t)0x1C); - - sceneryEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_SMALL_SCENERY, entryIndex, 0); - sceneryEntry->small_scenery.scenery_tab_id = 0xFF; - if (*extendedEntryData != 0xFF) { - uint8 entry_type, entry_index; - if (find_object_in_entry_group((rct_object_entry*)extendedEntryData, &entry_type, &entry_index)) { - sceneryEntry->small_scenery.scenery_tab_id = entry_index; - } - } - - extendedEntryData += sizeof(rct_object_entry); - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG16){ - sceneryEntry->small_scenery.var_10 = (uint32)extendedEntryData; - while (*++extendedEntryData != 0xFF); - extendedEntryData++; - } - - sceneryEntry->image = object_chunk_load_image_directory(&extendedEntryData); - if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) { - *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; - } - - return true; -} - -static void object_type_small_scenery_unload(void *objectEntry) -{ - rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry; - sceneryEntry->name = 0; - sceneryEntry->image = 0; - sceneryEntry->small_scenery.var_10 = 0; - sceneryEntry->small_scenery.scenery_tab_id = 0; -} - -static bool object_type_small_scenery_test(void *objectEntry) -{ - rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry; - - if (sceneryEntry->small_scenery.price <= 0) return false; - if (sceneryEntry->small_scenery.removal_price > 0) return true; - - // Make sure you don't make a profit when placing then removing. - if (-sceneryEntry->small_scenery.removal_price > sceneryEntry->small_scenery.price) return false; - - return true; -} - -static void object_type_small_scenery_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y) -{ - rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry; - rct_drawpixelinfo clipDPI; - if (!clip_drawpixelinfo(&clipDPI, dpi, x - 56, y - 56, 112, 112)) { - return; - } - - int imageId = sceneryEntry->image; - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR) { - imageId |= 0x20D00000; - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) { - imageId |= 0x92000000; - } - } - - x = 56; - y = sceneryEntry->small_scenery.height / 4 + 78; - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE) { - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_VOFFSET_CENTRE) { - y -= 12; - } - } - - gfx_draw_sprite(&clipDPI, imageId, x, y, 0); - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_GLASS) { - imageId = sceneryEntry->image + 0x44500004; - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) { - imageId |= 0x92000000; - } - - gfx_draw_sprite(&clipDPI, imageId, x, y, 0); - } - - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_ANIMATED_FG) { - imageId = sceneryEntry->image + 4; - if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) { - imageId |= 0x92000000; - } - - gfx_draw_sprite(&clipDPI, imageId, x, y, 0); - } -} - -static rct_string_id object_type_small_scenery_desc(void *objectEntry) -{ - return STR_NONE; -} - -static const object_type_vtable object_type_small_scenery_vtable[] = { - object_type_small_scenery_load, - object_type_small_scenery_unload, - object_type_small_scenery_test, - object_type_small_scenery_paint, - object_type_small_scenery_desc -}; - -/////////////////////////////////////////////////////////////////////////////// -// Large Scenery (rct2: 0x006B92A7) -/////////////////////////////////////////////////////////////////////////////// - -static bool object_type_large_scenery_load(void *objectEntry, uint32 entryIndex) -{ - rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry; - uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + (size_t)0x1A); - - sceneryEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_LARGE_SCENERY, entryIndex, 0); - sceneryEntry->large_scenery.scenery_tab_id = 0xFF; - if (*extendedEntryData != 0xFF) { - uint8 entry_type, entry_index; - if (find_object_in_entry_group((rct_object_entry*)extendedEntryData, &entry_type, &entry_index)) { - sceneryEntry->large_scenery.scenery_tab_id = entry_index; - } - } - - extendedEntryData += sizeof(rct_object_entry); - if (sceneryEntry->large_scenery.flags & (1 << 2)) { - sceneryEntry->large_scenery.text = (rct_large_scenery_text*)extendedEntryData; - extendedEntryData += 1038; - } - - sceneryEntry->large_scenery.tiles = (rct_large_scenery_tile*)extendedEntryData; - - // skip over large scenery tiles - while (*((uint16*)extendedEntryData) != 0xFFFF){ - extendedEntryData += sizeof(rct_large_scenery_tile); - } - - extendedEntryData += 2; - - int imageId = object_chunk_load_image_directory(&extendedEntryData); - if (sceneryEntry->large_scenery.flags & (1 << 2)){ - sceneryEntry->large_scenery.text_image = imageId; - - uint8* edx = (uint8*)sceneryEntry->large_scenery.text; - if (!(edx[0xC] & 1)) { - imageId += edx[0xD] * 4; - } else{ - imageId += edx[0xD] * 2; - } - } - sceneryEntry->image = imageId; - if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) { - *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; - } - - return true; -} - -static void object_type_large_scenery_unload(void *objectEntry) -{ - rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry; - sceneryEntry->name = 0; - sceneryEntry->image = 0; - sceneryEntry->large_scenery.tiles = 0; - sceneryEntry->large_scenery.scenery_tab_id = 0; - sceneryEntry->large_scenery.text = 0; - sceneryEntry->large_scenery.text_image = 0; -} - -static bool object_type_large_scenery_test(void *objectEntry) -{ - rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry; - - if (sceneryEntry->large_scenery.price <= 0) return false; - if (sceneryEntry->large_scenery.removal_price > 0) return true; - - // Make sure you don't make a profit when placing then removing. - if (-sceneryEntry->large_scenery.removal_price > sceneryEntry->large_scenery.price) return false; - - return true; -} - -static void object_type_large_scenery_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y) -{ - rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry; - - int imageId = sceneryEntry->image | 0xB2D00000; - gfx_draw_sprite(dpi, imageId, x, y - 39, 0); -} - -static rct_string_id object_type_large_scenery_desc(void *objectEntry) -{ - return STR_NONE; -} - -static const object_type_vtable object_type_large_scenery_vtable[] = { - object_type_large_scenery_load, - object_type_large_scenery_unload, - object_type_large_scenery_test, - object_type_large_scenery_paint, - object_type_large_scenery_desc -}; - -/////////////////////////////////////////////////////////////////////////////// -// Wall (rct2: 0x006E5A25) -/////////////////////////////////////////////////////////////////////////////// - -static bool object_type_wall_load(void *objectEntry, uint32 entryIndex) -{ - rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry; - uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + (size_t)0x0E); - - sceneryEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_WALLS, entryIndex, 0); - sceneryEntry->wall.scenery_tab_id = 0xFF; - if (*extendedEntryData != 0xFF){ - uint8 entry_type, entry_index; - if (find_object_in_entry_group((rct_object_entry*)extendedEntryData, &entry_type, &entry_index)) { - sceneryEntry->wall.scenery_tab_id = entry_index; - } - } - - extendedEntryData += sizeof(rct_object_entry); - sceneryEntry->image = object_chunk_load_image_directory(&extendedEntryData); - - if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) { - *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; - } - - return true; - -} - -static void object_type_wall_unload(void *objectEntry) -{ - rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry; - sceneryEntry->name = 0; - sceneryEntry->image = 0; - sceneryEntry->wall.scenery_tab_id = 0; -} - -static bool object_type_wall_test(void *objectEntry) -{ - rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry; - if (sceneryEntry->wall.price <= 0) return false; - return true; -} - -static void object_type_wall_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y) -{ - rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry; - rct_drawpixelinfo clipDPI; - if (!clip_drawpixelinfo(&clipDPI, dpi, x - 56, y - 56, 112, 112)) { - return; - } - - int imageId = sceneryEntry->image; - imageId |= 0x20D00000; - if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) { - imageId |= 0x92000000; - } - - x = 70; - y = sceneryEntry->wall.height * 2 + 72; - gfx_draw_sprite(&clipDPI, imageId, x, y, 0); - - if (sceneryEntry->wall.flags & WALL_SCENERY_FLAG2){ - imageId = sceneryEntry->image + 0x44500006; - gfx_draw_sprite(&clipDPI, imageId, x, y, 0); - } else if (sceneryEntry->wall.flags & WALL_SCENERY_IS_DOOR){ - imageId++; - gfx_draw_sprite(&clipDPI, imageId, x, y, 0); - } -} - -static rct_string_id object_type_wall_desc(void *objectEntry) -{ - return STR_NONE; -} - -static const object_type_vtable object_type_wall_vtable[] = { - object_type_wall_load, - object_type_wall_unload, - object_type_wall_test, - object_type_wall_paint, - object_type_wall_desc -}; - -/////////////////////////////////////////////////////////////////////////////// -// Banner (rct2: 0x006BA84E) -/////////////////////////////////////////////////////////////////////////////// - -static bool object_type_banner_load(void *objectEntry, uint32 entryIndex) -{ - rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry; - uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + (size_t)0x0C); - - sceneryEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_BANNERS, entryIndex, 0); - sceneryEntry->banner.scenery_tab_id = 0xFF; - if (*extendedEntryData != 0xFF){ - uint8 entry_type, entry_index; - if (find_object_in_entry_group((rct_object_entry*)extendedEntryData, &entry_type, &entry_index)){ - sceneryEntry->banner.scenery_tab_id = entry_index; - } - } - - extendedEntryData += sizeof(rct_object_entry); - sceneryEntry->image = object_chunk_load_image_directory(&extendedEntryData); - - if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) { - *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; - } - - return true; -} - -static void object_type_banner_unload(void *objectEntry) -{ - rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry; - sceneryEntry->name = 0; - sceneryEntry->image = 0; - sceneryEntry->banner.scenery_tab_id = 0; -} - -static bool object_type_banner_test(void *objectEntry) -{ - rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry; - if (sceneryEntry->banner.price <= 0) return false; - return true; -} - -static void object_type_banner_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y) -{ - rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry; - - int imageId = sceneryEntry->image | 0x20D00000; - gfx_draw_sprite(dpi, imageId, x, y, 0); - gfx_draw_sprite(dpi, imageId + 1, x, y, 0); -} - -static rct_string_id object_type_banner_desc(void *objectEntry) -{ - return STR_NONE; -} - -static const object_type_vtable object_type_banner_vtable[] = { - object_type_banner_load, - object_type_banner_unload, - object_type_banner_test, - object_type_banner_paint, - object_type_banner_desc -}; - -/////////////////////////////////////////////////////////////////////////////// -// Path (rct2: 0x006A8621) -/////////////////////////////////////////////////////////////////////////////// - -static bool object_type_path_load(void *objectEntry, uint32 entryIndex) -{ - rct_footpath_entry *pathEntry = (rct_footpath_entry*)objectEntry; - uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + (size_t)0x0E); - - pathEntry->string_idx = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_PATHS, entryIndex, 0); - - int imageId = object_chunk_load_image_directory(&extendedEntryData); - pathEntry->image = imageId; - pathEntry->bridge_image = imageId + 109; - - if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) { - *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; - } - - return true; -} - -static void object_type_path_unload(void *objectEntry) -{ - rct_footpath_entry *pathEntry = (rct_footpath_entry*)objectEntry; - pathEntry->string_idx = 0; - pathEntry->image = 0; - pathEntry->bridge_image = 0; -} - -static bool object_type_path_test(void *objectEntry) -{ - rct_footpath_entry *pathEntry = (rct_footpath_entry*)objectEntry; - if (pathEntry->var_0A >= 2) return false; - return true; -} - -static void object_type_path_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y) -{ - rct_footpath_entry *pathEntry = (rct_footpath_entry*)objectEntry; - gfx_draw_sprite(dpi, pathEntry->image + 71, x - 49, y - 17, 0); - gfx_draw_sprite(dpi, pathEntry->image + 72, x + 4, y - 17, 0); -} - -static rct_string_id object_type_path_desc(void *objectEntry) -{ - return STR_NONE; -} - -static const object_type_vtable object_type_path_vtable[] = { - object_type_path_load, - object_type_path_unload, - object_type_path_test, - object_type_path_paint, - object_type_path_desc -}; - -/////////////////////////////////////////////////////////////////////////////// -// Path Item (rct2: 0x006A86E2) -/////////////////////////////////////////////////////////////////////////////// - -static bool object_type_path_bit_load(void *objectEntry, uint32 entryIndex) -{ - rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry; - uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + (size_t)0x0E); - - sceneryEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_PATH_BITS, entryIndex, 0); - sceneryEntry->path_bit.scenery_tab_id = 0xFF; - if (*extendedEntryData != 0xFF) { - uint8 entry_type, entry_index; - if (find_object_in_entry_group((rct_object_entry*)extendedEntryData, &entry_type, &entry_index)){ - sceneryEntry->path_bit.scenery_tab_id = entry_index; - } - } - - extendedEntryData += sizeof(rct_object_entry); - sceneryEntry->image = object_chunk_load_image_directory(&extendedEntryData); - - if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) { - *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; - } - - return true; -} - -static void object_type_path_bit_unload(void *objectEntry) -{ - rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry; - sceneryEntry->name = 0; - sceneryEntry->image = 0; - sceneryEntry->path_bit.scenery_tab_id = 0; -} - -static bool object_type_path_bit_test(void *objectEntry) -{ - rct_scenery_entry *sceneryEntry = (rct_scenery_entry*)objectEntry; - if (sceneryEntry->path_bit.price <= 0) return false; - return true; -} - -static void object_type_path_bit_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y) -{ - rct_scenery_entry* sceneryEntry = (rct_scenery_entry*)objectEntry; - gfx_draw_sprite(dpi, sceneryEntry->image, x - 22, y - 24, 0); -} - -static rct_string_id object_type_path_bit_desc(void *objectEntry) -{ - return STR_NONE; -} - -static const object_type_vtable object_type_path_bit_vtable[] = { - object_type_path_bit_load, - object_type_path_bit_unload, - object_type_path_bit_test, - object_type_path_bit_paint, - object_type_path_bit_desc -}; - -/////////////////////////////////////////////////////////////////////////////// -// Scenery Set (rct2: 0x006B93AA) -/////////////////////////////////////////////////////////////////////////////// - -static bool object_type_scenery_set_load(void *objectEntry, uint32 entryIndex) -{ - rct_scenery_set_entry *scenerySetEntry = (rct_scenery_set_entry*)objectEntry; - uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + sizeof(rct_scenery_set_entry)); - - scenerySetEntry->name = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_SCENERY_SETS, entryIndex, 0); - - rct_object_entry *entryObjects = NULL; - uint8 *eax = RCT2_GLOBAL(0x9ADAF4, uint8*); - if ((uint32)eax != 0xFFFFFFFF){ - *((uint16*)eax) = 0; - entryObjects = (rct_object_entry*)(eax + 2); - } - - scenerySetEntry->entry_count = 0; - scenerySetEntry->var_107 = 0; - - for (; *extendedEntryData != 0xFF; extendedEntryData += sizeof(rct_object_entry)) { - scenerySetEntry->var_107++; - - if (entryObjects != NULL){ - memcpy(entryObjects, extendedEntryData, sizeof(rct_object_entry)); - entryObjects++; - (*(eax + 1))++; - } - uint8 entry_type; - uint8 entry_index = 0; - if (!find_object_in_entry_group((rct_object_entry*)extendedEntryData, &entry_type, &entry_index)) - continue; - - uint16 scenery_entry = entry_index; - - switch (entry_type){ - case OBJECT_TYPE_SMALL_SCENERY: - break; - case OBJECT_TYPE_LARGE_SCENERY: - scenery_entry |= 0x300; - break; - case OBJECT_TYPE_WALLS: - scenery_entry |= 0x200; - break; - case OBJECT_TYPE_PATH_BITS: - scenery_entry |= 0x100; - break; - default: - scenery_entry |= 0x400; - break; - } - - scenerySetEntry->scenery_entries[scenerySetEntry->entry_count++] = scenery_entry; - } - - extendedEntryData++; - scenerySetEntry->image = object_chunk_load_image_directory(&extendedEntryData); - - return true; -} - -static void object_type_scenery_set_unload(void *objectEntry) -{ - rct_scenery_set_entry *scenerySetEntry = (rct_scenery_set_entry*)objectEntry; - scenerySetEntry->name = 0; - scenerySetEntry->image = 0; - scenerySetEntry->entry_count = 0; - scenerySetEntry->var_107 = 0; - memset(scenerySetEntry->scenery_entries, 0, 256); -} - -static bool object_type_scenery_set_test(void *objectEntry) -{ - return true; -} - -static void object_type_scenery_set_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y) -{ - rct_scenery_set_entry *scenerySetEntry = (rct_scenery_set_entry*)objectEntry; - int imageId = scenerySetEntry->image + 0x20600001; - gfx_draw_sprite(dpi, imageId, x - 15, y - 14, 0); -} - -static rct_string_id object_type_scenery_set_desc(void *objectEntry) -{ - return STR_NONE; -} - -static const object_type_vtable object_type_scenery_set_vtable[] = { - object_type_scenery_set_load, - object_type_scenery_set_unload, - object_type_scenery_set_test, - object_type_scenery_set_paint, - object_type_scenery_set_desc -}; - -/////////////////////////////////////////////////////////////////////////////// -// Park Entrance (rct2: 0x00666E42) -/////////////////////////////////////////////////////////////////////////////// - -bool object_type_park_entrance_load(void *objectEntry, uint32 entryIndex) -{ - rct_entrance_type *entranceType = (rct_entrance_type*)objectEntry; - uint8 *extendedEntryData = (uint8*)((size_t)objectEntry + sizeof(rct_entrance_type)); - - entranceType->string_idx = object_get_localised_text(&extendedEntryData, OBJECT_TYPE_PARK_ENTRANCE, entryIndex, 0); - entranceType->image_id = object_chunk_load_image_directory(&extendedEntryData); - - if (RCT2_GLOBAL(0x9ADAF4, uint32) != 0xFFFFFFFF) { - *RCT2_GLOBAL(0x9ADAF4, uint16*) = 0; - } - - return true; -} - -static void object_type_park_entrance_unload(void *objectEntry) -{ - rct_entrance_type *entranceType = (rct_entrance_type*)objectEntry; - entranceType->string_idx = 0; - entranceType->image_id = 0; -} - -static bool object_type_park_entrance_test(void *objectEntry) -{ - return true; -} - -static void object_type_park_entrance_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y) -{ - rct_entrance_type *entranceType = (rct_entrance_type*)objectEntry; - - rct_drawpixelinfo clipDPI; - if (!clip_drawpixelinfo(&clipDPI, dpi, x - 56, y - 56, 112, 112)) { - return; - } - - int imageId = entranceType->image_id; - gfx_draw_sprite(&clipDPI, imageId + 1, 24, 68, 0); - gfx_draw_sprite(&clipDPI, imageId, 56, 84, 0); - gfx_draw_sprite(&clipDPI, imageId + 2, 88, 100, 0); -} - -static rct_string_id object_type_park_entrance_desc(void *objectEntry) -{ - return STR_NONE; -} - -static const object_type_vtable object_type_park_entrance_vtable[] = { - object_type_park_entrance_load, - object_type_park_entrance_unload, - object_type_park_entrance_test, - object_type_park_entrance_paint, - object_type_park_entrance_desc -}; - -/////////////////////////////////////////////////////////////////////////////// -// Water (rct2: 0x006E6E2A) -/////////////////////////////////////////////////////////////////////////////// - -static bool object_type_water_load(void *objectEntry, uint32 entryIndex) -{ - rct_water_type *waterEntry = (rct_water_type*)objectEntry; - - uint8 *pStringTable = (uint8*)((size_t)objectEntry + sizeof(rct_water_type)); - waterEntry->string_idx = object_get_localised_text(&pStringTable, OBJECT_TYPE_WATER, entryIndex, 0); - - int imageId = object_chunk_load_image_directory(&pStringTable); - waterEntry->image_id = imageId; - waterEntry->var_06 = imageId + 1; - waterEntry->var_0A = imageId + 4; - - if (RCT2_GLOBAL(0x009ADAF4, uint32) != 0xFFFFFFFF) { - *RCT2_GLOBAL(0x009ADAF4, uint16*) = 0; - } - - if (RCT2_GLOBAL(0x009ADAFD, uint8) == 0) { - load_palette(); - gfx_invalidate_screen(); - } - - return true; -} - -static void object_type_water_unload(void *objectEntry) -{ - rct_water_type *waterEntry = (rct_water_type*)objectEntry; - waterEntry->string_idx = 0; - waterEntry->image_id = 0; - waterEntry->var_06 = 0; - waterEntry->var_0A = 0; -} - -static bool object_type_water_test(void *objectEntry) -{ - return true; -} - -static void object_type_water_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y) -{ - // Write (no image) - gfx_draw_string_centred(dpi, 3326, x, y, 0, NULL); -} - -static rct_string_id object_type_water_desc(void *objectEntry) -{ - return STR_NONE; -} - -static const object_type_vtable object_type_water_vtable[] = { - object_type_water_load, - object_type_water_unload, - object_type_water_test, - object_type_water_paint, - object_type_water_desc -}; - -/////////////////////////////////////////////////////////////////////////////// -// Stex (rct2: 0x0066B355) -/////////////////////////////////////////////////////////////////////////////// - -static bool object_type_stex_load(void *objectEntry, uint32 entryIndex) -{ - rct_stex_entry *stexEntry = (rct_stex_entry*)objectEntry; - uint8 *stringTable = (uint8*)((size_t)objectEntry + (size_t)0x08); - - stexEntry->scenario_name = object_get_localised_text(&stringTable, OBJECT_TYPE_SCENARIO_TEXT, entryIndex, 0); - stexEntry->park_name = object_get_localised_text(&stringTable, OBJECT_TYPE_SCENARIO_TEXT, entryIndex, 1); - stexEntry->details = object_get_localised_text(&stringTable, OBJECT_TYPE_SCENARIO_TEXT, entryIndex, 2); - - if (RCT2_GLOBAL(0x9ADAF4, int) != -1) { - RCT2_GLOBAL(0x9ADAF4, uint16*)[0] = 0; - } - - return true; -} - -static void object_type_stex_unload(void *objectEntry) -{ - rct_stex_entry *stexEntry = (rct_stex_entry*)objectEntry; - stexEntry->scenario_name = 0; - stexEntry->park_name = 0; - stexEntry->details = 0; -} - -static bool object_type_stex_test(void *objectEntry) -{ - return true; -} - -static void object_type_stex_paint(void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y) -{ - // Write (no image) - gfx_draw_string_centred(dpi, 3326, x, y, 0, NULL); -} - -static rct_string_id object_type_stex_desc(void *objectEntry) -{ - rct_stex_entry *stexEntry = (rct_stex_entry*)objectEntry; - return stexEntry->details; -} - -static const object_type_vtable object_type_stex_vtable[] = { - object_type_stex_load, - object_type_stex_unload, - object_type_stex_test, - object_type_stex_paint, - object_type_stex_desc -}; - -/////////////////////////////////////////////////////////////////////////////// - -static const object_type_vtable * const object_type_vtables[] = { - object_type_ride_vtable, - object_type_small_scenery_vtable, - object_type_large_scenery_vtable, - object_type_wall_vtable, - object_type_banner_vtable, - object_type_path_vtable, - object_type_path_bit_vtable, - object_type_scenery_set_vtable, - object_type_park_entrance_vtable, - object_type_water_vtable, - object_type_stex_vtable -}; - -bool object_load(int type, void *objectEntry, uint32 entryIndex) -{ - assert(type >= OBJECT_TYPE_RIDE && type <= OBJECT_TYPE_SCENARIO_TEXT); - const object_type_vtable *vtable = object_type_vtables[type]; - return vtable->load(objectEntry, entryIndex) ? 0 : 1; -} - -void object_unload(int type, void *objectEntry) -{ - assert(type >= OBJECT_TYPE_RIDE && type <= OBJECT_TYPE_SCENARIO_TEXT); - const object_type_vtable *vtable = object_type_vtables[type]; - vtable->unload(objectEntry); -} - -bool object_test(int type, void *objectEntry) -{ - assert(type >= OBJECT_TYPE_RIDE && type <= OBJECT_TYPE_SCENARIO_TEXT); - const object_type_vtable *vtable = object_type_vtables[type]; - return vtable->test(objectEntry); -} - -void object_paint(int type, void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y) -{ - assert(type >= OBJECT_TYPE_RIDE && type <= OBJECT_TYPE_SCENARIO_TEXT); - const object_type_vtable *vtable = object_type_vtables[type]; - vtable->paint(objectEntry, dpi, x, y); -} - -rct_string_id object_desc(int type, void *objectEntry) -{ - assert(type >= OBJECT_TYPE_RIDE && type <= OBJECT_TYPE_SCENARIO_TEXT); - const object_type_vtable *vtable = object_type_vtables[type]; - return vtable->desc(objectEntry); -} - -/** - * - * rct2: 0x006A9428 - */ -int object_get_scenario_text(rct_object_entry *entry) -{ - rct_object_entry *installedObject = gInstalledObjects; - - installedObject = object_list_find(entry); - - if (installedObject == NULL){ - log_error("Object not found: %.8s", entry->name); - return 0; - } - - char path[MAX_PATH]; - char *objectPath = (char*)installedObject + 16; - substitute_path(path, gRCT2AddressObjectDataPath, objectPath); - - rct_object_entry openedEntry; - SDL_RWops* rw = SDL_RWFromFile(path, "rb"); - if (rw != NULL) { - SDL_RWread(rw, &openedEntry, sizeof(rct_object_entry), 1); - if (object_entry_compare(&openedEntry, entry)) { - - // Skip over the object entry - char *pos = (char*)installedObject + sizeof(rct_object_entry); - // Skip file name - while (*pos++); - - // Read chunk - int chunkSize = *((uint32*)pos); - - uint8 *chunk; - if (chunkSize == 0xFFFFFFFF) { - chunk = (uint8*)malloc(0x600000); - chunkSize = sawyercoding_read_chunk(rw, chunk); - chunk = realloc(chunk, chunkSize); - } - else { - chunk = (uint8*)malloc(chunkSize); - sawyercoding_read_chunk_with_size(rw, chunk, chunkSize); - } - SDL_RWclose(rw); - - // Calculate and check checksum - if (object_calculate_checksum(&openedEntry, chunk, chunkSize) != openedEntry.checksum) { - log_error("Opened object failed calculated checksum."); - free(chunk); - return 0; - } - - if (!object_test(openedEntry.flags & 0x0F, chunk)) { - // This is impossible for STEX entries to fail. - log_error("Opened object failed paint test."); - free(chunk); - return 0; - } - - // Save the real total images. - int total_no_images = gTotalNoImages; - - // This is being changed to force the images to be loaded into a different - // image id. - gTotalNoImages = 0x726E; - gStexTempChunk = (rct_stex_entry*)chunk; - // Not used anywhere. - RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TEXT_TEMP_OBJECT, rct_object_entry) = openedEntry; - - // Tell text to be loaded into a different address - RCT2_GLOBAL(0x009ADAFC, uint8) = 255; - memcpy(gTempObjectLoadName, openedEntry.name, 8); - // Not used?? - RCT2_GLOBAL(0x009ADAFD, uint8) = 1; - object_load(openedEntry.flags & 0x0F, chunk, 0); - // Tell text to be loaded into normal address - RCT2_GLOBAL(0x009ADAFC, uint8) = 0; - // Not used?? - RCT2_GLOBAL(0x009ADAFD, uint8) = 0; - gTotalNoImages = total_no_images; - return 1; - } - log_error("Opened object didn't match."); - SDL_RWclose(rw); - return 0; - } - log_error("File failed to open."); - return 0; -} - -/** - * - * rct2: 0x006A982D - */ -void object_free_scenario_text() -{ - if (gStexTempChunk != NULL) { - free(gStexTempChunk); - gStexTempChunk = NULL; - } -} - -uintptr_t object_get_length(const rct_object_entry *entry) -{ - return (uintptr_t)object_get_next(entry) - (uintptr_t)entry; -} - -rct_object_entry *object_get_next(const rct_object_entry *entry) -{ - uint8 *pos = (uint8*)entry; - - // Skip sizeof(rct_object_entry) - pos += 16; - - // Skip filename - while (*pos++); - - // Skip no of images - pos += 4; - - // Skip name - while (*pos++); - - // Skip size of chunk - pos += 4; - - // Skip required objects - pos += *pos * 16 + 1; - - // Skip theme objects - pos += *pos * 16 + 1; - - // Skip - pos += 4; - - return (rct_object_entry*)pos; -} - -char *object_get_name(rct_object_entry *entry) -{ - uint8 *pos = (uint8*)entry; - - // Skip sizeof(rct_object_entry) - pos += 16; - - // Skip filename - while (*pos++); - - // Skip no of images - pos += 4; - - return (char *)pos; -} diff --git a/src/object.h b/src/object.h index 8d4177e6d2..4defcbf9b0 100644 --- a/src/object.h +++ b/src/object.h @@ -121,18 +121,13 @@ void set_load_objects_fail_reason(); bool object_read_and_load_entries(SDL_RWops* rw); bool object_load_entries(rct_object_entry* entries); int object_load_packed(SDL_RWops* rw); +bool object_saved_packed(SDL_RWops* rw, const rct_object_entry * entry); void object_unload_all(); int check_object_entry(rct_object_entry *entry); int object_load_chunk(int groupIndex, const rct_object_entry *entry, int* chunk_size); -void object_unload_chunk(rct_object_entry *entry); -int object_get_scenario_text(rct_object_entry *entry); -void object_free_scenario_text(); -uintptr_t object_get_length(const rct_object_entry *entry); int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b); int object_calculate_checksum(const rct_object_entry *entry, const uint8 *data, int dataLength); -rct_object_entry *object_get_next(const rct_object_entry *entry); -int write_object_file(SDL_RWops* rw, rct_object_entry* entry); void reset_loaded_objects(); int find_object_in_entry_group(const rct_object_entry* entry, uint8* entry_type, uint8* entry_index); void object_create_identifier_name(char* string_buffer, const rct_object_entry* object); @@ -140,14 +135,4 @@ void object_create_identifier_name(char* string_buffer, const rct_object_entry* rct_object_entry *object_list_find_by_name(const char *name); rct_object_entry *object_list_find(rct_object_entry *entry); -char *object_get_name(rct_object_entry *entry); - -rct_object_filters *get_object_filter(int index); - -bool object_load(int type, void *objectEntry, uint32 entryIndex); -void object_unload(int type, void *objectEntry); -bool object_test(int type, void *objectEntry); -void object_paint(int type, void *objectEntry, rct_drawpixelinfo *dpi, sint32 x, sint32 y); -rct_string_id object_desc(int type, void *objectEntry); - #endif diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 95e00a5090..16577c8a61 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -658,6 +658,12 @@ extern "C" return (void *)object; } + void * object_repository_get_loaded_object(uint8 objectType, uint8 entryIndex) + { + int index = GetObjectEntryIndex(objectType, entryIndex); + return (void *)_loadedObjects[index]; + } + void object_repository_unload(size_t itemIndex) { // TODO @@ -758,6 +764,44 @@ extern "C" return 1; } + bool object_saved_packed(SDL_RWops * rw, const rct_object_entry * entry) + { + IObjectRepository * objectRepository = GetObjectRepository(); + const ObjectRepositoryItem * item = objectRepository->FindObject(entry); + if (item == nullptr) + { + return false; + } + + auto fs = FileStream(item->Path, FILE_MODE_OPEN); + rct_object_entry fileEntry = fs.ReadValue(); + if (!object_entry_compare(entry, &fileEntry)) + { + return false; + } + + sawyercoding_chunk_header chunkHeader = fs.ReadValue(); + uint8 * chunkData = fs.ReadArray(chunkHeader.length); + + if (SDL_RWwrite(rw, entry, sizeof(rct_object_entry), 1) != 1) + { + Memory::Free(chunkData); + return false; + } + if (SDL_RWwrite(rw, &chunkHeader, sizeof(sawyercoding_chunk_header), 1) != 1) + { + Memory::Free(chunkData); + return false; + } + if (SDL_RWwrite(rw, chunkData, chunkHeader.length, 1) != 1) + { + Memory::Free(chunkData); + return false; + } + + return true; + } + size_t object_repository_get_items_count() { IObjectRepository * objectRepository = GetObjectRepository(); @@ -778,9 +822,12 @@ extern "C" void object_delete(void * object) { - Object * baseObject = (Object *)object; - baseObject->Unload(); - delete baseObject; + if (object != nullptr) + { + Object * baseObject = (Object *)object; + baseObject->Unload(); + delete baseObject; + } } const utf8 * object_get_description(const void * object) diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index d35bff222c..34e311c31c 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -77,6 +77,7 @@ size_t object_repository_get_items_count(); const ObjectRepositoryItem * object_repository_get_items(); const ObjectRepositoryItem * object_repository_find_object_by_entry(const rct_object_entry * entry); void * object_repository_load_object(const rct_object_entry * objectEntry); +void * object_repository_get_loaded_object(uint8 objectType, uint8 entryIndex); void object_repository_unload(size_t itemIndex); void object_delete(void * object); diff --git a/src/object_list.c b/src/object_list.c index 627ac04996..a58a5bdcd4 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -20,6 +20,7 @@ #include "localisation/localisation.h" #include "object.h" #include "object_list.h" +#include "object/ObjectRepository.h" #include "platform/platform.h" #include "rct1.h" #include "ride/track.h" @@ -105,13 +106,14 @@ void *gLastLoadedObjectChunkData; static uint32 object_list_count_custom_objects() { + size_t numObjects = object_repository_get_items_count(); + const ObjectRepositoryItem * items = object_repository_get_items(); + uint32 numCustomObjects = 0; - rct_object_entry *object = gInstalledObjects; - for (uint32 i = 0; i < gInstalledObjectsCount; i++) { - if ((object->flags & 0xF0) == 0) { + for (size_t i = 0; i < numObjects; i++) { + if ((items[i].ObjectEntry.flags & 0xF0) == 0) { numCustomObjects++; } - object = object_get_next(object); } gNumInstalledCustomObjects = numCustomObjects; diff --git a/src/ride/track_design.c b/src/ride/track_design.c index 7be7cebbe3..d09a3b90b8 100644 --- a/src/ride/track_design.c +++ b/src/ride/track_design.c @@ -319,16 +319,6 @@ void track_design_dispose(rct_track_td6 *td6) } } -uint32 *sub_6AB49A(rct_object_entry* entry) -{ - rct_object_entry* object_list_entry = object_list_find(entry); - - if (object_list_entry == NULL) return NULL; - - // Return the address of the last value of the list entry - return (((uint32*)object_get_next(object_list_entry)) - 1); -} - /** * * rct2: 0x006ABDB0 diff --git a/src/scenario.c b/src/scenario.c index d576cfc5c4..a51628ec76 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -727,7 +727,7 @@ int scenario_write_packed_objects(SDL_RWops* rw) if (entryData == (void*)0xFFFFFFFF || (entry->flags & 0xF0)) { continue; } - if (!write_object_file(rw, (rct_object_entry*)entry)) { + if (!object_saved_packed(rw, (rct_object_entry*)entry)) { return 0; } } diff --git a/src/windows/editor_inventions_list.c b/src/windows/editor_inventions_list.c index fd0fe38ddd..f15c16a0cb 100644 --- a/src/windows/editor_inventions_list.c +++ b/src/windows/editor_inventions_list.c @@ -17,16 +17,17 @@ #include "../addresses.h" #include "../cursors.h" #include "../input.h" +#include "../interface/themes.h" #include "../interface/widget.h" #include "../interface/window.h" #include "../localisation/localisation.h" #include "../management/research.h" #include "../object.h" -#include "../world/scenery.h" -#include "../interface/themes.h" +#include "../object/ObjectRepository.h" #include "../rct1.h" -#include "../util/util.h" #include "../sprites.h" +#include "../util/util.h" +#include "../world/scenery.h" #pragma region Widgets @@ -772,9 +773,6 @@ static void window_editor_inventions_list_paint(rct_window *w, rct_drawpixelinfo return; // Preview image - x = w->x + ((widget->left + widget->right) / 2) + 1; - y = w->y + ((widget->top + widget->bottom) / 2) + 1; - int objectEntryType = 7; int eax = researchItem->entryIndex & 0xFFFFFF; if (eax >= 0x10000) @@ -785,7 +783,19 @@ static void window_editor_inventions_list_paint(rct_window *w, rct_drawpixelinfo if (chunk == NULL || chunk == (void*)0xFFFFFFFF) return; - object_paint(objectEntryType, chunk, dpi, x, y); + // Draw preview + widget = &w->widgets[WIDX_PREVIEW]; + void * object = object_repository_get_loaded_object(objectEntryType, researchItem->entryIndex & 0xFF); + if (object != NULL) { + rct_drawpixelinfo clipDPI; + x = w->x + widget->left + 1; + y = w->y + widget->top + 1; + int width = widget->right - widget->left; + int height = widget->bottom - widget->top; + if (clip_drawpixelinfo(&clipDPI, dpi, x, y, width, height)) { + object_draw_preview(object, &clipDPI); + } + } // Item name x = w->x + ((widget->left + widget->right) / 2) + 1; diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index bee24b36dc..e592f3eb52 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -733,9 +733,11 @@ static void window_editor_object_selection_close(rct_window *w) unload_unselected_objects(); editor_load_selected_objects(); reset_loaded_objects(); - object_free_scenario_text(); editor_object_flags_free(); + object_delete(_loadedObject); + _loadedObject = NULL; + if (gScreenFlags & SCREEN_FLAGS_EDITOR) { research_populate_list_random(); } @@ -793,7 +795,6 @@ static void window_editor_object_selection_mouseup(rct_window *w, int widgetInde w->selected_list_item = -1; w->object_entry = (rct_object_entry *) 0xFFFFFFFF; w->scrolls[0].v_top = 0; - object_free_scenario_text(); window_invalidate(w); break; case WIDX_FILTER_RIDE_TAB_TRANSPORT: @@ -813,7 +814,6 @@ static void window_editor_object_selection_mouseup(rct_window *w, int widgetInde w->selected_list_item = -1; w->object_entry = (rct_object_entry *) 0xFFFFFFFF; w->scrolls[0].v_top = 0; - object_free_scenario_text(); window_invalidate(w); break; @@ -825,7 +825,6 @@ static void window_editor_object_selection_mouseup(rct_window *w, int widgetInde case WIDX_INSTALL_TRACK: if (w->selected_list_item != -1) { w->selected_list_item = -1; - object_free_scenario_text(); } window_invalidate(w); @@ -1035,10 +1034,8 @@ static void window_editor_object_selection_scroll_mouseover(rct_window *w, int s if (selectedObject != w->selected_list_item) { w->selected_list_item = selectedObject; - if (_loadedObject != NULL) { - object_delete(_loadedObject); - _loadedObject = NULL; - } + object_delete(_loadedObject); + _loadedObject = NULL; list_item * listItem = &_listItems[selectedObject]; if (selectedObject == -1) { @@ -1468,7 +1465,6 @@ static void window_editor_object_set_page(rct_window *w, int page) w->selected_list_item = -1; w->object_entry = (rct_object_entry *)0xFFFFFFFF; w->scrolls[0].v_top = 0; - object_free_scenario_text(); if (page == WINDOW_OBJECT_SELECTION_PAGE_RIDE_VEHICLES_ATTRACTIONS) { _listSortType = RIDE_SORT_TYPE; From 8d168fb2ce314ba9a658ab877bddc22e18c5504e Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 2 Jul 2016 20:42:10 +0100 Subject: [PATCH 058/116] remove more old object code --- src/addresses.h | 5 +- src/object.h | 6 -- src/object_list.c | 104 -------------------------- src/object_list.h | 2 - src/windows/editor_object_selection.c | 2 - src/windows/options.c | 5 +- 6 files changed, 3 insertions(+), 121 deletions(-) diff --git a/src/addresses.h b/src/addresses.h index 7885109865..b62873a7e4 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -98,9 +98,6 @@ #define RCT2_ADDRESS_WATER_ENTRIES 0x009ADAE0 #define RCT2_ADDRESS_SCENARIO_TEXT_ENTRIES 0x009ADAE4 -#define RCT2_ADDRESS_INSTALLED_OBJECT_LIST 0x009ADAE8 -#define RCT2_ADDRESS_TOTAL_NO_IMAGES 0x009ADAF0 - #define RCT2_ADDRESS_CURRENT_SOUND_DEVICE 0x009AF280 #define RCT2_ADDRESS_VEHICLE_SOUND_LIST 0x009AF288 @@ -478,7 +475,9 @@ #define RCT2_ADDRESS_RUN_INTRO_TICK_PART 0x009AC319 #define RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS 0x009AC861 +#define RCT2_ADDRESS_INSTALLED_OBJECT_LIST 0x009ADAE8 #define RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST 0x009ADAEC +#define RCT2_ADDRESS_TOTAL_NO_IMAGES 0x009ADAF0 #define RCT2_ADDRESS_TOOL_WINDOWNUMBER 0x009DE542 #define RCT2_ADDRESS_TOOL_WINDOWCLASS 0x009DE544 diff --git a/src/object.h b/src/object.h index 4defcbf9b0..be5ee43f44 100644 --- a/src/object.h +++ b/src/object.h @@ -107,14 +107,8 @@ assert_struct_size(rct_object_filters, 3); extern const rct_object_entry_group object_entry_groups[]; extern char gTempObjectLoadName[9]; -extern uint32 gInstalledObjectsCount; -extern rct_object_entry *gInstalledObjects; -extern uint32 gNumInstalledRCT2Objects; -extern uint32 gNumInstalledCustomObjects; extern uint32 gTotalNoImages; -extern void *gLastLoadedObjectChunkData; - int object_load_entry(const utf8 *path, rct_object_entry *outEntry); void object_list_load(); void set_load_objects_fail_reason(); diff --git a/src/object_list.c b/src/object_list.c index a58a5bdcd4..28ac2f5bf1 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -91,45 +91,6 @@ const rct_object_entry_group object_entry_groups[] = { (void**)(gStexEntries ), (rct_object_entry_extended*)(0x00F3F03C + (720 * 20)) // scenario text 0x009ADAE4, 0xF4287C }; -static void load_object_filter(rct_object_entry* entry, uint8* chunk, rct_object_filters* filter); - -static rct_object_filters *_installedObjectFilters = NULL; - -rct_stex_entry *gStexTempChunk; - -uint32 gInstalledObjectsCount; -rct_object_entry *gInstalledObjects; -uint32 gNumInstalledRCT2Objects; -uint32 gNumInstalledCustomObjects; - -void *gLastLoadedObjectChunkData; - -static uint32 object_list_count_custom_objects() -{ - size_t numObjects = object_repository_get_items_count(); - const ObjectRepositoryItem * items = object_repository_get_items(); - - uint32 numCustomObjects = 0; - for (size_t i = 0; i < numObjects; i++) { - if ((items[i].ObjectEntry.flags & 0xF0) == 0) { - numCustomObjects++; - } - } - - gNumInstalledCustomObjects = numCustomObjects; - return numCustomObjects; -} - -/** - * - * rct2: 0x006A93CD - */ -static void object_list_examine() -{ - object_list_count_custom_objects(); - // object_list_sort(); -} - int check_object_entry(rct_object_entry *entry) { uint32 *dwords = (uint32*)entry; @@ -289,71 +250,6 @@ int find_object_in_entry_group(const rct_object_entry* entry, uint8* entry_type, return 1; } -rct_string_id object_get_name_string_id(rct_object_entry *entry, const void *chunk) -{ - int objectType = entry->flags & 0x0F; - switch (objectType) { - case OBJECT_TYPE_RIDE: - return ((rct_ride_entry*)chunk)->name; - case OBJECT_TYPE_SMALL_SCENERY: - case OBJECT_TYPE_LARGE_SCENERY: - case OBJECT_TYPE_WALLS: - case OBJECT_TYPE_BANNERS: - case OBJECT_TYPE_PATH_BITS: - return ((rct_scenery_entry*)chunk)->name; - case OBJECT_TYPE_PATHS: - return ((rct_footpath_entry*)chunk)->string_idx; - case OBJECT_TYPE_SCENERY_SETS: - return ((rct_scenery_set_entry*)chunk)->name; - case OBJECT_TYPE_PARK_ENTRANCE: - return ((rct_entrance_type*)chunk)->string_idx; - case OBJECT_TYPE_WATER: - return ((rct_water_type*)chunk)->string_idx; - case OBJECT_TYPE_SCENARIO_TEXT: - return ((rct_stex_entry*)chunk)->scenario_name; - default: - return STR_NONE; - } -} - -static void load_object_filter(rct_object_entry* entry, uint8* chunk, rct_object_filters* filter) -{ - rct_ride_entry *rideType; - rct_ride_filters *rideFilter; - - switch (entry->flags & 0xF) { - case OBJECT_TYPE_RIDE: - rideType = ((rct_ride_entry*)chunk); - rideFilter = &(filter->ride); - - rideFilter->category[0] = rideType->category[0]; - rideFilter->category[1] = rideType->category[1]; - - for (int i = 0; i < 3; i++) { - rideFilter->ride_type = rideType->ride_type[i]; - if (rideFilter->ride_type != 255) - break; - } - break; - case OBJECT_TYPE_SMALL_SCENERY: - case OBJECT_TYPE_LARGE_SCENERY: - case OBJECT_TYPE_WALLS: - case OBJECT_TYPE_BANNERS: - case OBJECT_TYPE_PATHS: - case OBJECT_TYPE_PATH_BITS: - case OBJECT_TYPE_SCENERY_SETS: - case OBJECT_TYPE_PARK_ENTRANCE: - case OBJECT_TYPE_WATER: - case OBJECT_TYPE_SCENARIO_TEXT: - break; - } -} - -rct_object_filters *get_object_filter(int index) -{ - return &_installedObjectFilters[index]; -} - void object_list_init() { for (uint8 objectType = 0; objectType < OBJECT_ENTRY_GROUP_COUNT; objectType++) { diff --git a/src/object_list.h b/src/object_list.h index 34b360b88e..6e1e6a3463 100644 --- a/src/object_list.h +++ b/src/object_list.h @@ -33,7 +33,5 @@ #define gStexEntries RCT2_ADDRESS(RCT2_ADDRESS_SCENARIO_TEXT_ENTRIES, rct_stex_entry*) #endif -extern rct_stex_entry *gStexTempChunk; - void object_list_init(); void *get_loaded_object_entry(size_t index); diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index e592f3eb52..d92021219d 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -1294,8 +1294,6 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf gfx_draw_string_left(dpi, 3164, gCommonFormatArgs, 0, x, y); } - rct_stex_entry* stex_entry = gStexTempChunk; - // Draw sort button text widget = &w->widgets[WIDX_LIST_SORT_TYPE]; if (widget->type != WWT_EMPTY) { diff --git a/src/windows/options.c b/src/windows/options.c index 12b4e2e718..6371f05282 100644 --- a/src/windows/options.c +++ b/src/windows/options.c @@ -1536,10 +1536,7 @@ static void window_options_invalidate(rct_window *w) w->disabled_widgets |= (1ULL << WIDX_REAL_NAME_CHECKBOX); // save plugin data checkbox: visible or not - if (gNumInstalledCustomObjects == 0) - window_options_misc_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_EMPTY; - else - window_options_misc_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_CHECKBOX; + window_options_misc_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_CHECKBOX; widget_set_checkbox_value(w, WIDX_REAL_NAME_CHECKBOX, gParkFlags & PARK_FLAGS_SHOW_REAL_GUEST_NAMES); widget_set_checkbox_value(w, WIDX_SAVE_PLUGIN_DATA_CHECKBOX, gConfigGeneral.save_plugin_data); From faf1f08b7faf7b64b17bee18623092e4e65d54e7 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 2 Jul 2016 21:52:17 +0100 Subject: [PATCH 059/116] fix loading object via console --- src/interface/console.c | 138 ++++++++++++-------------- src/object.h | 2 +- src/object/ObjectRepository.cpp | 29 +++++- src/object/ObjectRepository.h | 2 + src/object/RideObject.cpp | 1 + src/windows/editor_object_selection.c | 3 +- 6 files changed, 95 insertions(+), 80 deletions(-) diff --git a/src/interface/console.c b/src/interface/console.c index 80ae721210..1e4dc37ffa 100644 --- a/src/interface/console.c +++ b/src/interface/console.c @@ -30,6 +30,7 @@ #include "../input.h" #include "../network/twitch.h" #include "../object.h" +#include "../object/ObjectRepository.h" #include "../world/banner.h" #include "../world/climate.h" #include "../world/scenery.h" @@ -868,84 +869,69 @@ static int cc_twitch(const utf8 **argv, int argc) static int cc_load_object(const utf8 **argv, int argc) { if (argc > 0) { - utf8 path[MAX_PATH]; - - substitute_path(path, gRCT2AddressObjectDataPath, argv[0]); - strcat(path, ".DAT\0"); - - rct_object_entry entry; - if (object_load_entry(path, &entry)) { - uint8 type = entry.flags & 0xF; - uint8 index; - - if (check_object_entry(&entry)) { - if (!find_object_in_entry_group(&entry, &type, &index)){ - - int entryGroupIndex = 0; - for (; entryGroupIndex < object_entry_group_counts[type]; entryGroupIndex++){ - if (object_entry_groups[type].chunks[entryGroupIndex] == (uint8*)-1){ - break; - } - } - - if (entryGroupIndex >= object_entry_group_counts[type]) { - console_writeline_error("Too many objects of that type."); - } - else { - // Load the obect - if (!object_load_chunk(entryGroupIndex, &entry, NULL)) { - console_writeline_error("Could not load object file."); - } - else { - reset_loaded_objects(); - if (type == OBJECT_TYPE_RIDE) { - // Automatically research the ride so it's supported by the game. - rct_ride_entry *rideEntry; - int rideType; - - rideEntry = get_ride_entry(entryGroupIndex); - - for (int j = 0; j < 3; j++) { - rideType = rideEntry->ride_type[j]; - if (rideType != 255) - research_insert(true, 0x10000 | (rideType << 8) | entryGroupIndex, rideEntry->category[0]); - } - - gSilentResearch = true; - sub_684AC3(); - gSilentResearch = false; - } - else if (type == OBJECT_TYPE_SCENERY_SETS) { - rct_scenery_set_entry *scenerySetEntry; - - scenerySetEntry = get_scenery_group_entry(entryGroupIndex); - - research_insert(true, entryGroupIndex, RESEARCH_CATEGORY_SCENERYSET); - - gSilentResearch = true; - sub_684AC3(); - gSilentResearch = false; - } - scenery_set_default_placement_configuration(); - window_new_ride_init_vars(); - - RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_UPDATE_TICKS, uint16) = 0; - gfx_invalidate_screen(); - console_writeline("Object file loaded."); - } - } - } - else { - console_writeline_error("Object is already in scenario."); - } - } - else { - console_writeline_error("The object file was invalid."); - } + char name[9] = { 0 }; + memset(name, ' ', 8); + int i = 0; + for (const char * ch = argv[0]; *ch != '\0' && i < 8; ch++) { + name[i++] = *ch; } - else { - console_writeline_error("Could not find the object file."); + + const ObjectRepositoryItem * ori = object_repository_find_object_by_name(name); + if (ori == NULL) { + console_writeline_error("Could not find the object."); + return 1; } + + const rct_object_entry * entry = &ori->ObjectEntry; + void * loadedObject = object_repository_find_loaded_object(entry); + if (loadedObject != NULL) { + console_writeline_error("Object is already in scenario."); + return 1; + } + + int groupIndex; + if (!object_load_chunk(-1, entry, &groupIndex)) { + console_writeline_error("Unable to load object."); + return 1; + } + + reset_loaded_objects(); + + uint8 objectType = entry->flags & 0x0F; + if (objectType == OBJECT_TYPE_RIDE) { + // Automatically research the ride so it's supported by the game. + rct_ride_entry *rideEntry; + int rideType; + + rideEntry = get_ride_entry(groupIndex); + + for (int j = 0; j < 3; j++) { + rideType = rideEntry->ride_type[j]; + if (rideType != 255) + research_insert(true, 0x10000 | (rideType << 8) | groupIndex, rideEntry->category[0]); + } + + gSilentResearch = true; + sub_684AC3(); + gSilentResearch = false; + } + else if (objectType == OBJECT_TYPE_SCENERY_SETS) { + rct_scenery_set_entry *scenerySetEntry; + + scenerySetEntry = get_scenery_group_entry(groupIndex); + + research_insert(true, groupIndex, RESEARCH_CATEGORY_SCENERYSET); + + gSilentResearch = true; + sub_684AC3(); + gSilentResearch = false; + } + scenery_set_default_placement_configuration(); + window_new_ride_init_vars(); + + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_UPDATE_TICKS, uint16) = 0; + gfx_invalidate_screen(); + console_writeline("Object file loaded."); } return 0; diff --git a/src/object.h b/src/object.h index be5ee43f44..abf9b63a30 100644 --- a/src/object.h +++ b/src/object.h @@ -119,7 +119,7 @@ bool object_saved_packed(SDL_RWops* rw, const rct_object_entry * entry); void object_unload_all(); int check_object_entry(rct_object_entry *entry); -int object_load_chunk(int groupIndex, const rct_object_entry *entry, int* chunk_size); +bool object_load_chunk(int groupIndex, const rct_object_entry * entry, int * outGroupIndex); int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b); int object_calculate_checksum(const rct_object_entry *entry, const uint8 *data, int dataLength); void reset_loaded_objects(); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 16577c8a61..cd6f2383cf 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -595,7 +595,7 @@ extern "C" IObjectRepository * objRepo = GetObjectRepository(); } - int object_load_chunk(int groupIndex, const rct_object_entry * entry, int * chunkSize) + bool object_load_chunk(int groupIndex, const rct_object_entry * entry, int * outGroupIndex) { IObjectRepository * objRepo = GetObjectRepository(); Object * object = objRepo->LoadObject(entry); @@ -623,6 +623,10 @@ extern "C" } } chunkList[groupIndex] = object->GetLegacyData(); + if (outGroupIndex != nullptr) + { + *outGroupIndex = groupIndex; + } rct_object_entry_extended * extendedEntry = &object_entry_groups[objectType].entries[groupIndex]; Memory::Copy(extendedEntry, object->GetObjectEntry(), sizeof(rct_object_entry)); @@ -658,6 +662,23 @@ extern "C" return (void *)object; } + void * object_repository_find_loaded_object(const rct_object_entry * objectEntry) + { + for (size_t i = 0; i < 721; i++) + { + Object * object = _loadedObjects[i]; + if (object != nullptr) + { + const rct_object_entry * entry = object->GetObjectEntry(); + if (memcmp(objectEntry->name, entry->name, 8) == 0) + { + return (void *)object; + } + } + } + return nullptr; + } + void * object_repository_get_loaded_object(uint8 objectType, uint8 entryIndex) { int index = GetObjectEntryIndex(objectType, entryIndex); @@ -820,6 +841,12 @@ extern "C" return objectRepository->FindObject(entry); } + const ObjectRepositoryItem * object_repository_find_object_by_name(const char * name) + { + IObjectRepository * objectRepository = GetObjectRepository(); + return objectRepository->FindObject(name); + } + void object_delete(void * object) { if (object != nullptr) diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 34e311c31c..7df740b2a6 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -76,7 +76,9 @@ IObjectRepository * GetObjectRepository(); size_t object_repository_get_items_count(); const ObjectRepositoryItem * object_repository_get_items(); const ObjectRepositoryItem * object_repository_find_object_by_entry(const rct_object_entry * entry); +const ObjectRepositoryItem * object_repository_find_object_by_name(const char * name); void * object_repository_load_object(const rct_object_entry * objectEntry); +void * object_repository_find_loaded_object(const rct_object_entry * objectEntry); void * object_repository_get_loaded_object(uint8 objectType, uint8 entryIndex); void object_repository_unload(size_t itemIndex); diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index f09304c610..01b9f75ce3 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -101,6 +101,7 @@ void RideObject::Load() _legacyType.name = language_allocate_object_string(GetName()); _legacyType.description = language_allocate_object_string(GetDescription()); _legacyType.images_offset = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); + _legacyType.vehicle_preset_list = &_presetColours; int cur_vehicle_images_offset = _legacyType.images_offset + 3; for (int i = 0; i < 4; i++) diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index d92021219d..54e1d9649c 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -1708,8 +1708,7 @@ static void editor_load_selected_objects() if (_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED) { uint8 entry_index, entry_type; if (!find_object_in_entry_group(&items[i].ObjectEntry, &entry_type, &entry_index)) { - int chunk_size; - if (!object_load_chunk(-1, &items[i].ObjectEntry, &chunk_size)) { + if (!object_load_chunk(-1, &items[i].ObjectEntry, NULL)) { log_error("Failed to load entry %.8s", items->Name); } From 7124143b8908e0f87083aabe15c58fe8d2621a34 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 2 Jul 2016 22:13:37 +0100 Subject: [PATCH 060/116] do more cleanup of old object code --- openrct2.vcxproj | 3 +- src/localisation/language.cpp | 123 -------------------------------- src/localisation/language.h | 2 - src/object.c | 92 ------------------------ src/object.h | 8 +-- src/object/ObjectRepository.cpp | 59 ++++++++++++++- src/object/RideObject.cpp | 29 -------- src/object/WaterObject.cpp | 7 +- 8 files changed, 62 insertions(+), 261 deletions(-) delete mode 100644 src/object.c diff --git a/openrct2.vcxproj b/openrct2.vcxproj index fe0d037877..42eb95041d 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -118,7 +118,6 @@ - @@ -605,4 +604,4 @@ - + \ No newline at end of file diff --git a/src/localisation/language.cpp b/src/localisation/language.cpp index bd87a4b628..b3c8f75d01 100644 --- a/src/localisation/language.cpp +++ b/src/localisation/language.cpp @@ -322,129 +322,6 @@ static bool rct2_language_is_multibyte_charset(int languageId) } } -/* rct2: 0x006A9E24*/ -rct_string_id object_get_localised_text(uint8_t** pStringTable/*ebp*/, int type/*ecx*/, int index/*ebx*/, int tableindex/*edx*/) -{ - uint8 languageId, chosenLanguageId; - char *pString = nullptr; - int result = 0; - bool isBlank; - - while ((languageId = *(*pStringTable)++) != RCT2_LANGUAGE_ID_END) { - isBlank = true; - - // Strings that are just ' ' are set as invalid langauges. - // But if there is no real string then it will set the string as - // the blank string - for (char *ch = (char*)(*pStringTable); *ch != 0; ch++) { - if (!isblank(*ch)) { - isBlank = false; - break; - } - } - - if (isBlank) languageId = 0xFE; - - // This is the ideal situation. Language found - if (languageId == LanguagesDescriptors[gCurrentLanguage].rct2_original_id) { - chosenLanguageId = languageId; - pString = (char*)(*pStringTable); - result |= 1; - } - - // Just in case always load english into pString - if (languageId == RCT2_LANGUAGE_ID_ENGLISH_UK && !(result & 1)) { - chosenLanguageId = languageId; - pString = (char*)(*pStringTable); - result |= 2; - } - - // Failing that fall back to whatever is first string - if (!(result & 7)) { - chosenLanguageId = languageId; - pString = (char*)(*pStringTable); - if (!isBlank) result |= 4; - } - - // Skip over the actual string entry to get to the next entry - while (*(*pStringTable)++ != 0); - } - // Fall back in case language does not get set. - if (pString == NULL) - { - pString = (char*)(*pStringTable); - } - - char name[9]; - if (RCT2_GLOBAL(0x009ADAFC, uint8) == 0) { - memcpy(name, object_entry_groups[type].entries[index].name, 8); - } else { - memcpy(name, gTempObjectLoadName, 8); - } - name[8] = 0; - - rct_string_id stringId = _languageCurrent->GetObjectOverrideStringId(name, tableindex); - if (stringId != STR_NONE) { - return stringId; - } - - // If not scenario text - if (RCT2_GLOBAL(0x009ADAFC, uint8) == 0) { - int stringid = NONSTEX_BASE_STRING_ID; - for (int i = 0; i < type; i++) { - int nrobjects = object_entry_group_counts[i]; - int nrstringtables = ObjectTypeStringTableCount[i]; - stringid += nrobjects * nrstringtables; - } - stringid += index * ObjectTypeStringTableCount[type]; - // Used by the object list to allocate name in plugin.dat - RCT2_GLOBAL(RCT2_ADDRESS_CURR_OBJECT_BASE_STRING_ID, uint32) = stringid; - stringid += tableindex; - - // cache UTF-8 string - int cacheStringOffset = stringid - STEX_BASE_STRING_ID; - utf8 **cacheString = &_cachedObjectStrings[cacheStringOffset]; - if (*cacheString != nullptr) { - free(*cacheString); - } - if (rct2_language_is_multibyte_charset(chosenLanguageId)) { - *cacheString = convert_multibyte_charset(pString, chosenLanguageId); - } else { - *cacheString = win1252_to_utf8_alloc(pString); - } - utf8_trim_string(*cacheString); - - //put pointer in stringtable - _languageCurrent->SetString(stringid, *cacheString); - // Until all string related functions are finished copy - // to old array as well. - _languageOriginal[stringid] = *cacheString; - return stringid; - } else { - int stringid = STEX_BASE_STRING_ID + tableindex; - - // cache UTF-8 string - int cacheStringOffset = stringid - STEX_BASE_STRING_ID; - utf8 **cacheString = &_cachedObjectStrings[cacheStringOffset]; - if (*cacheString != nullptr) { - free(*cacheString); - } - if (rct2_language_is_multibyte_charset(chosenLanguageId)) { - *cacheString = convert_multibyte_charset(pString, chosenLanguageId); - } else { - *cacheString = win1252_to_utf8_alloc(pString); - } - utf8_trim_string(*cacheString); - - //put pointer in stringtable - _languageCurrent->SetString(stringid, *cacheString); - // Until all string related functions are finished copy - // to old array as well. - _languageOriginal[stringid] = *cacheString; - return stringid; - } -} - bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_string_id *outStringIds) { outStringIds[0] = _languageCurrent->GetScenarioOverrideStringId(scenarioFilename, 0); diff --git a/src/localisation/language.h b/src/localisation/language.h index 4bcab7a61f..0a6823f4e3 100644 --- a/src/localisation/language.h +++ b/src/localisation/language.h @@ -69,8 +69,6 @@ const char *language_get_string(rct_string_id id); bool language_open(int id); void language_close_all(); -rct_string_id object_get_localised_text(uint8_t** pStringTable/*ebp*/, int type/*ecx*/, int index/*ebx*/, int tableindex/*edx*/); - uint32 utf8_get_next(const utf8 *char_ptr, const utf8 **nextchar_ptr); utf8 *utf8_write_codepoint(utf8 *dst, uint32 codepoint); int utf8_insert_codepoint(utf8 *dst, uint32 codepoint); diff --git a/src/object.c b/src/object.c deleted file mode 100644 index 5368758525..0000000000 --- a/src/object.c +++ /dev/null @@ -1,92 +0,0 @@ -#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers -/***************************************************************************** - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * OpenRCT2 is the work of many authors, a full list can be found in contributors.md - * For more information, visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * A full copy of the GNU General Public License can be found in licence.txt - *****************************************************************************/ -#pragma endregion - -#include "addresses.h" -#include "config.h" -#include "drawing/drawing.h" -#include "localisation/localisation.h" -#include "object.h" -#include "object_list.h" -#include "platform/platform.h" -#include "rct1.h" -#include "ride/ride.h" -#include "scenario.h" -#include "util/sawyercoding.h" -#include "world/entrance.h" -#include "world/footpath.h" -#include "world/scenery.h" -#include "world/water.h" - -char gTempObjectLoadName[9] = { 0 }; -uint32 gTotalNoImages = 0; - -int object_load_entry(const utf8 *path, rct_object_entry *outEntry) -{ - SDL_RWops *file; - - file = SDL_RWFromFile(path, "rb"); - if (file == NULL) - return 0; - - if (SDL_RWread(file, outEntry, sizeof(rct_object_entry), 1) != 1) { - SDL_RWclose(file); - return 0; - } - - SDL_RWclose(file); - return 1; -} - -int 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->flags & 0x0F) != (b->flags & 0x0F)) - return 0; - int match = memcmp(a->name, b->name, 8); - if (match) - return 0; - } - else { - if (a->flags != b->flags) - return 0; - int match = memcmp(a->name, b->name, 8); - if (match) - return 0; - if (a->checksum != b->checksum) - return 0; - } - - return 1; -} - -int object_calculate_checksum(const rct_object_entry *entry, const uint8 *data, int dataLength) -{ - const uint8 *entryBytePtr = (uint8*)entry; - - uint32 checksum = 0xF369A75B; - checksum ^= entryBytePtr[0]; - checksum = rol32(checksum, 11); - for (int i = 4; i < 12; i++) { - checksum ^= entryBytePtr[i]; - checksum = rol32(checksum, 11); - } - for (int i = 0; i < dataLength; i++) { - checksum ^= data[i]; - checksum = rol32(checksum, 11); - } - return (int)checksum; -} diff --git a/src/object.h b/src/object.h index abf9b63a30..157348e49f 100644 --- a/src/object.h +++ b/src/object.h @@ -105,11 +105,7 @@ assert_struct_size(rct_object_filters, 3); #pragma pack(pop) extern const rct_object_entry_group object_entry_groups[]; -extern char gTempObjectLoadName[9]; -extern uint32 gTotalNoImages; - -int object_load_entry(const utf8 *path, rct_object_entry *outEntry); void object_list_load(); void set_load_objects_fail_reason(); bool object_read_and_load_entries(SDL_RWops* rw); @@ -120,8 +116,8 @@ void object_unload_all(); int check_object_entry(rct_object_entry *entry); bool object_load_chunk(int groupIndex, const rct_object_entry * entry, int * outGroupIndex); -int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b); -int object_calculate_checksum(const rct_object_entry *entry, const uint8 *data, int dataLength); +bool object_entry_compare(const rct_object_entry *a, const rct_object_entry *b); +int object_calculate_checksum(const rct_object_entry * entry, const void * data, size_t dataLength); void reset_loaded_objects(); int find_object_in_entry_group(const rct_object_entry* entry, uint8* entry_type, uint8* entry_index); void object_create_identifier_name(char* string_buffer, const rct_object_entry* object); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index cd6f2383cf..07a35523bb 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -640,8 +640,6 @@ extern "C" void reset_loaded_objects() { - gTotalNoImages = 0xF26E; - for (int i = 0; i < 721; i++) { Object * object = _loadedObjects[i]; @@ -881,4 +879,61 @@ extern "C" const Object * baseObject = (const Object *)object; baseObject->DrawPreview(dpi); } + + 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->flags & 0x0F) != (b->flags & 0x0F)) + { + return 0; + } + int match = memcmp(a->name, b->name, 8); + if (match) + { + return 0; + } + } + else + { + if (a->flags != b->flags) + { + return 0; + } + int match = memcmp(a->name, b->name, 8); + if (match) + { + return 0; + } + if (a->checksum != b->checksum) + { + return 0; + } + } + return 1; + } + + int object_calculate_checksum(const rct_object_entry * entry, const void * data, size_t dataLength) + { + const uint8 *entryBytePtr = (uint8*)entry; + + uint32 checksum = 0xF369A75B; + checksum ^= entryBytePtr[0]; + checksum = rol32(checksum, 11); + for (int i = 4; i < 12; i++) + { + checksum ^= entryBytePtr[i]; + checksum = rol32(checksum, 11); + } + + uint8 * dataBytes = (uint8 *)data; + for (size_t i = 0; i < dataLength; i++) + { + checksum ^= dataBytes[i]; + checksum = rol32(checksum, 11); + } + + return (int)checksum; + } } diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index 01b9f75ce3..e092b292a3 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -304,35 +304,6 @@ void RideObject::Load() vehicleEntry->peep_loading_positions = _peepLoadingPositions[i]; } } - - // 0x6DEB71 - if (RCT2_GLOBAL(0x9ADAFD, uint8) == 0) - { - for (int i = 0; i < 3; i++) - { - sint16 rideType = _legacyType.ride_type[i]; - if (rideType != RIDE_TYPE_NULL) - { - uint8 * typeToRideEntryIndexMap = gTypeToRideEntryIndexMap; - while (rideType >= 0) - { - if (*typeToRideEntryIndexMap++ == 0xFF) - { - rideType--; - } - } - - typeToRideEntryIndexMap--; - uint8 previous_entry = 0; // TODO set this to entryIndex - while (typeToRideEntryIndexMap < gTypeToRideEntryIndexMap + Util::CountOf(gTypeToRideEntryIndexMap)) - { - uint8 backup_entry = *typeToRideEntryIndexMap; - *typeToRideEntryIndexMap++ = previous_entry; - previous_entry = backup_entry; - } - } - } - } } void RideObject::Unload() diff --git a/src/object/WaterObject.cpp b/src/object/WaterObject.cpp index cbe669a985..4ad0616341 100644 --- a/src/object/WaterObject.cpp +++ b/src/object/WaterObject.cpp @@ -47,11 +47,8 @@ void WaterObject::Load() _legacyType.var_06 = _legacyType.image_id + 1; _legacyType.var_0A = _legacyType.image_id + 4; - if (RCT2_GLOBAL(0x009ADAFD, uint8) == 0) - { - load_palette(); - gfx_invalidate_screen(); - } + load_palette(); + gfx_invalidate_screen(); } void WaterObject::Unload() From 3bfa747ce4bb091a8057b9c1d51c6c1308e75d15 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 2 Jul 2016 23:03:25 +0100 Subject: [PATCH 061/116] implement a proper image list allocation --- openrct2.vcxproj | 1 + src/drawing/Image.cpp | 100 ++++++++++++++++++++++++++++++++++++++++++ src/drawing/sprite.c | 24 ---------- 3 files changed, 101 insertions(+), 24 deletions(-) create mode 100644 src/drawing/Image.cpp diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 42eb95041d..df88b9b32d 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -68,6 +68,7 @@ + diff --git a/src/drawing/Image.cpp b/src/drawing/Image.cpp new file mode 100644 index 0000000000..8e026686dd --- /dev/null +++ b/src/drawing/Image.cpp @@ -0,0 +1,100 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include +#include "../core/Guard.hpp" + +extern "C" +{ + #include "drawing.h" +} + +constexpr uint32 BASE_IMAGE_ID = 29294; +constexpr uint32 MAX_IMAGES = 262144; +constexpr uint32 INVALID_IMAGE_ID = UINT32_MAX; + +struct ImageList +{ + uint32 BaseId; + uint32 Count; +}; + +static bool _initialised = false; +static std::list _freeLists; + +static uint32 AllocateImageList(uint32 count) +{ + if (!_initialised) + { + _initialised = true; + _freeLists.clear(); + _freeLists.push_back({ BASE_IMAGE_ID, MAX_IMAGES }); + } + + for (auto it = _freeLists.begin(); it != _freeLists.end(); it++) + { + ImageList imageList = *it; + if (imageList.Count >= count) + { + _freeLists.erase(it); + if (imageList.Count > count) + { + ImageList remainder = { imageList.BaseId + count, + imageList.Count - count }; + _freeLists.push_back(remainder); + } + + return imageList.BaseId; + } + } + return INVALID_IMAGE_ID; +} + +static void FreeImageList(uint32 baseImageId, uint32 count) +{ + Guard::Assert(_initialised); + + // TODO validate that this was an allocated list + _freeLists.push_back({ baseImageId, count }); +} + +extern "C" +{ + uint32 gfx_object_allocate_images(const rct_g1_element * images, uint32 count) + { + uint32 baseImageId = AllocateImageList(count); + if (baseImageId == INVALID_IMAGE_ID) + { + log_error("Reached maximum image limit."); + return INVALID_IMAGE_ID; + } + + uint32 imageId = baseImageId; + for (uint32 i = 0; i < count; i++) + { + g1Elements[imageId] = images[i]; + drawing_engine_invalidate_image(imageId); + imageId++; + } + + return baseImageId; + } + + void gfx_object_free_images(uint32 baseImageId, uint32 count) + { + FreeImageList(baseImageId, count); + } +} diff --git a/src/drawing/sprite.c b/src/drawing/sprite.c index e1983c881a..26458bb1ab 100644 --- a/src/drawing/sprite.c +++ b/src/drawing/sprite.c @@ -173,30 +173,6 @@ int gfx_load_g2() return 0; } -static uint32 _nextImageId = 29294; - -uint32 gfx_object_allocate_images(const rct_g1_element * images, uint32 count) -{ - uint32 baseImageId = _nextImageId; - for (uint32 i = 0; i < count; i++) { - uint32 imageId = _nextImageId; - if (imageId >= 291438) { - log_error("Reached maximum image limit."); - break; - } - - g1Elements[imageId] = images[i]; - drawing_engine_invalidate_image(imageId); - _nextImageId++; - } - return baseImageId; -} - -void gfx_object_free_images(uint32 baseImageId, uint32 count) -{ - _nextImageId = 29294; -} - /** * This function looks like it initialises the 0x009E3CE4 array which references sprites used for background / palette mixing or * something. Further investigation is needed. From 6f97ec798e2869d16cae90a938002deaa81b1772 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 3 Jul 2016 15:13:36 +0100 Subject: [PATCH 062/116] remove object entry addresses and use constants --- src/object/ObjectRepository.cpp | 8 +++---- src/object_list.c | 24 ++++++++++++++++--- src/object_list.h | 3 ++- src/rct2/S6Exporter.cpp | 11 ++++----- src/scenario.c | 41 +++++++++++++-------------------- 5 files changed, 48 insertions(+), 39 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 07a35523bb..d337356692 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -561,7 +561,7 @@ IObjectRepository * GetObjectRepository() return _objectRepository; } -Object * _loadedObjects[721] = { nullptr }; +Object * _loadedObjects[OBJECT_ENTRY_COUNT] = { nullptr }; int GetObjectEntryIndex(uint8 objectType, uint8 entryIndex) { @@ -640,7 +640,7 @@ extern "C" void reset_loaded_objects() { - for (int i = 0; i < 721; i++) + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) { Object * object = _loadedObjects[i]; if (object != nullptr) @@ -662,7 +662,7 @@ extern "C" void * object_repository_find_loaded_object(const rct_object_entry * objectEntry) { - for (size_t i = 0; i < 721; i++) + for (size_t i = 0; i < OBJECT_ENTRY_COUNT; i++) { Object * object = _loadedObjects[i]; if (object != nullptr) @@ -690,7 +690,7 @@ extern "C" void object_unload_all() { - for (int i = 0; i < 721; i++) + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) { Object * object = _loadedObjects[i]; if (object != nullptr) diff --git a/src/object_list.c b/src/object_list.c index 28ac2f5bf1..e70a314049 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -259,19 +259,37 @@ void object_list_init() } } -void *get_loaded_object_entry(size_t index) +void get_type_entry_index(size_t index, uint8 * outObjectType, uint8 * outEntryIndex) { uint8 objectType = OBJECT_TYPE_RIDE; for (size_t i = 0; i < OBJECT_ENTRY_GROUP_COUNT; i++) { size_t groupCount = object_entry_group_counts[i]; if (index >= groupCount) { - index -= object_entry_group_counts[i]; + index -= groupCount; objectType++; } else { break; } } - void *entry = object_entry_groups[objectType].chunks[index]; + if (outObjectType != NULL) *outObjectType = objectType; + if (outEntryIndex != NULL) *outEntryIndex = (uint8)index; +} + +const rct_object_entry * get_loaded_object_entry(size_t index) +{ + uint8 objectType, entryIndex; + get_type_entry_index(index, &objectType, &entryIndex); + + rct_object_entry * entry = (rct_object_entry *)&(object_entry_groups[objectType].entries[entryIndex]); + return entry; +} + +void * get_loaded_object_chunk(size_t index) +{ + uint8 objectType, entryIndex; + get_type_entry_index(index, &objectType, &entryIndex); + + void *entry = object_entry_groups[objectType].chunks[entryIndex]; return entry; } diff --git a/src/object_list.h b/src/object_list.h index 6e1e6a3463..4277cb569e 100644 --- a/src/object_list.h +++ b/src/object_list.h @@ -34,4 +34,5 @@ #endif void object_list_init(); -void *get_loaded_object_entry(size_t index); +const rct_object_entry * get_loaded_object_entry(size_t index); +void * get_loaded_object_chunk(size_t index); diff --git a/src/rct2/S6Exporter.cpp b/src/rct2/S6Exporter.cpp index e83d988234..77e97b2fb5 100644 --- a/src/rct2/S6Exporter.cpp +++ b/src/rct2/S6Exporter.cpp @@ -132,7 +132,7 @@ void S6Exporter::Save(SDL_RWops * rw, bool isScenario) // 3: Write available objects chunk chunkHeader.encoding = CHUNK_ENCODING_ROTATE; - chunkHeader.length = 721 * sizeof(rct_object_entry); + chunkHeader.length = OBJECT_ENTRY_COUNT * sizeof(rct_object_entry); encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)_s6.objects, chunkHeader); SDL_RWwrite(rw, buffer, encodedLength, 1); @@ -228,19 +228,18 @@ void S6Exporter::Export() { _s6.info = *gS6Info; - for (int i = 0; i < 721; i++) + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) { - rct_object_entry_extended *entry = &(RCT2_ADDRESS(0x00F3F03C, rct_object_entry_extended)[i]); - void *entryData = get_loaded_object_entry(i); + const rct_object_entry * entry = get_loaded_object_entry(i); + void * entryData = get_loaded_object_chunk(i); if (entryData == (void *)0xFFFFFFFF) { - memset(&_s6.objects[i], 0xFF, sizeof(rct_object_entry)); + Memory::Set(&_s6.objects[i], 0xFF, sizeof(rct_object_entry)); } else { _s6.objects[i] = *((rct_object_entry*)entry); } - } _s6.elapsed_months = gDateMonthsElapsed; diff --git a/src/scenario.c b/src/scenario.c index a51628ec76..996e5921b9 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -700,17 +700,14 @@ int scenario_prepare_for_save() */ int scenario_get_num_packed_objects_to_write() { - int i, count = 0; - rct_object_entry_extended *entry = (rct_object_entry_extended*)0x00F3F03C; - - for (i = 0; i < OBJECT_ENTRY_COUNT; i++, entry++) { - void *entryData = get_loaded_object_entry(i); - if (entryData == (void*)0xFFFFFFFF || (entry->flags & 0xF0)) { - continue; + int count = 0; + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) { + const rct_object_entry *entry = get_loaded_object_entry(i); + void *entryData = get_loaded_object_chunk(i); + if (entryData != (void*)0xFFFFFFFF && !(entry->flags & 0xF0)) { + count++; } - count++; } - return count; } @@ -720,18 +717,15 @@ int scenario_get_num_packed_objects_to_write() */ int scenario_write_packed_objects(SDL_RWops* rw) { - int i; - rct_object_entry_extended *entry = (rct_object_entry_extended*)0x00F3F03C; - for (i = 0; i < OBJECT_ENTRY_COUNT; i++, entry++) { - void *entryData = get_loaded_object_entry(i); - if (entryData == (void*)0xFFFFFFFF || (entry->flags & 0xF0)) { - continue; - } - if (!object_saved_packed(rw, (rct_object_entry*)entry)) { - return 0; + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) { + const rct_object_entry *entry = get_loaded_object_entry(i); + void *entryData = get_loaded_object_chunk(i); + if (entryData != (void*)0xFFFFFFFF && !(entry->flags & 0xF0)) { + if (!object_saved_packed(rw, entry)) { + return 0; + } } } - return 1; } @@ -745,7 +739,7 @@ int scenario_write_available_objects(FILE *file) int i, encodedLength; sawyercoding_chunk_header chunkHeader; - const int totalEntries = 721; + const int totalEntries = OBJECT_ENTRY_COUNT; const int bufferLength = totalEntries * sizeof(rct_object_entry); // Initialise buffers @@ -762,17 +756,14 @@ int scenario_write_available_objects(FILE *file) } // Write entries - rct_object_entry_extended *srcEntry = (rct_object_entry_extended*)0x00F3F03C; rct_object_entry *dstEntry = (rct_object_entry*)buffer; for (i = 0; i < OBJECT_ENTRY_COUNT; i++) { - void *entryData = get_loaded_object_entry(i); + void *entryData = get_loaded_object_chunk(i); if (entryData == (void*)0xFFFFFFFF) { memset(dstEntry, 0xFF, sizeof(rct_object_entry)); } else { - *dstEntry = *((rct_object_entry*)srcEntry); + *dstEntry = *get_loaded_object_entry(i); } - - srcEntry++; dstEntry++; } From 80381cfaa043d50bd507dd7ed5ca8e1d085e68ac Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 3 Jul 2016 17:10:22 +0100 Subject: [PATCH 063/116] fix objects always been packed into saves --- src/rct2/S6Exporter.cpp | 2 +- src/rct2/S6Importer.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rct2/S6Exporter.cpp b/src/rct2/S6Exporter.cpp index 77e97b2fb5..ec9e6e8a5d 100644 --- a/src/rct2/S6Exporter.cpp +++ b/src/rct2/S6Exporter.cpp @@ -89,7 +89,7 @@ void S6Exporter::SaveScenario(SDL_RWops *rw) void S6Exporter::Save(SDL_RWops * rw, bool isScenario) { _s6.header.type = isScenario ? S6_TYPE_SCENARIO : S6_TYPE_SAVEDGAME; - _s6.header.num_packed_objects = scenario_get_num_packed_objects_to_write(); + _s6.header.num_packed_objects = ExportObjects ? scenario_get_num_packed_objects_to_write() : 0; _s6.header.version = S6_RCT2_VERSION; _s6.header.magic_number = S6_MAGIC_NUMBER; diff --git a/src/rct2/S6Importer.cpp b/src/rct2/S6Importer.cpp index c8f7b13c7d..8088765d6c 100644 --- a/src/rct2/S6Importer.cpp +++ b/src/rct2/S6Importer.cpp @@ -372,7 +372,8 @@ void S6Importer::Import() // pad_13CE778 // Fix and set dynamic variables - if (!object_load_entries(_s6.objects)) { + if (!object_load_entries(_s6.objects)) + { throw ObjectLoadException(); } reset_loaded_objects(); From 52928e1e08bb3ad00bcd44d8b4f16643a0ae3557 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 3 Jul 2016 18:02:18 +0100 Subject: [PATCH 064/116] protect objects against invalid allocation ids --- src/drawing/Image.cpp | 6 +++++- src/localisation/language.cpp | 9 ++++++--- src/object/BannerObject.cpp | 7 ++++--- src/object/BannerObject.h | 4 ++-- src/object/EntranceObject.cpp | 6 ++++-- src/object/EntranceObject.h | 2 +- src/object/FootpathItemObject.cpp | 6 ++++-- src/object/FootpathItemObject.h | 4 ++-- src/object/FootpathObject.cpp | 7 ++++--- src/object/FootpathObject.h | 2 +- src/object/LargeSceneryObject.cpp | 7 ++++--- src/object/LargeSceneryObject.h | 4 ++-- src/object/ObjectRepository.cpp | 1 + src/object/RideObject.cpp | 7 +++++++ src/object/RideObject.h | 2 +- src/object/SceneryGroupObject.cpp | 6 ++++-- src/object/SceneryGroupObject.h | 6 +++--- src/object/SmallSceneryObject.cpp | 12 ++++-------- src/object/SmallSceneryObject.h | 4 ++-- src/object/StexObject.cpp | 8 +++++--- src/object/StexObject.h | 2 +- src/object/WallObject.cpp | 7 ++++--- src/object/WallObject.h | 4 ++-- src/object/WaterObject.cpp | 5 +++-- src/object/WaterObject.h | 2 +- src/rct2/S6Exporter.cpp | 2 +- 26 files changed, 78 insertions(+), 54 deletions(-) diff --git a/src/drawing/Image.cpp b/src/drawing/Image.cpp index 8e026686dd..e4d88b8967 100644 --- a/src/drawing/Image.cpp +++ b/src/drawing/Image.cpp @@ -66,6 +66,7 @@ static uint32 AllocateImageList(uint32 count) static void FreeImageList(uint32 baseImageId, uint32 count) { Guard::Assert(_initialised); + Guard::Assert(baseImageId >= BASE_IMAGE_ID); // TODO validate that this was an allocated list _freeLists.push_back({ baseImageId, count }); @@ -95,6 +96,9 @@ extern "C" void gfx_object_free_images(uint32 baseImageId, uint32 count) { - FreeImageList(baseImageId, count); + if (baseImageId != 0) + { + FreeImageList(baseImageId, count); + } } } diff --git a/src/localisation/language.cpp b/src/localisation/language.cpp index b3c8f75d01..f4dc609711 100644 --- a/src/localisation/language.cpp +++ b/src/localisation/language.cpp @@ -355,11 +355,14 @@ rct_string_id language_allocate_object_string(const utf8 * target) void language_free_object_string(rct_string_id stringId) { - if (_languageCurrent != nullptr) + if (stringId != 0) { - _languageCurrent->SetString(stringId, nullptr); + if (_languageCurrent != nullptr) + { + _languageCurrent->SetString(stringId, nullptr); + } + _availableObjectStringIds.push(stringId); } - _availableObjectStringIds.push(stringId); } } diff --git a/src/object/BannerObject.cpp b/src/object/BannerObject.cpp index c4cba5beaf..99fcf16ec3 100644 --- a/src/object/BannerObject.cpp +++ b/src/object/BannerObject.cpp @@ -31,9 +31,7 @@ enum OBJ_STRING_ID void BannerObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { - _legacyType.name = stream->ReadValue(); - _legacyType.image = stream->ReadValue(); - + stream->Seek(6, STREAM_SEEK_CURRENT); _legacyType.banner.scrolling_mode = stream->ReadValue(); _legacyType.banner.flags = stream->ReadValue(); _legacyType.banner.price = stream->ReadValue(); @@ -72,6 +70,9 @@ void BannerObject::Unload() { language_free_object_string(_legacyType.name); gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); + + _legacyType.name = 0; + _legacyType.image = 0; } void BannerObject::DrawPreview(rct_drawpixelinfo * dpi) const diff --git a/src/object/BannerObject.h b/src/object/BannerObject.h index 933816c3b9..a7dc09d218 100644 --- a/src/object/BannerObject.h +++ b/src/object/BannerObject.h @@ -26,8 +26,8 @@ extern "C" class BannerObject : public Object { private: - rct_scenery_entry _legacyType; - rct_object_entry _sceneryTabEntry; + rct_scenery_entry _legacyType = { 0 }; + rct_object_entry _sceneryTabEntry = { 0 }; public: explicit BannerObject(const rct_object_entry &entry) : Object(entry) { }; diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index b302d1fb82..da81343e1b 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -30,8 +30,7 @@ enum OBJ_STRING_ID void EntranceObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { - _legacyType.string_idx = stream->ReadValue(); - _legacyType.image_id = stream->ReadValue(); + stream->Seek(6, STREAM_SEEK_CURRENT); _legacyType.scrolling_mode = stream->ReadValue(); _legacyType.text_height = stream->ReadValue(); @@ -49,6 +48,9 @@ void EntranceObject::Unload() { language_free_object_string(_legacyType.string_idx); gfx_object_free_images(_legacyType.image_id, GetImageTable()->GetCount()); + + _legacyType.string_idx = 0; + _legacyType.image_id = 0; } void EntranceObject::DrawPreview(rct_drawpixelinfo * dpi) const diff --git a/src/object/EntranceObject.h b/src/object/EntranceObject.h index be843883b8..cb370e8c0d 100644 --- a/src/object/EntranceObject.h +++ b/src/object/EntranceObject.h @@ -26,7 +26,7 @@ extern "C" class EntranceObject : public Object { private: - rct_entrance_type _legacyType; + rct_entrance_type _legacyType = { 0 }; public: explicit EntranceObject(const rct_object_entry &entry) : Object(entry) { }; diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp index 48f2916424..0852ed1a49 100644 --- a/src/object/FootpathItemObject.cpp +++ b/src/object/FootpathItemObject.cpp @@ -30,8 +30,7 @@ enum OBJ_STRING_ID void FootpathItemObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { - _legacyType.name = stream->ReadValue(); - _legacyType.image = stream->ReadValue(); + stream->Seek(6, STREAM_SEEK_CURRENT); _legacyType.path_bit.flags = stream->ReadValue(); _legacyType.path_bit.draw_type = stream->ReadValue(); _legacyType.path_bit.tool_id = stream->ReadValue(); @@ -71,6 +70,9 @@ void FootpathItemObject::Unload() { language_free_object_string(_legacyType.name); gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); + + _legacyType.name = 0; + _legacyType.image = 0; } void FootpathItemObject::DrawPreview(rct_drawpixelinfo * dpi) const diff --git a/src/object/FootpathItemObject.h b/src/object/FootpathItemObject.h index 5fe3956359..6aabe8b58c 100644 --- a/src/object/FootpathItemObject.h +++ b/src/object/FootpathItemObject.h @@ -26,8 +26,8 @@ extern "C" class FootpathItemObject : public Object { private: - rct_scenery_entry _legacyType; - rct_object_entry _sceneryTabEntry; + rct_scenery_entry _legacyType = { 0 }; + rct_object_entry _sceneryTabEntry = { 0 }; public: explicit FootpathItemObject(const rct_object_entry &entry) : Object(entry) { }; diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp index 2580f42f01..b7bfe4c928 100644 --- a/src/object/FootpathObject.cpp +++ b/src/object/FootpathObject.cpp @@ -31,9 +31,7 @@ enum OBJ_STRING_ID void FootpathObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { - _legacyType.string_idx = stream->ReadValue(); - _legacyType.image = stream->ReadValue(); - _legacyType.bridge_image = stream->ReadValue(); + stream->Seek(10, STREAM_SEEK_CURRENT); _legacyType.var_0A = stream->ReadValue(); _legacyType.flags = stream->ReadValue(); _legacyType.scrolling_mode = stream->ReadValue(); @@ -60,6 +58,9 @@ void FootpathObject::Unload() { language_free_object_string(_legacyType.string_idx); gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); + + _legacyType.string_idx = 0; + _legacyType.image = 0; } void FootpathObject::DrawPreview(rct_drawpixelinfo * dpi) const diff --git a/src/object/FootpathObject.h b/src/object/FootpathObject.h index ef4d3638a0..6bf997e6e1 100644 --- a/src/object/FootpathObject.h +++ b/src/object/FootpathObject.h @@ -26,7 +26,7 @@ extern "C" class FootpathObject : public Object { private: - rct_footpath_entry _legacyType; + rct_footpath_entry _legacyType = { 0 }; public: explicit FootpathObject(const rct_object_entry &entry) : Object(entry) { }; diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index cefb6828da..7a76701fba 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -37,9 +37,7 @@ LargeSceneryObject::~LargeSceneryObject() void LargeSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { - _legacyType.name = stream->ReadValue(); - _legacyType.image = stream->ReadValue(); - + stream->Seek(6, STREAM_SEEK_CURRENT); _legacyType.large_scenery.tool_id = stream->ReadValue(); _legacyType.large_scenery.flags = stream->ReadValue(); _legacyType.large_scenery.price = stream->ReadValue(); @@ -115,6 +113,9 @@ void LargeSceneryObject::Unload() { language_free_object_string(_legacyType.name); gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); + + _legacyType.name = 0; + _legacyType.image = 0; } void LargeSceneryObject::DrawPreview(rct_drawpixelinfo * dpi) const diff --git a/src/object/LargeSceneryObject.h b/src/object/LargeSceneryObject.h index 708b9f09c4..1034243988 100644 --- a/src/object/LargeSceneryObject.h +++ b/src/object/LargeSceneryObject.h @@ -26,8 +26,8 @@ extern "C" class LargeSceneryObject : public Object { private: - rct_scenery_entry _legacyType; - rct_object_entry _sceneryTabEntry; + rct_scenery_entry _legacyType = { 0 }; + rct_object_entry _sceneryTabEntry = { 0 }; rct_large_scenery_text * _3dFont = nullptr; rct_large_scenery_tile * _tiles = nullptr; diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index d337356692..9e1c9ce72a 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -645,6 +645,7 @@ extern "C" Object * object = _loadedObjects[i]; if (object != nullptr) { + object->Unload(); object->Load(); } } diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index e092b292a3..22929f6ae0 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -46,6 +46,9 @@ RideObject::~RideObject() void RideObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { stream->Read(&_legacyType); + _legacyType.name = 0; + _legacyType.description = 0; + _legacyType.images_offset = 0; GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); GetStringTable()->Read(context, stream, OBJ_STRING_ID_DESCRIPTION); @@ -311,6 +314,10 @@ void RideObject::Unload() language_free_object_string(_legacyType.name); language_free_object_string(_legacyType.description); gfx_object_free_images(_legacyType.images_offset, GetImageTable()->GetCount()); + + _legacyType.name = 0; + _legacyType.description = 0; + _legacyType.images_offset = 0; } void RideObject::DrawPreview(rct_drawpixelinfo * dpi) const diff --git a/src/object/RideObject.h b/src/object/RideObject.h index d53b9901df..2f8d0f097a 100644 --- a/src/object/RideObject.h +++ b/src/object/RideObject.h @@ -26,7 +26,7 @@ extern "C" class RideObject : public Object { private: - rct_ride_entry _legacyType; + rct_ride_entry _legacyType = { 0 }; vehicle_colour_preset_list _presetColours = { 0 }; sint8 * _peepLoadingPositions[4] = { nullptr }; diff --git a/src/object/SceneryGroupObject.cpp b/src/object/SceneryGroupObject.cpp index c2d1094867..74b2df8148 100644 --- a/src/object/SceneryGroupObject.cpp +++ b/src/object/SceneryGroupObject.cpp @@ -37,8 +37,7 @@ SceneryGroupObject::~SceneryGroupObject() void SceneryGroupObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { - _legacyType.name = stream->ReadValue(); - _legacyType.image = stream->ReadValue(); + stream->Seek(6, STREAM_SEEK_CURRENT); stream->Seek(0x80 * 2, STREAM_SEEK_CURRENT); _legacyType.entry_count = stream->ReadValue(); _legacyType.var_107 = stream->ReadValue(); @@ -84,6 +83,9 @@ void SceneryGroupObject::Unload() { language_free_object_string(_legacyType.name); gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); + + _legacyType.name = 0; + _legacyType.image = 0; } void SceneryGroupObject::DrawPreview(rct_drawpixelinfo * dpi) const diff --git a/src/object/SceneryGroupObject.h b/src/object/SceneryGroupObject.h index f2867bdc1b..a8715fc309 100644 --- a/src/object/SceneryGroupObject.h +++ b/src/object/SceneryGroupObject.h @@ -28,9 +28,9 @@ struct ObjectRepositoryItem; class SceneryGroupObject : public Object { private: - rct_scenery_set_entry _legacyType; - uint32 _numItems; - rct_object_entry * _items; + rct_scenery_set_entry _legacyType = { 0 }; + uint32 _numItems = 0; + rct_object_entry * _items = nullptr; public: explicit SceneryGroupObject(const rct_object_entry &entry) : Object(entry) { }; diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index 13133cf1d2..9c97b08bd5 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -37,9 +37,7 @@ SmallSceneryObject::~SmallSceneryObject() void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { - _legacyType.name = stream->ReadValue(); - _legacyType.image = stream->ReadValue(); - + stream->Seek(6, STREAM_SEEK_CURRENT); _legacyType.small_scenery.flags = stream->ReadValue(); _legacyType.small_scenery.height = stream->ReadValue(); _legacyType.small_scenery.tool_id = stream->ReadValue(); @@ -103,15 +101,13 @@ void SmallSceneryObject::Unload() { language_free_object_string(_legacyType.name); gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); + + _legacyType.name = 0; + _legacyType.image = 0; } void SmallSceneryObject::DrawPreview(rct_drawpixelinfo * dpi) const { - // rct_drawpixelinfo clipDPI; - // if (!clip_drawpixelinfo(&clipDPI, dpi, x - 56, y - 56, 112, 112)) { - // return; - // } - uint32 flags = _legacyType.small_scenery.flags; uint32 imageId = _legacyType.image; if (flags & SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR) diff --git a/src/object/SmallSceneryObject.h b/src/object/SmallSceneryObject.h index 9e87b3a2f9..173b0025fb 100644 --- a/src/object/SmallSceneryObject.h +++ b/src/object/SmallSceneryObject.h @@ -26,8 +26,8 @@ extern "C" class SmallSceneryObject : public Object { private: - rct_scenery_entry _legacyType; - rct_object_entry _sceneryTabEntry; + rct_scenery_entry _legacyType = { 0 }; + rct_object_entry _sceneryTabEntry = { 0 }; uint8 * _var10data = nullptr; public: diff --git a/src/object/StexObject.cpp b/src/object/StexObject.cpp index 8023b25b46..9b83b4515f 100644 --- a/src/object/StexObject.cpp +++ b/src/object/StexObject.cpp @@ -31,9 +31,7 @@ enum OBJ_STRING_ID void StexObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { - _legacyType.scenario_name = stream->ReadValue(); - _legacyType.park_name = stream->ReadValue(); - _legacyType.details = stream->ReadValue(); + stream->Seek(6, STREAM_SEEK_CURRENT); _legacyType.var_06 = stream->ReadValue(); stream->Seek(1, STREAM_SEEK_CURRENT); @@ -54,6 +52,10 @@ void StexObject::Unload() language_free_object_string(_legacyType.scenario_name); language_free_object_string(_legacyType.park_name); language_free_object_string(_legacyType.details); + + _legacyType.scenario_name = 0; + _legacyType.park_name = 0; + _legacyType.details = 0; } void StexObject::DrawPreview(rct_drawpixelinfo * dpi) const diff --git a/src/object/StexObject.h b/src/object/StexObject.h index 6032ef5de7..ba09077ebd 100644 --- a/src/object/StexObject.h +++ b/src/object/StexObject.h @@ -26,7 +26,7 @@ extern "C" class StexObject : public Object { private: - rct_stex_entry _legacyType; + rct_stex_entry _legacyType = { 0 }; public: explicit StexObject(const rct_object_entry &entry) : Object(entry) { }; diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp index 1182551b5d..5a7276aac4 100644 --- a/src/object/WallObject.cpp +++ b/src/object/WallObject.cpp @@ -31,9 +31,7 @@ enum OBJ_STRING_ID void WallObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { - _legacyType.name = stream->ReadValue(); - _legacyType.image = stream->ReadValue(); - + stream->Seek(6, STREAM_SEEK_CURRENT); _legacyType.wall.tool_id = stream->ReadValue(); _legacyType.wall.flags = stream->ReadValue(); _legacyType.wall.height = stream->ReadValue(); @@ -75,6 +73,9 @@ void WallObject::Unload() { language_free_object_string(_legacyType.name); gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); + + _legacyType.name = 0; + _legacyType.image = 0; } void WallObject::DrawPreview(rct_drawpixelinfo * dpi) const diff --git a/src/object/WallObject.h b/src/object/WallObject.h index 51aed22c32..5dce93e816 100644 --- a/src/object/WallObject.h +++ b/src/object/WallObject.h @@ -26,8 +26,8 @@ extern "C" class WallObject : public Object { private: - rct_scenery_entry _legacyType; - rct_object_entry _sceneryTabEntry; + rct_scenery_entry _legacyType = { 0 }; + rct_object_entry _sceneryTabEntry = { 0 }; public: explicit WallObject(const rct_object_entry &entry) : Object(entry) { }; diff --git a/src/object/WaterObject.cpp b/src/object/WaterObject.cpp index 4ad0616341..a35d45121a 100644 --- a/src/object/WaterObject.cpp +++ b/src/object/WaterObject.cpp @@ -30,8 +30,7 @@ enum OBJ_STRING_ID void WaterObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { - _legacyType.string_idx = stream->ReadValue(); - _legacyType.image_id = stream->ReadValue(); + stream->Seek(6, STREAM_SEEK_CURRENT); _legacyType.var_06 = stream->ReadValue(); _legacyType.var_0A = stream->ReadValue(); _legacyType.var_0E = stream->ReadValue(); @@ -54,6 +53,8 @@ void WaterObject::Load() void WaterObject::Unload() { language_free_object_string(_legacyType.string_idx); + + _legacyType.string_idx = 0; } void WaterObject::DrawPreview(rct_drawpixelinfo * dpi) const diff --git a/src/object/WaterObject.h b/src/object/WaterObject.h index 2bc4deabbc..b0531ac4ae 100644 --- a/src/object/WaterObject.h +++ b/src/object/WaterObject.h @@ -26,7 +26,7 @@ extern "C" class WaterObject : public Object { private: - rct_water_type _legacyType; + rct_water_type _legacyType = { 0 }; public: explicit WaterObject(const rct_object_entry &entry) : Object(entry) { }; diff --git a/src/rct2/S6Exporter.cpp b/src/rct2/S6Exporter.cpp index ec9e6e8a5d..be20a8e3b2 100644 --- a/src/rct2/S6Exporter.cpp +++ b/src/rct2/S6Exporter.cpp @@ -507,7 +507,7 @@ extern "C" } delete s6exporter; - // reset_loaded_objects(); + reset_loaded_objects(); gfx_invalidate_screen(); if (result && !(flags & S6_SAVE_FLAG_AUTOMATIC)) From 4e259920b16099649fb931ad3bece49b8b120480 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 3 Jul 2016 19:48:21 +0100 Subject: [PATCH 065/116] fix and detect freeing invalid image lists --- src/drawing/Image.cpp | 32 +++++++++++++++++++++++++++++++ src/object/LargeSceneryObject.cpp | 5 +++-- src/object/LargeSceneryObject.h | 1 + 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/drawing/Image.cpp b/src/drawing/Image.cpp index e4d88b8967..0fab47c9b9 100644 --- a/src/drawing/Image.cpp +++ b/src/drawing/Image.cpp @@ -14,8 +14,11 @@ *****************************************************************************/ #pragma endregion +#include #include +#include "../core/Console.hpp" #include "../core/Guard.hpp" +#include "../core/Memory.hpp" extern "C" { @@ -35,13 +38,34 @@ struct ImageList static bool _initialised = false; static std::list _freeLists; +#ifdef DEBUG +static std::list _allocatedLists; + +static bool AllocatedListContains(uint32 baseImageId, uint32 count) +{ + bool contains = std::any_of( + _allocatedLists.begin(), + _allocatedLists.end(), + [baseImageId, count](const ImageList &imageList) -> bool + { + return imageList.BaseId == baseImageId && imageList.Count == count; + }); + return contains; +} +#endif + static uint32 AllocateImageList(uint32 count) { + Guard::Assert(count != 0); + if (!_initialised) { _initialised = true; _freeLists.clear(); _freeLists.push_back({ BASE_IMAGE_ID, MAX_IMAGES }); +#ifdef DEBUG + _allocatedLists.clear(); +#endif } for (auto it = _freeLists.begin(); it != _freeLists.end(); it++) @@ -57,6 +81,9 @@ static uint32 AllocateImageList(uint32 count) _freeLists.push_back(remainder); } +#ifdef DEBUG + _allocatedLists.push_back({ imageList.BaseId, count }); +#endif return imageList.BaseId; } } @@ -68,6 +95,11 @@ static void FreeImageList(uint32 baseImageId, uint32 count) Guard::Assert(_initialised); Guard::Assert(baseImageId >= BASE_IMAGE_ID); +#ifdef DEBUG + bool contains = AllocatedListContains(baseImageId, count); + Guard::Assert(contains); +#endif + // TODO validate that this was an allocated list _freeLists.push_back({ baseImageId, count }); } diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index 7a76701fba..94e1679d10 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -81,7 +81,8 @@ void LargeSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre void LargeSceneryObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); - _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); + _baseImageId = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); + _legacyType.image = _baseImageId; _legacyType.large_scenery.tiles = _tiles; @@ -112,7 +113,7 @@ void LargeSceneryObject::Load() void LargeSceneryObject::Unload() { language_free_object_string(_legacyType.name); - gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount()); + gfx_object_free_images(_baseImageId, GetImageTable()->GetCount()); _legacyType.name = 0; _legacyType.image = 0; diff --git a/src/object/LargeSceneryObject.h b/src/object/LargeSceneryObject.h index 1034243988..00d67c3dbb 100644 --- a/src/object/LargeSceneryObject.h +++ b/src/object/LargeSceneryObject.h @@ -27,6 +27,7 @@ class LargeSceneryObject : public Object { private: rct_scenery_entry _legacyType = { 0 }; + uint32 _baseImageId = 0; rct_object_entry _sceneryTabEntry = { 0 }; rct_large_scenery_text * _3dFont = nullptr; rct_large_scenery_tile * _tiles = nullptr; From e8635c1307d04baaf649c4d52bc7cbe4fa62599e Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 3 Jul 2016 21:05:18 +0100 Subject: [PATCH 066/116] prepare for better object loading --- src/object/ObjectRepository.cpp | 118 +++++++++++++++++++------- src/object/ObjectRepository.h | 23 ++--- src/object_list.c | 38 --------- src/rct2/S6Importer.cpp | 26 ++---- src/windows/editor_object_selection.c | 1 + 5 files changed, 108 insertions(+), 98 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 9e1c9ce72a..7385d3cc1f 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -44,7 +44,7 @@ extern "C" #include "../util/sawyercoding.h" } -constexpr uint16 OBJECT_REPOSITORY_VERSION = 7; +constexpr uint16 OBJECT_REPOSITORY_VERSION = 8; struct ObjectRepositoryHeader { @@ -155,14 +155,11 @@ public: return nullptr; } - Object * LoadObject(const rct_object_entry * objectEntry) override + Object * LoadObject(const ObjectRepositoryItem * ori) override { - Object * object = nullptr; - const ObjectRepositoryItem * item = FindObject(objectEntry); - if (item != nullptr) - { - object = ObjectFactory::CreateObjectFromLegacyFile(item->Path); - } + Guard::ArgumentNotNull(ori); + + Object * object = ObjectFactory::CreateObjectFromLegacyFile(ori->Path); return object; } @@ -388,9 +385,7 @@ private: item.ObjectEntry = stream->ReadValue(); item.Path = stream->ReadString(); - item.NumImages = stream->ReadValue(); item.Name = stream->ReadString(); - item.ChunkSize = stream->ReadValue(); switch (item.ObjectEntry.flags & 0x0F) { case OBJECT_TYPE_RIDE: @@ -420,9 +415,7 @@ private: { stream->WriteValue(item.ObjectEntry); stream->WriteString(item.Path); - stream->WriteValue(item.NumImages); stream->WriteString(item.Name); - stream->WriteValue(item.ChunkSize); switch (item.ObjectEntry.flags & 0x0F) { case OBJECT_TYPE_RIDE: @@ -597,15 +590,25 @@ extern "C" bool object_load_chunk(int groupIndex, const rct_object_entry * entry, int * outGroupIndex) { - IObjectRepository * objRepo = GetObjectRepository(); - Object * object = objRepo->LoadObject(entry); + IObjectRepository * objectRepository = GetObjectRepository(); + const ObjectRepositoryItem * ori = objectRepository->FindObject(entry); + if (ori == nullptr) + { + utf8 objName[9] = { 0 }; + Memory::Copy(objName, ori->ObjectEntry.name, 8); + Console::Error::WriteFormat("[%s]: Object not found.", objName); + Console::Error::WriteLine(); + return false; + } + + Object * object = objectRepository->LoadObject(ori); if (object == nullptr) { utf8 objName[9] = { 0 }; - Memory::Copy(objName, entry->name, 8); - Console::Error::WriteFormat("[%s]: Object not found or could not be loaded.", objName); + Memory::Copy(objName, ori->ObjectEntry.name, 8); + Console::Error::WriteFormat("[%s]: Object could not be loaded.", objName); Console::Error::WriteLine(); - return 0; + return false; } uint8 objectType = object->GetObjectType(); @@ -618,7 +621,7 @@ extern "C" { log_error("Object Load failed due to too many objects of a certain type."); delete object; - return 0; + return false; } } } @@ -635,7 +638,50 @@ extern "C" int loadedObjectIndex = GetObjectEntryIndex(objectType, groupIndex); delete _loadedObjects[loadedObjectIndex]; _loadedObjects[loadedObjectIndex] = object; - return 1; + return true; + } + + bool object_load_entries(rct_object_entry * entries) + { + log_verbose("loading required objects"); + + object_unload_all(); + + bool loadFailed = false; + + // Load each object + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) + { + if (check_object_entry(&entries[i])) + { + // Get entry group index + int entryGroupIndex = i; + for (int j = 0; j < OBJECT_ENTRY_GROUP_COUNT; j++) + { + if (entryGroupIndex < object_entry_group_counts[j]) + { + break; + } + entryGroupIndex -= object_entry_group_counts[j]; + } + + // Load the obect + if (!object_load_chunk(entryGroupIndex, &entries[i], NULL)) { + // log_error("failed to load entry: %.8s", entries[i].name); + // memcpy(gCommonFormatArgs, &entries[i], sizeof(rct_object_entry)); + loadFailed = true; + } + } + } + + if (loadFailed) + { + object_unload_all(); + return false; + } + + log_verbose("finished loading required objects"); + return true; } void reset_loaded_objects() @@ -655,9 +701,17 @@ extern "C" void * object_repository_load_object(const rct_object_entry * objectEntry) { + Object * object = nullptr; IObjectRepository * objRepository = GetObjectRepository(); - Object * object = objRepository->LoadObject(objectEntry); - object->Load(); + const ObjectRepositoryItem * ori = objRepository->FindObject(objectEntry); + if (ori != nullptr) + { + object = objRepository->LoadObject(ori); + if (object != nullptr) + { + object->Load(); + } + } return (void *)object; } @@ -730,18 +784,22 @@ extern "C" // Checks for a scenario string object (possibly for localisation) if ((stexObjectEntry->flags & 0xFF) != 255) { - IObjectRepository * objRepo = GetObjectRepository(); - Object * object = objRepo->LoadObject(stexObjectEntry); - if (object != nullptr) + IObjectRepository * objectRepository = GetObjectRepository(); + const ObjectRepositoryItem * ori = objectRepository->FindObject(stexObjectEntry); + if (ori != nullptr) { - StexObject * stexObject = static_cast(object); - const utf8 * scenarioName = stexObject->GetScenarioName(); - const utf8 * scenarioDetails = stexObject->GetScenarioDetails(); + Object * object = objectRepository->LoadObject(ori); + if (object != nullptr) + { + StexObject * stexObject = static_cast(object); + const utf8 * scenarioName = stexObject->GetScenarioName(); + const utf8 * scenarioDetails = stexObject->GetScenarioDetails(); - String::Set(scenarioEntry->name, sizeof(scenarioEntry->name), scenarioName); - String::Set(scenarioEntry->details, sizeof(scenarioEntry->details), scenarioDetails); + String::Set(scenarioEntry->name, sizeof(scenarioEntry->name), scenarioName); + String::Set(scenarioEntry->details, sizeof(scenarioEntry->details), scenarioDetails); - delete object; + delete object; + } } } } diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 7df740b2a6..7162056fd6 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -27,33 +27,36 @@ extern "C" } #endif +#ifdef __cplusplus + class Object; +#else + typedef struct Object Object; +#endif + typedef struct ObjectRepositoryItem { rct_object_entry ObjectEntry; utf8 * Path; - uint32 NumImages; utf8 * Name; - size_t ChunkSize; + Object * LoadedObject; union { - struct - { - uint16 NumThemeObjects; - rct_object_entry * ThemeObjects; - }; struct { uint8 RideFlags; uint8 RideCategory[2]; uint8 RideType[3]; }; + struct + { + uint16 NumThemeObjects; + rct_object_entry * ThemeObjects; + }; }; } ObjectRepositoryItem; #ifdef __cplusplus -class Object; - interface IObjectRepository { virtual ~IObjectRepository() { } @@ -63,7 +66,7 @@ interface IObjectRepository virtual const ObjectRepositoryItem * FindObject(const utf8 * name) const abstract; virtual const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) const abstract; - virtual Object * LoadObject(const rct_object_entry * objectEntry) abstract; + virtual Object * LoadObject(const ObjectRepositoryItem * ori) abstract; virtual void AddObject(const rct_object_entry * objectEntry, const void * data, size_t dataSize) abstract; diff --git a/src/object_list.c b/src/object_list.c index e70a314049..a813515fd7 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -187,44 +187,6 @@ bool object_read_and_load_entries(SDL_RWops* rw) return result; } -bool object_load_entries(rct_object_entry* entries) -{ - log_verbose("loading required objects"); - - object_unload_all(); - - bool loadFailed = false; - // Load each object - for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) { - if (!check_object_entry(&entries[i])) { - continue; - } - - // Get entry group index - int entryGroupIndex = i; - for (int j = 0; j < countof(object_entry_group_counts); j++) { - if (entryGroupIndex < object_entry_group_counts[j]) - break; - entryGroupIndex -= object_entry_group_counts[j]; - } - - // Load the obect - if (!object_load_chunk(entryGroupIndex, &entries[i], NULL)) { - // log_error("failed to load entry: %.8s", entries[i].name); - // memcpy(gCommonFormatArgs, &entries[i], sizeof(rct_object_entry)); - loadFailed = true; - } - } - - if (loadFailed) { - object_unload_all(); - return false; - } - - log_verbose("finished loading required objects"); - return true; -} - /** * * rct2: 0x006A9DA2 diff --git a/src/rct2/S6Importer.cpp b/src/rct2/S6Importer.cpp index 8088765d6c..286da59971 100644 --- a/src/rct2/S6Importer.cpp +++ b/src/rct2/S6Importer.cpp @@ -114,16 +114,9 @@ void S6Importer::LoadSavedGame(SDL_RWops *rw) // Read packed objects // TODO try to contain this more and not store objects until later - if (_s6.header.num_packed_objects > 0) { - int j = 0; - for (uint16 i = 0; i < _s6.header.num_packed_objects; i++) - { - j += object_load_packed(rw); - } - if (j > 0) - { - object_list_load(); - } + for (uint16 i = 0; i < _s6.header.num_packed_objects; i++) + { + object_load_packed(rw); } sawyercoding_read_chunk_safe(rw, &_s6.objects, sizeof(_s6.objects)); @@ -144,16 +137,9 @@ void S6Importer::LoadScenario(SDL_RWops *rw) // Read packed objects // TODO try to contain this more and not store objects until later - if (_s6.header.num_packed_objects > 0) { - int j = 0; - for (uint16 i = 0; i < _s6.header.num_packed_objects; i++) - { - j += object_load_packed(rw); - } - if (j > 0) - { - object_list_load(); - } + for (uint16 i = 0; i < _s6.header.num_packed_objects; i++) + { + object_load_packed(rw); } sawyercoding_read_chunk_safe(rw, &_s6.objects, sizeof(_s6.objects)); diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 54e1d9649c..c462948e25 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -347,6 +347,7 @@ static void visible_list_refresh(rct_window *w) int numObjects = (int)object_repository_get_items_count(); visible_list_dispose(); + w->selected_list_item = -1; _listItems = malloc(numObjects * sizeof(list_item)); _numListItems = 0; From 2f8f10cd11c0baa521cc42b16dfcf05ff7a8e7c0 Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 4 Jul 2016 00:05:39 +0100 Subject: [PATCH 067/116] improve object loading efficiency --- openrct2.vcxproj | 2 + src/object.h | 2 +- src/object/ObjectManager.cpp | 299 ++++++++++++++++++++++++++++++++ src/object/ObjectManager.h | 40 +++++ src/object/ObjectRepository.cpp | 235 ++++++++++++------------- src/object/ObjectRepository.h | 4 + src/object_list.c | 2 +- src/object_list.h | 1 + 8 files changed, 456 insertions(+), 129 deletions(-) create mode 100644 src/object/ObjectManager.cpp create mode 100644 src/object/ObjectManager.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index df88b9b32d..d8f417eea1 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -127,6 +127,7 @@ + @@ -444,6 +445,7 @@ + diff --git a/src/object.h b/src/object.h index 157348e49f..d5a2dea50a 100644 --- a/src/object.h +++ b/src/object.h @@ -114,7 +114,7 @@ int object_load_packed(SDL_RWops* rw); bool object_saved_packed(SDL_RWops* rw, const rct_object_entry * entry); void object_unload_all(); -int check_object_entry(rct_object_entry *entry); +int check_object_entry(const rct_object_entry *entry); bool object_load_chunk(int groupIndex, const rct_object_entry * entry, int * outGroupIndex); bool object_entry_compare(const rct_object_entry *a, const rct_object_entry *b); int object_calculate_checksum(const rct_object_entry * entry, const void * data, size_t dataLength); diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp new file mode 100644 index 0000000000..3a0a09ac31 --- /dev/null +++ b/src/object/ObjectManager.cpp @@ -0,0 +1,299 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include +#include +#include "../core/Console.hpp" +#include "../core/Memory.hpp" +#include "Object.h" +#include "ObjectManager.h" +#include "ObjectRepository.h" + +extern "C" +{ + #include "../object_list.h" +} + +class ObjectManager : public IObjectManager +{ +private: + IObjectRepository * _objectRepository; + Object * * _loadedObjects = nullptr; + +public: + ObjectManager(IObjectRepository * objectRepository) + { + _objectRepository = objectRepository; + } + + ~ObjectManager() override + { + SetNewLoadedObjectList(nullptr); + } + + Object * GetLoadedObject(size_t index) override + { + if (_loadedObjects == nullptr) + { + return nullptr; + } + return _loadedObjects[index]; + } + + bool LoadObjects(const rct_object_entry * entries, size_t count) override + { + IObjectRepository * objectRepository = GetObjectRepository(); + + // Find all the required objects + size_t numRequiredObjects; + auto requiredObjects = new const ObjectRepositoryItem *[OBJECT_ENTRY_COUNT]; + if (!GetRequiredObjects(entries, requiredObjects, &numRequiredObjects)) + { + return false; + } + + // Create a new list of loaded objects + size_t numNewLoadedObjects; + Object * * loadedObjects = LoadObjects(requiredObjects, &numNewLoadedObjects); + + delete requiredObjects; + + if (loadedObjects == nullptr) + { + UnloadAll(); + return false; + } + else + { + SetNewLoadedObjectList(loadedObjects); + UpdateLegacyLoadedObjectList(); + reset_type_to_ride_entry_index_map(); + Console::WriteLine("%u / %u new objects loaded", numNewLoadedObjects, numRequiredObjects); + return true; + } + } + + void UnloadAll() override + { + if (_loadedObjects != nullptr) + { + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) + { + UnloadObject(_loadedObjects[i]); + _loadedObjects[i] = nullptr; + } + } + UpdateLegacyLoadedObjectList(); + reset_type_to_ride_entry_index_map(); + } + +private: + void SetNewLoadedObjectList(Object * * newLoadedObjects) + { + if (newLoadedObjects == nullptr) + { + UnloadAll(); + } + else + { + UnloadObjectsExcept(newLoadedObjects); + } + Memory::Free(_loadedObjects); + _loadedObjects = newLoadedObjects; + } + + void UnloadObject(Object * object) + { + if (object != nullptr) + { + // TODO try to prevent doing a repository search + const ObjectRepositoryItem * ori = _objectRepository->FindObject(object->GetObjectEntry()); + if (ori != nullptr) + { + _objectRepository->UnregisterLoadedObject(ori, object); + } + + object->Unload(); + delete object; + } + } + + void UnloadObjectsExcept(Object * * newLoadedObjects) + { + if (_loadedObjects == nullptr) + { + return; + } + + // Build a hash set for quick checking + auto exceptSet = std::unordered_set(); + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) + { + Object * object = newLoadedObjects[i]; + if (object != nullptr) + { + exceptSet.insert(object); + } + } + + // Unload objects that are not in the hash set + size_t totalObjectsLoaded = 0; + size_t numObjectsUnloaded = 0; + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) + { + Object * object = _loadedObjects[i]; + if (object != nullptr) + { + totalObjectsLoaded++; + if (exceptSet.find(object) == exceptSet.end()) + { + UnloadObject(object); + _loadedObjects[i] = nullptr; + numObjectsUnloaded++; + } + } + } + + Console::WriteLine("%u / %u objects unloaded", numObjectsUnloaded, totalObjectsLoaded); + } + + void UpdateLegacyLoadedObjectList() + { + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) + { + Object * loadedObject = nullptr; + if (_loadedObjects != nullptr) + { + loadedObject = _loadedObjects[i]; + } + + uint8 objectType, entryIndex; + get_type_entry_index(i, &objectType, &entryIndex); + + rct_object_entry_extended * legacyEntry = &object_entry_groups[objectType].entries[entryIndex]; + void * * legacyChunk = &object_entry_groups[objectType].chunks[entryIndex]; + if (loadedObject == nullptr) + { + Memory::Set(legacyEntry, 0xFF, sizeof(rct_object_entry_extended)); + *legacyChunk = (void *)-1; + } + else + { + legacyEntry->entry = *loadedObject->GetObjectEntry(); + legacyEntry->chunk_size = 0; + *legacyChunk = loadedObject->GetLegacyData(); + } + } + } + + bool GetRequiredObjects(const rct_object_entry * entries, + const ObjectRepositoryItem * * requiredObjects, + size_t * outNumRequiredObjects) + { + bool missingObjects = false; + size_t numRequiredObjects = 0; + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) + { + const rct_object_entry * entry = &entries[i]; + const ObjectRepositoryItem * ori = nullptr; + if (check_object_entry(entry)) + { + ori = _objectRepository->FindObject(entry); + if (ori == nullptr) + { + missingObjects = true; + ReportMissingObject(entry); + } + numRequiredObjects++; + } + requiredObjects[i] = ori; + } + + if (outNumRequiredObjects != nullptr) + { + *outNumRequiredObjects = numRequiredObjects; + } + return !missingObjects; + } + + Object * * LoadObjects(const ObjectRepositoryItem * * requiredObjects, size_t * outNewObjectsLoaded) + { + size_t newObjectsLoaded = 0; + Object * * loadedObjects = Memory::AllocateArray(OBJECT_ENTRY_COUNT); + for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) + { + Object * loadedObject = nullptr; + const ObjectRepositoryItem * ori = requiredObjects[i]; + if (ori != nullptr) + { + loadedObject = ori->LoadedObject; + if (loadedObject == nullptr) + { + // Try to load object + loadedObject = _objectRepository->LoadObject(ori); + if (loadedObject == nullptr) + { + ReportObjectLoadProblem(&ori->ObjectEntry); + Memory::Free(loadedObjects); + return nullptr; + } + else + { + loadedObject->Load(); + newObjectsLoaded++; + } + + // Connect the ori to the registered object + _objectRepository->RegisterLoadedObject(ori, loadedObject); + } + } + loadedObjects[i] = loadedObject; + } + if (outNewObjectsLoaded != nullptr) + { + *outNewObjectsLoaded = newObjectsLoaded; + } + return loadedObjects; + } + + static void ReportMissingObject(const rct_object_entry * entry) + { + utf8 objName[9] = { 0 }; + Memory::Copy(objName, entry->name, 8); + Console::Error::WriteFormat("[%s]: Object not found.", objName); + Console::Error::WriteLine(); + } + + static void ReportObjectLoadProblem(const rct_object_entry * entry) + { + utf8 objName[9] = { 0 }; + Memory::Copy(objName, entry->name, 8); + Console::Error::WriteFormat("[%s]: Object could not be loaded.", objName); + Console::Error::WriteLine(); + } +}; + +ObjectManager * _objectManager; + +IObjectManager * GetObjectManager() +{ + if (_objectManager == nullptr) + { + IObjectRepository * objectRepository = GetObjectRepository(); + _objectManager = new ObjectManager(objectRepository); + } + return _objectManager; +} diff --git a/src/object/ObjectManager.h b/src/object/ObjectManager.h new file mode 100644 index 0000000000..4e09950fee --- /dev/null +++ b/src/object/ObjectManager.h @@ -0,0 +1,40 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "../common.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + #include "../object.h" +#ifdef __cplusplus +} +#endif + +interface IObjectManager +{ + virtual ~IObjectManager() { } + + virtual Object * GetLoadedObject(size_t index) abstract; + + virtual bool LoadObjects(const rct_object_entry * entries, size_t count) abstract; + virtual void UnloadAll() abstract; +}; + +IObjectManager * GetObjectManager(); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 7385d3cc1f..abc7264cd7 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -30,6 +30,7 @@ #include "../core/String.hpp" #include "Object.h" #include "ObjectFactory.h" +#include "ObjectManager.h" #include "ObjectRepository.h" #include "RideObject.h" #include "StexObject.h" @@ -39,6 +40,7 @@ extern "C" #include "../config.h" #include "../localisation/localisation.h" #include "../object.h" + #include "../object_list.h" #include "../platform/platform.h" #include "../scenario.h" #include "../util/sawyercoding.h" @@ -87,6 +89,8 @@ struct ObjectEntryEqual using ObjectEntryMap = std::unordered_map; +static void ReportMissingObject(const rct_object_entry * entry); + class ObjectRepository : public IObjectRepository { std::vector _items; @@ -163,6 +167,23 @@ public: return object; } + void RegisterLoadedObject(const ObjectRepositoryItem * ori, Object * object) override + { + ObjectRepositoryItem * item = &_items[ori->Id]; + + Guard::Assert(item->LoadedObject == nullptr); + item->LoadedObject = object; + } + + void UnregisterLoadedObject(const ObjectRepositoryItem * ori, Object * object) override + { + ObjectRepositoryItem * item = &_items[ori->Id]; + if (item->LoadedObject == object) + { + item->LoadedObject = nullptr; + } + } + void AddObject(const rct_object_entry * objectEntry, const void * data, size_t dataSize) override { char objectName[9] = { 0 }; @@ -364,8 +385,9 @@ private: const ObjectRepositoryItem * conflict = FindObject(&item->ObjectEntry); if (conflict == nullptr) { + size_t index = _items.size(); + item->Id = index; _items.push_back(*item); - size_t index = _items.size() - 1; _itemMap[item->ObjectEntry] = index; return true; } @@ -554,9 +576,7 @@ IObjectRepository * GetObjectRepository() return _objectRepository; } -Object * _loadedObjects[OBJECT_ENTRY_COUNT] = { nullptr }; - -int GetObjectEntryIndex(uint8 objectType, uint8 entryIndex) +static int GetObjectEntryIndex(uint8 objectType, uint8 entryIndex) { int result = 0; for (uint8 i = 0; i < objectType; i++) @@ -590,95 +610,62 @@ extern "C" bool object_load_chunk(int groupIndex, const rct_object_entry * entry, int * outGroupIndex) { - IObjectRepository * objectRepository = GetObjectRepository(); - const ObjectRepositoryItem * ori = objectRepository->FindObject(entry); - if (ori == nullptr) - { - utf8 objName[9] = { 0 }; - Memory::Copy(objName, ori->ObjectEntry.name, 8); - Console::Error::WriteFormat("[%s]: Object not found.", objName); - Console::Error::WriteLine(); - return false; - } + return false; - Object * object = objectRepository->LoadObject(ori); - if (object == nullptr) - { - utf8 objName[9] = { 0 }; - Memory::Copy(objName, ori->ObjectEntry.name, 8); - Console::Error::WriteFormat("[%s]: Object could not be loaded.", objName); - Console::Error::WriteLine(); - return false; - } - - uint8 objectType = object->GetObjectType(); - void * * chunkList = object_entry_groups[objectType].chunks; - if (groupIndex == -1) - { - for (groupIndex = 0; chunkList[groupIndex] != (void*)-1; groupIndex++) - { - if (groupIndex + 1 >= object_entry_group_counts[objectType]) - { - log_error("Object Load failed due to too many objects of a certain type."); - delete object; - return false; - } - } - } - chunkList[groupIndex] = object->GetLegacyData(); - if (outGroupIndex != nullptr) - { - *outGroupIndex = groupIndex; - } - - rct_object_entry_extended * extendedEntry = &object_entry_groups[objectType].entries[groupIndex]; - Memory::Copy(extendedEntry, object->GetObjectEntry(), sizeof(rct_object_entry)); - extendedEntry->chunk_size = 0; - - int loadedObjectIndex = GetObjectEntryIndex(objectType, groupIndex); - delete _loadedObjects[loadedObjectIndex]; - _loadedObjects[loadedObjectIndex] = object; - return true; + // IObjectRepository * objectRepository = GetObjectRepository(); + // const ObjectRepositoryItem * ori = objectRepository->FindObject(entry); + // if (ori == nullptr) + // { + // ReportMissingObject(entry); + // return false; + // } + // + // Object * object = objectRepository->LoadObject(ori); + // if (object == nullptr) + // { + // utf8 objName[9] = { 0 }; + // Memory::Copy(objName, ori->ObjectEntry.name, 8); + // Console::Error::WriteFormat("[%s]: Object could not be loaded.", objName); + // Console::Error::WriteLine(); + // return false; + // } + // + // uint8 objectType = object->GetObjectType(); + // void * * chunkList = object_entry_groups[objectType].chunks; + // if (groupIndex == -1) + // { + // for (groupIndex = 0; chunkList[groupIndex] != (void*)-1; groupIndex++) + // { + // if (groupIndex + 1 >= object_entry_group_counts[objectType]) + // { + // log_error("Object Load failed due to too many objects of a certain type."); + // delete object; + // return false; + // } + // } + // } + // chunkList[groupIndex] = object->GetLegacyData(); + // if (outGroupIndex != nullptr) + // { + // *outGroupIndex = groupIndex; + // } + // + // rct_object_entry_extended * extendedEntry = &object_entry_groups[objectType].entries[groupIndex]; + // Memory::Copy(extendedEntry, object->GetObjectEntry(), sizeof(rct_object_entry)); + // extendedEntry->chunk_size = 0; + // + // int loadedObjectIndex = GetObjectEntryIndex(objectType, groupIndex); + // delete _loadedObjects[loadedObjectIndex]; + // _loadedObjects[loadedObjectIndex] = object; + // return true; } bool object_load_entries(rct_object_entry * entries) { log_verbose("loading required objects"); - object_unload_all(); - - bool loadFailed = false; - - // Load each object - for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) - { - if (check_object_entry(&entries[i])) - { - // Get entry group index - int entryGroupIndex = i; - for (int j = 0; j < OBJECT_ENTRY_GROUP_COUNT; j++) - { - if (entryGroupIndex < object_entry_group_counts[j]) - { - break; - } - entryGroupIndex -= object_entry_group_counts[j]; - } - - // Load the obect - if (!object_load_chunk(entryGroupIndex, &entries[i], NULL)) { - // log_error("failed to load entry: %.8s", entries[i].name); - // memcpy(gCommonFormatArgs, &entries[i], sizeof(rct_object_entry)); - loadFailed = true; - } - } - } - - if (loadFailed) - { - object_unload_all(); - return false; - } + IObjectManager * objectManger = GetObjectManager(); + objectManger->LoadObjects(entries, OBJECT_ENTRY_COUNT); log_verbose("finished loading required objects"); return true; @@ -686,17 +673,20 @@ extern "C" void reset_loaded_objects() { - for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) - { - Object * object = _loadedObjects[i]; - if (object != nullptr) - { - object->Unload(); - object->Load(); - } - } - - reset_type_to_ride_entry_index_map(); + // if (_loadedObjects != nullptr) + // { + // for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) + // { + // Object * object = _loadedObjects[i]; + // if (object != nullptr) + // { + // object->Unload(); + // object->Load(); + // } + // } + // } + // + // reset_type_to_ride_entry_index_map(); } void * object_repository_load_object(const rct_object_entry * objectEntry) @@ -717,25 +707,24 @@ extern "C" void * object_repository_find_loaded_object(const rct_object_entry * objectEntry) { - for (size_t i = 0; i < OBJECT_ENTRY_COUNT; i++) + Object * object = nullptr; + + IObjectRepository * objectRepository = GetObjectRepository(); + const ObjectRepositoryItem * ori = objectRepository->FindObject(objectEntry); + if (ori != nullptr) { - Object * object = _loadedObjects[i]; - if (object != nullptr) - { - const rct_object_entry * entry = object->GetObjectEntry(); - if (memcmp(objectEntry->name, entry->name, 8) == 0) - { - return (void *)object; - } - } + object = ori->LoadedObject; } - return nullptr; + + return (void *)object; } void * object_repository_get_loaded_object(uint8 objectType, uint8 entryIndex) { int index = GetObjectEntryIndex(objectType, entryIndex); - return (void *)_loadedObjects[index]; + + IObjectManager * objectManager = GetObjectManager(); + return (void *)objectManager->GetLoadedObject(index); } void object_repository_unload(size_t itemIndex) @@ -745,24 +734,8 @@ extern "C" void object_unload_all() { - for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) - { - Object * object = _loadedObjects[i]; - if (object != nullptr) - { - object->Unload(); - delete object; - _loadedObjects[i] = nullptr; - } - } - for (int i = 0; i < OBJECT_ENTRY_GROUP_COUNT; i++) - { - for (int j = 0; j < object_entry_group_counts[i]; j++) - { - memset(&object_entry_groups[i].entries[j], 0xFF, sizeof(rct_object_entry_extended)); - object_entry_groups[i].chunks[j] = (uint8*)0xFFFFFFFF; - } - } + IObjectManager * objectManager = GetObjectManager(); + objectManager->UnloadAll(); } void scenario_translate(scenario_index_entry * scenarioEntry, const rct_object_entry * stexObjectEntry) @@ -996,3 +969,11 @@ extern "C" return (int)checksum; } } + +static void ReportMissingObject(const rct_object_entry * entry) +{ + utf8 objName[9] = { 0 }; + Memory::Copy(objName, entry->name, 8); + Console::Error::WriteFormat("[%s]: Object not found.", objName); + Console::Error::WriteLine(); +} diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 7162056fd6..45e0602a13 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -35,6 +35,7 @@ extern "C" typedef struct ObjectRepositoryItem { + size_t Id; rct_object_entry ObjectEntry; utf8 * Path; utf8 * Name; @@ -67,6 +68,9 @@ interface IObjectRepository virtual const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) const abstract; virtual Object * LoadObject(const ObjectRepositoryItem * ori) abstract; + virtual void RegisterLoadedObject(const ObjectRepositoryItem * ori, Object * object) abstract; + virtual void UnregisterLoadedObject(const ObjectRepositoryItem * ori, Object * object) abstract; + virtual void AddObject(const rct_object_entry * objectEntry, const void * data, size_t dataSize) abstract; diff --git a/src/object_list.c b/src/object_list.c index a813515fd7..d43f0070fa 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -91,7 +91,7 @@ const rct_object_entry_group object_entry_groups[] = { (void**)(gStexEntries ), (rct_object_entry_extended*)(0x00F3F03C + (720 * 20)) // scenario text 0x009ADAE4, 0xF4287C }; -int check_object_entry(rct_object_entry *entry) +int check_object_entry(const rct_object_entry *entry) { uint32 *dwords = (uint32*)entry; return (0xFFFFFFFF & dwords[0] & dwords[1] & dwords[2] & dwords[3]) + 1 != 0; diff --git a/src/object_list.h b/src/object_list.h index 4277cb569e..040b1d6e3d 100644 --- a/src/object_list.h +++ b/src/object_list.h @@ -34,5 +34,6 @@ #endif void object_list_init(); +void get_type_entry_index(size_t index, uint8 * outObjectType, uint8 * outEntryIndex); const rct_object_entry * get_loaded_object_entry(size_t index); void * get_loaded_object_chunk(size_t index); From 42ad4ddfd1a4c3cc53cd767b9a9d24147d71f0ef Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 4 Jul 2016 17:55:04 +0100 Subject: [PATCH 068/116] fix minor errors --- src/object/ObjectManager.cpp | 3 ++- src/object/ObjectRepository.h | 5 +++++ src/object/RideObject.cpp | 2 +- src/windows/editor_object_selection.c | 4 ++-- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index 3a0a09ac31..da43e32a3c 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -62,6 +62,7 @@ public: auto requiredObjects = new const ObjectRepositoryItem *[OBJECT_ENTRY_COUNT]; if (!GetRequiredObjects(entries, requiredObjects, &numRequiredObjects)) { + delete[] requiredObjects; return false; } @@ -69,7 +70,7 @@ public: size_t numNewLoadedObjects; Object * * loadedObjects = LoadObjects(requiredObjects, &numNewLoadedObjects); - delete requiredObjects; + delete[] requiredObjects; if (loadedObjects == nullptr) { diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 45e0602a13..21620e4209 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -94,3 +94,8 @@ const utf8 * object_get_description(const void * object); void object_draw_preview(const void * object, rct_drawpixelinfo * dpi); #endif + +enum ORI_RIDE_FLAG +{ + ORI_RIDE_FLAG_SEPARATE = 1 << 0, +}; diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index 22929f6ae0..58f55fb273 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -367,7 +367,7 @@ void RideObject::SetRepositoryItem(ObjectRepositoryItem * item) const if ((_legacyType.flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME) && !rideTypeShouldLoseSeparateFlag(&_legacyType)) { - flags |= 0x1000000; + flags |= ORI_RIDE_FLAG_SEPARATE; } item->RideFlags = flags; } diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index c462948e25..946cce1152 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -1898,14 +1898,14 @@ static rct_string_id get_ride_type_string_id(const ObjectRepositoryItem * item) return result; } -bool editor_check_object_group_at_least_one_selected(int objectType) +bool editor_check_object_group_at_least_one_selected(int checkObjectType) { int numObjects = (int)object_repository_get_items_count(); const ObjectRepositoryItem * items = object_repository_get_items(); for (int i = 0; i < numObjects; i++) { uint8 objectType = items[i].ObjectEntry.flags & 0x0F; - if (objectType == objectType && (_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED)) { + if (checkObjectType == objectType && (_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED)) { return true; } } From 82d90fe35093ee281bae994f8f241e7a25632666 Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 4 Jul 2016 18:01:29 +0100 Subject: [PATCH 069/116] use pointer for smallscenery/var10 --- src/object/SmallSceneryObject.cpp | 4 ++-- src/paint/map_element/scenery.c | 2 +- src/world/scenery.h | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index 9c97b08bd5..6c39059b79 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -43,7 +43,7 @@ void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre _legacyType.small_scenery.tool_id = stream->ReadValue(); _legacyType.small_scenery.price = stream->ReadValue(); _legacyType.small_scenery.removal_price = stream->ReadValue(); - _legacyType.small_scenery.var_10 = stream->ReadValue(); + stream->Seek(4, STREAM_SEEK_CURRENT); _legacyType.small_scenery.var_14 = stream->ReadValue(); _legacyType.small_scenery.var_16 = stream->ReadValue(); _legacyType.small_scenery.var_18 = stream->ReadValue(); @@ -93,7 +93,7 @@ void SmallSceneryObject::Load() if (_legacyType.small_scenery.flags & SMALL_SCENERY_FLAG16) { - _legacyType.small_scenery.var_10 = (uint32)_var10data; + _legacyType.small_scenery.var_10 = _var10data; } } diff --git a/src/paint/map_element/scenery.c b/src/paint/map_element/scenery.c index 474a39a66c..4c625e7cdd 100644 --- a/src/paint/map_element/scenery.c +++ b/src/paint/map_element/scenery.c @@ -230,7 +230,7 @@ void scenery_paint(uint8 direction, int height, rct_map_element* mapElement) { esi &= entry->small_scenery.var_16; int image_id = 0; if (esi < entry->small_scenery.var_18) { - image_id = ((uint8*)entry->small_scenery.var_10)[esi]; + image_id = entry->small_scenery.var_10[esi]; } image_id = (image_id * 4) + direction + entry->image; if (entry->small_scenery.flags & (SMALL_SCENERY_FLAG21 | SMALL_SCENERY_FLAG17)) { diff --git a/src/world/scenery.h b/src/world/scenery.h index 5914e695b8..6e95c654a8 100644 --- a/src/world/scenery.h +++ b/src/world/scenery.h @@ -28,13 +28,15 @@ typedef struct rct_small_scenery_entry { uint8 tool_id; // 0x0B sint16 price; // 0x0C sint16 removal_price; // 0x0E - uint32 var_10; + uint8 *var_10; uint16 var_14; uint16 var_16; uint16 var_18; uint8 scenery_tab_id; // 0x1A } rct_small_scenery_entry; +#ifdef PLATFORM_32BIT assert_struct_size(rct_small_scenery_entry, 21); +#endif typedef enum { SMALL_SCENERY_FLAG_FULL_TILE = (1 << 0), // 0x1 From 13e9a76732844d8ea013f5e17ba71d871063e3c9 Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 4 Jul 2016 18:26:36 +0100 Subject: [PATCH 070/116] force a object repo reload if language changes --- src/editor.c | 3 +++ src/object/ObjectRepository.cpp | 14 ++++++++++---- src/object/ObjectRepository.h | 1 + 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/editor.c b/src/editor.c index 2483101076..28adee5d2d 100644 --- a/src/editor.c +++ b/src/editor.c @@ -60,6 +60,7 @@ void editor_load() audio_pause_sounds(); audio_unpause_sounds(); object_unload_all(); + object_list_load(); map_init(150); banner_init(); reset_park_entrances(); @@ -146,6 +147,7 @@ void trackdesigner_load() gScreenAge = 0; object_unload_all(); + object_list_load(); map_init(150); set_all_land_owned(); banner_init(); @@ -184,6 +186,7 @@ void trackmanager_load() gScreenAge = 0; object_unload_all(); + object_list_load(); map_init(150); set_all_land_owned(); banner_init(); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index abc7264cd7..04ca902f2d 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -46,11 +46,12 @@ extern "C" #include "../util/sawyercoding.h" } -constexpr uint16 OBJECT_REPOSITORY_VERSION = 8; +constexpr uint16 OBJECT_REPOSITORY_VERSION = 9; struct ObjectRepositoryHeader { uint16 Version; + uint16 LanguageId; uint32 TotalFiles; uint64 TotalFileSize; uint32 FileDateModifiedChecksum; @@ -96,6 +97,7 @@ class ObjectRepository : public IObjectRepository std::vector _items; QueryDirectoryResult _queryDirectoryResult; ObjectEntryMap _itemMap; + uint16 _languageId; public: ~ObjectRepository() @@ -103,7 +105,7 @@ public: ClearItems(); } - void LoadOrConstruct() + void LoadOrConstruct() override { ClearItems(); @@ -117,6 +119,8 @@ public: if (!Load()) { + _languageId = gCurrentLanguage; + Construct(); Save(); } @@ -310,6 +314,7 @@ private: auto header = fs.ReadValue(); if (header.Version == OBJECT_REPOSITORY_VERSION && + header.LanguageId == gCurrentLanguage && header.TotalFiles == _queryDirectoryResult.TotalFiles && header.TotalFileSize == _queryDirectoryResult.TotalFileSize && header.FileDateModifiedChecksum == _queryDirectoryResult.FileDateModifiedChecksum && @@ -344,6 +349,7 @@ private: // Write header ObjectRepositoryHeader header; header.Version = OBJECT_REPOSITORY_VERSION; + header.LanguageId = _languageId; header.TotalFiles = _queryDirectoryResult.TotalFiles; header.TotalFileSize = _queryDirectoryResult.TotalFileSize; header.FileDateModifiedChecksum = _queryDirectoryResult.FileDateModifiedChecksum; @@ -571,7 +577,6 @@ IObjectRepository * GetObjectRepository() if (_objectRepository == nullptr) { _objectRepository = new ObjectRepository(); - _objectRepository->LoadOrConstruct(); } return _objectRepository; } @@ -605,7 +610,8 @@ extern "C" void object_list_load() { - IObjectRepository * objRepo = GetObjectRepository(); + IObjectRepository * objectRepository = GetObjectRepository(); + objectRepository->LoadOrConstruct(); } bool object_load_chunk(int groupIndex, const rct_object_entry * entry, int * outGroupIndex) diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 21620e4209..77db1c82d4 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -62,6 +62,7 @@ interface IObjectRepository { virtual ~IObjectRepository() { } + virtual void LoadOrConstruct() abstract; virtual const size_t GetNumObjects() const abstract; virtual const ObjectRepositoryItem * GetObjects() const abstract; virtual const ObjectRepositoryItem * FindObject(const utf8 * name) const abstract; From 2824224710bd3db0e0e90b99f3563d4bb51f6032 Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 4 Jul 2016 18:53:35 +0100 Subject: [PATCH 071/116] use overridden object strings --- src/localisation/language.cpp | 9 ++++++ src/localisation/language.h | 1 + src/object/BannerObject.cpp | 6 ---- src/object/BannerObject.h | 2 -- src/object/EntranceObject.cpp | 6 ---- src/object/EntranceObject.h | 2 -- src/object/FootpathItemObject.cpp | 6 ---- src/object/FootpathItemObject.h | 2 -- src/object/FootpathObject.cpp | 6 ---- src/object/FootpathObject.h | 2 -- src/object/LargeSceneryObject.cpp | 6 ---- src/object/LargeSceneryObject.h | 2 -- src/object/Object.cpp | 49 +++++++++++++++++++++++++++++++ src/object/Object.h | 9 ++++-- src/object/RideObject.cpp | 12 ++------ src/object/RideObject.h | 1 - src/object/SceneryGroupObject.cpp | 6 ---- src/object/SceneryGroupObject.h | 2 -- src/object/SmallSceneryObject.cpp | 7 ----- src/object/SmallSceneryObject.h | 2 -- src/object/WallObject.cpp | 6 ---- src/object/WallObject.h | 2 -- src/object/WaterObject.cpp | 6 ---- src/object/WaterObject.h | 2 -- 24 files changed, 68 insertions(+), 86 deletions(-) diff --git a/src/localisation/language.cpp b/src/localisation/language.cpp index f4dc609711..976261de7b 100644 --- a/src/localisation/language.cpp +++ b/src/localisation/language.cpp @@ -365,4 +365,13 @@ void language_free_object_string(rct_string_id stringId) } } +rct_string_id language_get_object_override_string_id(const char * identifier, uint8 index) +{ + if (_languageCurrent == nullptr) + { + return STR_NONE; + } + return _languageCurrent->GetObjectOverrideStringId(identifier, index); +} + } diff --git a/src/localisation/language.h b/src/localisation/language.h index 0a6823f4e3..153dd1481a 100644 --- a/src/localisation/language.h +++ b/src/localisation/language.h @@ -82,5 +82,6 @@ utf8 *widechar_to_utf8(const wchar_t *src); bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_string_id *outStringIds); rct_string_id language_allocate_object_string(const utf8 * target); void language_free_object_string(rct_string_id stringId); +rct_string_id language_get_object_override_string_id(const char * identifier, uint8 index); #endif diff --git a/src/object/BannerObject.cpp b/src/object/BannerObject.cpp index 99fcf16ec3..73eac1caf4 100644 --- a/src/object/BannerObject.cpp +++ b/src/object/BannerObject.cpp @@ -84,9 +84,3 @@ void BannerObject::DrawPreview(rct_drawpixelinfo * dpi) const gfx_draw_sprite(dpi, imageId + 0, x - 12, y + 8, 0); gfx_draw_sprite(dpi, imageId + 1, x - 12, y + 8, 0); } - -const utf8 * BannerObject::GetName() const -{ - const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); - return name != nullptr ? name : ""; -} diff --git a/src/object/BannerObject.h b/src/object/BannerObject.h index a7dc09d218..4ef47e405c 100644 --- a/src/object/BannerObject.h +++ b/src/object/BannerObject.h @@ -39,6 +39,4 @@ public: void Unload() override; void DrawPreview(rct_drawpixelinfo * dpi) const override; - - const utf8 * GetName() const override; }; diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index da81343e1b..0469a3b0f1 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -63,9 +63,3 @@ void EntranceObject::DrawPreview(rct_drawpixelinfo * dpi) const gfx_draw_sprite(dpi, imageId + 0, x + 0, y + 28, 0); gfx_draw_sprite(dpi, imageId + 2, x + 32, y + 44, 0); } - -const utf8 * EntranceObject::GetName() const -{ - const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); - return name != nullptr ? name : ""; -} diff --git a/src/object/EntranceObject.h b/src/object/EntranceObject.h index cb370e8c0d..9da64b57f5 100644 --- a/src/object/EntranceObject.h +++ b/src/object/EntranceObject.h @@ -38,6 +38,4 @@ public: void Unload() override; void DrawPreview(rct_drawpixelinfo * dpi) const override; - - const utf8 * GetName() const override; }; diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp index 0852ed1a49..dfcec859d9 100644 --- a/src/object/FootpathItemObject.cpp +++ b/src/object/FootpathItemObject.cpp @@ -81,9 +81,3 @@ void FootpathItemObject::DrawPreview(rct_drawpixelinfo * dpi) const int y = dpi->height / 2; gfx_draw_sprite(dpi, _legacyType.image, x - 22, y - 24, 0); } - -const utf8 * FootpathItemObject::GetName() const -{ - const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); - return name != nullptr ? name : ""; -} diff --git a/src/object/FootpathItemObject.h b/src/object/FootpathItemObject.h index 6aabe8b58c..e3812781a9 100644 --- a/src/object/FootpathItemObject.h +++ b/src/object/FootpathItemObject.h @@ -39,6 +39,4 @@ public: void Unload() override; void DrawPreview(rct_drawpixelinfo * dpi) const override; - - const utf8 * GetName() const override; }; diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp index b7bfe4c928..8cc43bacbf 100644 --- a/src/object/FootpathObject.cpp +++ b/src/object/FootpathObject.cpp @@ -70,9 +70,3 @@ void FootpathObject::DrawPreview(rct_drawpixelinfo * dpi) const gfx_draw_sprite(dpi, _legacyType.image + 71, x - 49, y - 17, 0); gfx_draw_sprite(dpi, _legacyType.image + 72, x + 4, y - 17, 0); } - -const utf8 * FootpathObject::GetName() const -{ - const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); - return name != nullptr ? name : ""; -} diff --git a/src/object/FootpathObject.h b/src/object/FootpathObject.h index 6bf997e6e1..7000c8776d 100644 --- a/src/object/FootpathObject.h +++ b/src/object/FootpathObject.h @@ -38,6 +38,4 @@ public: void Unload() override; void DrawPreview(rct_drawpixelinfo * dpi) const override; - - const utf8 * GetName() const override; }; diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index 94e1679d10..a51918eadf 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -128,12 +128,6 @@ void LargeSceneryObject::DrawPreview(rct_drawpixelinfo * dpi) const gfx_draw_sprite(dpi, imageId, x, y, 0); } -const utf8 * LargeSceneryObject::GetName() const -{ - const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); - return name != nullptr ? name : ""; -} - rct_large_scenery_tile * LargeSceneryObject::ReadTiles(IStream * stream) { auto tiles = std::vector(); diff --git a/src/object/LargeSceneryObject.h b/src/object/LargeSceneryObject.h index 00d67c3dbb..5f28210852 100644 --- a/src/object/LargeSceneryObject.h +++ b/src/object/LargeSceneryObject.h @@ -44,8 +44,6 @@ public: void DrawPreview(rct_drawpixelinfo * dpi) const override; - const utf8 * GetName() const override; - private: static rct_large_scenery_tile * ReadTiles(IStream * stream); }; diff --git a/src/object/Object.cpp b/src/object/Object.cpp index decc2e977f..90f11bcd16 100644 --- a/src/object/Object.cpp +++ b/src/object/Object.cpp @@ -14,9 +14,58 @@ *****************************************************************************/ #pragma endregion +#include "../core/Memory.hpp" +#include "../core/String.hpp" #include "Object.h" +extern "C" +{ + #include "../localisation/localisation.h" +} + +enum OBJ_STRING_ID +{ + OBJ_STRING_ID_NAME, +}; + Object::Object(const rct_object_entry &entry) { _objectEntry = entry; + + char name[9] = { 0 }; + Memory::Copy(name, entry.name, 8); + _identifier = String::Duplicate(name); +} + +Object::~Object() +{ + Memory::Free(_identifier); +} + +const utf8 * Object::GetOverrideString(uint8 index) const +{ + const char * identifier = GetIdentifier(); + rct_string_id stringId = language_get_object_override_string_id(identifier, index); + + const utf8 * result = nullptr; + if (stringId != STR_NONE) + { + result = language_get_string(stringId); + } + return result; +} + +const utf8 * Object::GetString(uint8 index) const +{ + const utf8 * sz = GetOverrideString(index); + if (sz == nullptr) + { + sz = GetStringTable()->GetString(index); + } + return sz != nullptr ? sz : ""; +} + +const utf8 * Object::GetName() const +{ + return GetString(OBJ_STRING_ID_NAME); } diff --git a/src/object/Object.h b/src/object/Object.h index 4485858988..b1e84eb377 100644 --- a/src/object/Object.h +++ b/src/object/Object.h @@ -40,6 +40,7 @@ interface IReadObjectContext class Object { private: + char * _identifier; rct_object_entry _objectEntry; StringTable _stringTable; ImageTable _imageTable; @@ -49,11 +50,15 @@ protected: const StringTable * GetStringTable() const { return &_stringTable; } ImageTable * GetImageTable() { return &_imageTable; } + const utf8 * GetOverrideString(uint8 index) const; + const utf8 * GetString(uint8 index) const; + public: explicit Object(const rct_object_entry &entry); - virtual ~Object() { } + virtual ~Object(); // Legacy data structures + const char * GetIdentifier() const { return _identifier; } const rct_object_entry * GetObjectEntry() const { return &_objectEntry; } virtual void * GetLegacyData() abstract; @@ -64,7 +69,7 @@ public: virtual void DrawPreview(rct_drawpixelinfo * dpi) const { } virtual uint8 GetObjectType() const { return _objectEntry.flags & 0x0F; } - virtual const utf8 * GetName() const abstract; + virtual const utf8 * GetName() const; virtual void SetRepositoryItem(ObjectRepositoryItem * item) const { } }; diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index 58f55fb273..6904fcc7b9 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -334,22 +334,14 @@ void RideObject::DrawPreview(rct_drawpixelinfo * dpi) const gfx_draw_sprite(dpi, imageId, 0, 0, 0); } -const utf8 * RideObject::GetName() const -{ - const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); - return name != nullptr ? name : ""; -} - const utf8 * RideObject::GetDescription() const { - const utf8 * description = GetStringTable()->GetString(OBJ_STRING_ID_DESCRIPTION); - return description != nullptr ? description : ""; + return GetString(OBJ_STRING_ID_DESCRIPTION); } const utf8 * RideObject::GetCapacity() const { - const utf8 * capacity = GetStringTable()->GetString(OBJ_STRING_ID_CAPACITY); - return capacity != nullptr ? capacity : ""; + return GetString(OBJ_STRING_ID_CAPACITY); } void RideObject::SetRepositoryItem(ObjectRepositoryItem * item) const diff --git a/src/object/RideObject.h b/src/object/RideObject.h index 2f8d0f097a..02c4094ea4 100644 --- a/src/object/RideObject.h +++ b/src/object/RideObject.h @@ -42,7 +42,6 @@ public: void DrawPreview(rct_drawpixelinfo * dpi) const override; - const utf8 * GetName() const override; const utf8 * GetDescription() const; const utf8 * GetCapacity() const; diff --git a/src/object/SceneryGroupObject.cpp b/src/object/SceneryGroupObject.cpp index 74b2df8148..2976d6c2a9 100644 --- a/src/object/SceneryGroupObject.cpp +++ b/src/object/SceneryGroupObject.cpp @@ -97,12 +97,6 @@ void SceneryGroupObject::DrawPreview(rct_drawpixelinfo * dpi) const gfx_draw_sprite(dpi, imageId, x - 15, y - 14, 0); } -const utf8 * SceneryGroupObject::GetName() const -{ - const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); - return name != nullptr ? name : ""; -} - void SceneryGroupObject::SetRepositoryItem(ObjectRepositoryItem * item) const { Memory::Free(item->ThemeObjects); diff --git a/src/object/SceneryGroupObject.h b/src/object/SceneryGroupObject.h index a8715fc309..af4df3cd44 100644 --- a/src/object/SceneryGroupObject.h +++ b/src/object/SceneryGroupObject.h @@ -44,8 +44,6 @@ public: void DrawPreview(rct_drawpixelinfo * dpi) const override; - const utf8 * GetName() const override; - void SetRepositoryItem(ObjectRepositoryItem * item) const override; private: diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index 6c39059b79..ccb335da01 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -152,13 +152,6 @@ void SmallSceneryObject::DrawPreview(rct_drawpixelinfo * dpi) const } } - -const utf8 * SmallSceneryObject::GetName() const -{ - const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); - return name != nullptr ? name : ""; -} - uint8 * SmallSceneryObject::ReadVar10(IStream * stream) { uint8 b; diff --git a/src/object/SmallSceneryObject.h b/src/object/SmallSceneryObject.h index 173b0025fb..36a14111ea 100644 --- a/src/object/SmallSceneryObject.h +++ b/src/object/SmallSceneryObject.h @@ -42,8 +42,6 @@ public: void DrawPreview(rct_drawpixelinfo * dpi) const override; - const utf8 * GetName() const override; - private: static uint8 * ReadVar10(IStream * stream); }; diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp index 5a7276aac4..233c62dd3d 100644 --- a/src/object/WallObject.cpp +++ b/src/object/WallObject.cpp @@ -105,9 +105,3 @@ void WallObject::DrawPreview(rct_drawpixelinfo * dpi) const gfx_draw_sprite(dpi, imageId, x, y, 0); } } - -const utf8 * WallObject::GetName() const -{ - const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); - return name != nullptr ? name : ""; -} diff --git a/src/object/WallObject.h b/src/object/WallObject.h index 5dce93e816..dc538c6405 100644 --- a/src/object/WallObject.h +++ b/src/object/WallObject.h @@ -39,6 +39,4 @@ public: void Unload() override; void DrawPreview(rct_drawpixelinfo * dpi) const override; - - const utf8 * GetName() const override; }; diff --git a/src/object/WaterObject.cpp b/src/object/WaterObject.cpp index a35d45121a..41e7e32d6d 100644 --- a/src/object/WaterObject.cpp +++ b/src/object/WaterObject.cpp @@ -64,9 +64,3 @@ void WaterObject::DrawPreview(rct_drawpixelinfo * dpi) const int y = dpi->height / 2; gfx_draw_string_centred(dpi, 3326, x, y, 0, nullptr); } - -const utf8 * WaterObject::GetName() const -{ - const utf8 * name = GetStringTable()->GetString(OBJ_STRING_ID_NAME); - return name != nullptr ? name : ""; -} diff --git a/src/object/WaterObject.h b/src/object/WaterObject.h index b0531ac4ae..151daf42cc 100644 --- a/src/object/WaterObject.h +++ b/src/object/WaterObject.h @@ -38,6 +38,4 @@ public: void Unload() override; void DrawPreview(rct_drawpixelinfo * dpi) const override; - - const utf8 * GetName() const override; }; From 793e83779f86e45d96065a30732e43a274710934 Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 4 Jul 2016 19:03:30 +0100 Subject: [PATCH 072/116] handle RCT2 language encoding properly --- src/localisation/language.cpp | 9 +++++++++ src/localisation/language.h | 1 + src/object/StringTable.cpp | 14 +++++++------- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/localisation/language.cpp b/src/localisation/language.cpp index 976261de7b..d154358954 100644 --- a/src/localisation/language.cpp +++ b/src/localisation/language.cpp @@ -322,6 +322,15 @@ static bool rct2_language_is_multibyte_charset(int languageId) } } +utf8 *rct2_language_string_to_utf8(const char *src, int languageId) +{ + if (rct2_language_is_multibyte_charset(languageId)) { + return convert_multibyte_charset(src, languageId); + } else { + return win1252_to_utf8_alloc(src); + } +} + bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_string_id *outStringIds) { outStringIds[0] = _languageCurrent->GetScenarioOverrideStringId(scenarioFilename, 0); diff --git a/src/localisation/language.h b/src/localisation/language.h index 153dd1481a..c509c7b37e 100644 --- a/src/localisation/language.h +++ b/src/localisation/language.h @@ -79,6 +79,7 @@ int utf8_length(const utf8 *text); wchar_t *utf8_to_widechar(const utf8 *src); utf8 *widechar_to_utf8(const wchar_t *src); +utf8 *rct2_language_string_to_utf8(const char *src, int languageId); bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_string_id *outStringIds); rct_string_id language_allocate_object_string(const utf8 * target); void language_free_object_string(rct_string_id stringId); diff --git a/src/object/StringTable.cpp b/src/object/StringTable.cpp index 0f1642d40f..88ed280d1d 100644 --- a/src/object/StringTable.cpp +++ b/src/object/StringTable.cpp @@ -56,17 +56,17 @@ void StringTable::Read(IReadObjectContext * context, IStream * stream, uint8 id) entry.Id = id; entry.LanguageId = languageId; - char * win1252 = stream->ReadString(); - if (StringIsBlank(win1252)) + char * stringAsWin1252 = stream->ReadString(); + utf8 * stringAsUtf8 = rct2_language_string_to_utf8(stringAsWin1252, languageId); + Memory::Free(stringAsWin1252); + + if (StringIsBlank(stringAsUtf8)) { entry.LanguageId = RCT2_LANGUAGE_ID_BLANK; } + String::Trim(stringAsUtf8); - entry.Text = win1252_to_utf8_alloc(win1252); - Memory::Free(win1252); - - String::Trim(entry.Text); - + entry.Text = stringAsUtf8; _strings.push_back(entry); } } From e51c96d67a1d1c216f3c005152a57fdc1bd6073a Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 5 Jul 2016 18:00:58 +0100 Subject: [PATCH 073/116] comment out object load / unload logging --- src/object/ObjectManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index da43e32a3c..7a6e2f0790 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -82,7 +82,7 @@ public: SetNewLoadedObjectList(loadedObjects); UpdateLegacyLoadedObjectList(); reset_type_to_ride_entry_index_map(); - Console::WriteLine("%u / %u new objects loaded", numNewLoadedObjects, numRequiredObjects); + // Console::WriteLine("%u / %u new objects loaded", numNewLoadedObjects, numRequiredObjects); return true; } } @@ -168,7 +168,7 @@ private: } } - Console::WriteLine("%u / %u objects unloaded", numObjectsUnloaded, totalObjectsLoaded); + // Console::WriteLine("%u / %u objects unloaded", numObjectsUnloaded, totalObjectsLoaded); } void UpdateLegacyLoadedObjectList() From 5b9cb813e7f68a0ce8547c560f00a082cdae40f9 Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 5 Jul 2016 19:33:12 +0100 Subject: [PATCH 074/116] fix load_object cc --- src/interface/console.c | 10 +-- src/object/ObjectManager.cpp | 136 +++++++++++++++++++++++++++++--- src/object/ObjectManager.h | 17 +++- src/object/ObjectRepository.cpp | 14 ---- src/object/ObjectRepository.h | 1 - 5 files changed, 147 insertions(+), 31 deletions(-) diff --git a/src/interface/console.c b/src/interface/console.c index 1e4dc37ffa..c5b0fc7e0a 100644 --- a/src/interface/console.c +++ b/src/interface/console.c @@ -30,6 +30,7 @@ #include "../input.h" #include "../network/twitch.h" #include "../object.h" +#include "../object/ObjectManager.h" #include "../object/ObjectRepository.h" #include "../world/banner.h" #include "../world/climate.h" @@ -883,19 +884,18 @@ static int cc_load_object(const utf8 **argv, int argc) { } const rct_object_entry * entry = &ori->ObjectEntry; - void * loadedObject = object_repository_find_loaded_object(entry); + void * loadedObject = object_manager_get_loaded_object(entry); if (loadedObject != NULL) { console_writeline_error("Object is already in scenario."); return 1; } - int groupIndex; - if (!object_load_chunk(-1, entry, &groupIndex)) { + loadedObject = object_manager_load_object(entry); + if (loadedObject == NULL) { console_writeline_error("Unable to load object."); return 1; } - - reset_loaded_objects(); + int groupIndex = object_manager_get_loaded_object_entry_index(loadedObject); uint8 objectType = entry->flags & 0x0F; if (objectType == OBJECT_TYPE_RIDE) { diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index 7a6e2f0790..1daa07634d 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -53,6 +53,60 @@ public: return _loadedObjects[index]; } + Object * GetLoadedObject(const rct_object_entry * entry) override + { + Object * loadedObject = nullptr; + const ObjectRepositoryItem * ori = _objectRepository->FindObject(entry); + if (ori != nullptr) + { + loadedObject = ori->LoadedObject; + } + return loadedObject; + } + + uint8 GetLoadedObjectEntryIndex(const Object * object) override + { + uint8 result = UINT8_MAX; + if (_loadedObjects != nullptr) + { + for (size_t i = 0; i < OBJECT_ENTRY_COUNT; i++) + { + if (_loadedObjects[i] == object) + { + get_type_entry_index(i, nullptr, &result); + break; + } + } + } + return result; + } + + Object * LoadObject(const rct_object_entry * entry) override + { + Object * loadedObject = nullptr; + const ObjectRepositoryItem * ori = _objectRepository->FindObject(entry); + if (ori != nullptr) + { + loadedObject = ori->LoadedObject; + if (loadedObject == nullptr) + { + uint8 objectType = entry->flags & 0x0F; + sint32 slot = FindSpareSlot(objectType); + if (slot != -1) + { + loadedObject = GetOrLoadObject(ori); + if (loadedObject != nullptr) + { + _loadedObjects[slot] = loadedObject; + UpdateLegacyLoadedObjectList(); + reset_type_to_ride_entry_index_map(); + } + } + } + } + return loadedObject; + } + bool LoadObjects(const rct_object_entry * entries, size_t count) override { IObjectRepository * objectRepository = GetObjectRepository(); @@ -102,6 +156,23 @@ public: } private: + sint32 FindSpareSlot(uint8 objectType) + { + if (_loadedObjects != nullptr) + { + sint32 firstIndex = GetIndexFromTypeEntry(objectType, 0); + sint32 endIndex = firstIndex + object_entry_group_counts[objectType]; + for (sint32 i = firstIndex; i < endIndex; i++) + { + if (_loadedObjects[i] == nullptr) + { + return i; + } + } + } + return -1; + } + void SetNewLoadedObjectList(Object * * newLoadedObjects) { if (newLoadedObjects == nullptr) @@ -243,22 +314,15 @@ private: loadedObject = ori->LoadedObject; if (loadedObject == nullptr) { - // Try to load object - loadedObject = _objectRepository->LoadObject(ori); + loadedObject = GetOrLoadObject(ori); if (loadedObject == nullptr) { ReportObjectLoadProblem(&ori->ObjectEntry); Memory::Free(loadedObjects); return nullptr; - } - else - { - loadedObject->Load(); + } else { newObjectsLoaded++; } - - // Connect the ori to the registered object - _objectRepository->RegisterLoadedObject(ori, loadedObject); } } loadedObjects[i] = loadedObject; @@ -270,6 +334,24 @@ private: return loadedObjects; } + Object * GetOrLoadObject(const ObjectRepositoryItem * ori) + { + Object * loadedObject = ori->LoadedObject; + if (loadedObject == nullptr) + { + // Try to load object + loadedObject = _objectRepository->LoadObject(ori); + if (loadedObject != nullptr) + { + loadedObject->Load(); + + // Connect the ori to the registered object + _objectRepository->RegisterLoadedObject(ori, loadedObject); + } + } + return loadedObject; + } + static void ReportMissingObject(const rct_object_entry * entry) { utf8 objName[9] = { 0 }; @@ -285,6 +367,17 @@ private: Console::Error::WriteFormat("[%s]: Object could not be loaded.", objName); Console::Error::WriteLine(); } + + static sint32 GetIndexFromTypeEntry(uint8 objectType, uint8 entryIndex) + { + int result = 0; + for (uint8 i = 0; i < objectType; i++) + { + result += object_entry_group_counts[i]; + } + result += entryIndex; + return result; + } }; ObjectManager * _objectManager; @@ -298,3 +391,28 @@ IObjectManager * GetObjectManager() } return _objectManager; } + +extern "C" +{ + void * object_manager_get_loaded_object(const rct_object_entry * entry) + { + IObjectManager * objectManager = GetObjectManager(); + Object * loadedObject = objectManager->GetLoadedObject(entry); + return (void *)loadedObject; + } + + uint8 object_manager_get_loaded_object_entry_index(const void * loadedObject) + { + IObjectManager * objectManager = GetObjectManager(); + const Object * object = (const Object *)loadedObject; + uint8 entryIndex = objectManager->GetLoadedObjectEntryIndex(object); + return entryIndex; + } + + void * object_manager_load_object(const rct_object_entry * entry) + { + IObjectManager * objectManager = GetObjectManager(); + Object * loadedObject = objectManager->LoadObject(entry); + return (void *)loadedObject; + } +} diff --git a/src/object/ObjectManager.h b/src/object/ObjectManager.h index 4e09950fee..a2a2ad1ea4 100644 --- a/src/object/ObjectManager.h +++ b/src/object/ObjectManager.h @@ -27,14 +27,27 @@ extern "C" } #endif +#ifdef __cplusplus + interface IObjectManager { virtual ~IObjectManager() { } virtual Object * GetLoadedObject(size_t index) abstract; + virtual Object * GetLoadedObject(const rct_object_entry * entry) abstract; + virtual uint8 GetLoadedObjectEntryIndex(const Object * object) abstract; - virtual bool LoadObjects(const rct_object_entry * entries, size_t count) abstract; - virtual void UnloadAll() abstract; + virtual Object * LoadObject(const rct_object_entry * entry) abstract; + virtual bool LoadObjects(const rct_object_entry * entries, size_t count) abstract; + virtual void UnloadAll() abstract; }; IObjectManager * GetObjectManager(); + +#else + +void * object_manager_get_loaded_object(const rct_object_entry * entry); +uint8 object_manager_get_loaded_object_entry_index(const void * loadedObject); +void * object_manager_load_object(const rct_object_entry * entry); + +#endif diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 04ca902f2d..18ae1ce8e5 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -711,20 +711,6 @@ extern "C" return (void *)object; } - void * object_repository_find_loaded_object(const rct_object_entry * objectEntry) - { - Object * object = nullptr; - - IObjectRepository * objectRepository = GetObjectRepository(); - const ObjectRepositoryItem * ori = objectRepository->FindObject(objectEntry); - if (ori != nullptr) - { - object = ori->LoadedObject; - } - - return (void *)object; - } - void * object_repository_get_loaded_object(uint8 objectType, uint8 entryIndex) { int index = GetObjectEntryIndex(objectType, entryIndex); diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 77db1c82d4..1ee96967b4 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -86,7 +86,6 @@ const ObjectRepositoryItem * object_repository_get_items(); const ObjectRepositoryItem * object_repository_find_object_by_entry(const rct_object_entry * entry); const ObjectRepositoryItem * object_repository_find_object_by_name(const char * name); void * object_repository_load_object(const rct_object_entry * objectEntry); -void * object_repository_find_loaded_object(const rct_object_entry * objectEntry); void * object_repository_get_loaded_object(uint8 objectType, uint8 entryIndex); void object_repository_unload(size_t itemIndex); From c672cb920b2a9aa857c48b49e6aeffa521243123 Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 6 Jul 2016 20:19:33 +0100 Subject: [PATCH 075/116] read ride objects field by field This will help with x64 port --- src/object/RideObject.cpp | 84 +++++++++++++++++++++++++++++++++++++-- src/object/RideObject.h | 2 +- 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index 6904fcc7b9..4d91204d03 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -45,10 +45,38 @@ RideObject::~RideObject() void RideObject::ReadLegacy(IReadObjectContext * context, IStream * stream) { - stream->Read(&_legacyType); - _legacyType.name = 0; - _legacyType.description = 0; - _legacyType.images_offset = 0; + stream->Seek(8, STREAM_SEEK_CURRENT); + _legacyType.flags = stream->ReadValue(); + for (int i = 0; i < 3; i++) + { + _legacyType.ride_type[i] = stream->ReadValue(); + } + _legacyType.min_cars_in_train = stream->ReadValue(); + _legacyType.max_cars_in_train = stream->ReadValue(); + _legacyType.cars_per_flat_ride = stream->ReadValue(); + _legacyType.zero_cars = stream->ReadValue(); + _legacyType.tab_vehicle = stream->ReadValue(); + _legacyType.default_vehicle = stream->ReadValue(); + _legacyType.front_vehicle = stream->ReadValue(); + _legacyType.second_vehicle = stream->ReadValue(); + _legacyType.rear_vehicle = stream->ReadValue(); + _legacyType.third_vehicle = stream->ReadValue(); + _legacyType.pad_019 = stream->ReadValue(); + for (int i = 0; i < 4; i++) + { + rct_ride_entry_vehicle * entry = &_legacyType.vehicles[i]; + ReadLegacyVehicle(context, stream, entry); + } + stream->Seek(4, STREAM_SEEK_CURRENT); + _legacyType.excitement_multipler = stream->ReadValue(); + _legacyType.intensity_multipler = stream->ReadValue(); + _legacyType.nausea_multipler = stream->ReadValue(); + _legacyType.max_height = stream->ReadValue(); + _legacyType.enabledTrackPieces = stream->ReadValue(); + _legacyType.category[0] = stream->ReadValue(); + _legacyType.category[1] = stream->ReadValue(); + _legacyType.shop_item = stream->ReadValue(); + _legacyType.shop_item_secondary = stream->ReadValue(); GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); GetStringTable()->Read(context, stream, OBJ_STRING_ID_DESCRIPTION); @@ -363,3 +391,51 @@ void RideObject::SetRepositoryItem(ObjectRepositoryItem * item) const } item->RideFlags = flags; } + +void RideObject::ReadLegacyVehicle(IReadObjectContext * context, IStream * stream, rct_ride_entry_vehicle * vehicle) +{ + vehicle->rotation_frame_mask = stream->ReadValue(); + vehicle->var_02 = stream->ReadValue(); + vehicle->var_03 = stream->ReadValue(); + vehicle->spacing = stream->ReadValue(); + vehicle->car_friction = stream->ReadValue(); + vehicle->tab_height = stream->ReadValue(); + vehicle->num_seats = stream->ReadValue(); + vehicle->sprite_flags = stream->ReadValue(); + vehicle->sprite_width = stream->ReadValue(); + vehicle->sprite_height_negative = stream->ReadValue(); + vehicle->sprite_height_positive = stream->ReadValue(); + vehicle->var_11 = stream->ReadValue(); + vehicle->flags_a = stream->ReadValue(); + vehicle->flags_b = stream->ReadValue(); + vehicle->var_16 = stream->ReadValue(); + stream->Seek(4, STREAM_SEEK_CURRENT); + vehicle->var_1C = stream->ReadValue(); + vehicle->var_20 = stream->ReadValue(); + vehicle->var_24 = stream->ReadValue(); + vehicle->var_28 = stream->ReadValue(); + vehicle->var_2C = stream->ReadValue(); + vehicle->var_30 = stream->ReadValue(); + vehicle->var_34 = stream->ReadValue(); + vehicle->var_38 = stream->ReadValue(); + vehicle->var_3C = stream->ReadValue(); + vehicle->var_40 = stream->ReadValue(); + vehicle->var_44 = stream->ReadValue(); + vehicle->var_48 = stream->ReadValue(); + vehicle->var_4C = stream->ReadValue(); + vehicle->no_vehicle_images = stream->ReadValue(); + vehicle->no_seating_rows = stream->ReadValue(); + vehicle->spinning_inertia = stream->ReadValue(); + vehicle->spinning_friction = stream->ReadValue(); + vehicle->friction_sound_id = stream->ReadValue(); + vehicle->var_58 = stream->ReadValue(); + vehicle->sound_range = stream->ReadValue(); + vehicle->var_5A = stream->ReadValue(); + vehicle->powered_acceleration = stream->ReadValue(); + vehicle->powered_max_speed = stream->ReadValue(); + vehicle->car_visual = stream->ReadValue(); + vehicle->effect_visual = stream->ReadValue(); + vehicle->draw_order = stream->ReadValue(); + vehicle->special_frames = stream->ReadValue(); + stream->Seek(4, STREAM_SEEK_CURRENT); +} diff --git a/src/object/RideObject.h b/src/object/RideObject.h index 02c4094ea4..70d9b81b60 100644 --- a/src/object/RideObject.h +++ b/src/object/RideObject.h @@ -48,5 +48,5 @@ public: void SetRepositoryItem(ObjectRepositoryItem * item) const; private: - + void ReadLegacyVehicle(IReadObjectContext * context, IStream * stream, rct_ride_entry_vehicle * vehicle); }; From 488da7942c49e21aea630e39dd727700276ddcf0 Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 6 Jul 2016 20:37:28 +0100 Subject: [PATCH 076/116] use object_manager_get_loaded_object instead --- src/object/ObjectRepository.cpp | 8 -------- src/object/ObjectRepository.h | 1 - src/windows/editor_inventions_list.c | 6 +++++- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 18ae1ce8e5..e89f21dd7c 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -711,14 +711,6 @@ extern "C" return (void *)object; } - void * object_repository_get_loaded_object(uint8 objectType, uint8 entryIndex) - { - int index = GetObjectEntryIndex(objectType, entryIndex); - - IObjectManager * objectManager = GetObjectManager(); - return (void *)objectManager->GetLoadedObject(index); - } - void object_repository_unload(size_t itemIndex) { // TODO diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 1ee96967b4..9652f13708 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -86,7 +86,6 @@ const ObjectRepositoryItem * object_repository_get_items(); const ObjectRepositoryItem * object_repository_find_object_by_entry(const rct_object_entry * entry); const ObjectRepositoryItem * object_repository_find_object_by_name(const char * name); void * object_repository_load_object(const rct_object_entry * objectEntry); -void * object_repository_get_loaded_object(uint8 objectType, uint8 entryIndex); void object_repository_unload(size_t itemIndex); void object_delete(void * object); diff --git a/src/windows/editor_inventions_list.c b/src/windows/editor_inventions_list.c index f15c16a0cb..25fee9c2eb 100644 --- a/src/windows/editor_inventions_list.c +++ b/src/windows/editor_inventions_list.c @@ -23,6 +23,7 @@ #include "../localisation/localisation.h" #include "../management/research.h" #include "../object.h" +#include "../object/ObjectManager.h" #include "../object/ObjectRepository.h" #include "../rct1.h" #include "../sprites.h" @@ -783,9 +784,12 @@ static void window_editor_inventions_list_paint(rct_window *w, rct_drawpixelinfo if (chunk == NULL || chunk == (void*)0xFFFFFFFF) return; + rct_object_entry * entry = &object_entry_groups[objectEntryType].entries[researchItem->entryIndex & 0xFF].entry; + // Draw preview widget = &w->widgets[WIDX_PREVIEW]; - void * object = object_repository_get_loaded_object(objectEntryType, researchItem->entryIndex & 0xFF); + + void * object = object_manager_get_loaded_object(entry); if (object != NULL) { rct_drawpixelinfo clipDPI; x = w->x + widget->left + 1; From f59d6b7a002437ce602de72b03c6f6a96c52bd60 Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 6 Jul 2016 22:31:14 +0100 Subject: [PATCH 077/116] implement unloading arbitrary objects --- src/object/ObjectManager.cpp | 65 +++++++++++++++++++++++---- src/object/ObjectManager.h | 2 + src/object/ObjectRepository.cpp | 5 --- src/object/ObjectRepository.h | 1 - src/windows/editor_object_selection.c | 51 ++++++++++++--------- 5 files changed, 89 insertions(+), 35 deletions(-) diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index 1daa07634d..f430c668cb 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -67,16 +67,10 @@ public: uint8 GetLoadedObjectEntryIndex(const Object * object) override { uint8 result = UINT8_MAX; - if (_loadedObjects != nullptr) + size_t index = GetLoadedObjectIndex(object); + if (index != SIZE_MAX) { - for (size_t i = 0; i < OBJECT_ENTRY_COUNT; i++) - { - if (_loadedObjects[i] == object) - { - get_type_entry_index(i, nullptr, &result); - break; - } - } + get_type_entry_index(index, nullptr, &result); } return result; } @@ -141,6 +135,36 @@ public: } } + void UnloadObjects(const rct_object_entry * entries, size_t count) override + { + // TODO there are two performance issues here: + // - FindObject for every entry which is a dictionary lookup + // - GetLoadedObjectIndex for every entry which enumerates _loadedList + + size_t numObjectsUnloaded = 0; + for (size_t i = 0; i < count; i++) + { + const rct_object_entry * entry = &entries[i]; + const ObjectRepositoryItem * ori = _objectRepository->FindObject(entry); + if (ori != nullptr) + { + Object * loadedObject = ori->LoadedObject; + size_t index = GetLoadedObjectIndex(loadedObject); + + UnloadObject(loadedObject); + _loadedObjects[index] = nullptr; + + numObjectsUnloaded++; + } + } + + if (numObjectsUnloaded > 0) + { + UpdateLegacyLoadedObjectList(); + reset_type_to_ride_entry_index_map(); + } + } + void UnloadAll() override { if (_loadedObjects != nullptr) @@ -173,6 +197,23 @@ private: return -1; } + size_t GetLoadedObjectIndex(const Object * object) + { + size_t result = SIZE_MAX; + if (_loadedObjects != nullptr) + { + for (size_t i = 0; i < OBJECT_ENTRY_COUNT; i++) + { + if (_loadedObjects[i] == object) + { + result = i; + break; + } + } + } + return result; + } + void SetNewLoadedObjectList(Object * * newLoadedObjects) { if (newLoadedObjects == nullptr) @@ -415,4 +456,10 @@ extern "C" Object * loadedObject = objectManager->LoadObject(entry); return (void *)loadedObject; } + + void object_manager_unload_objects(const rct_object_entry * entries, size_t count) + { + IObjectManager * objectManager = GetObjectManager(); + objectManager->UnloadObjects(entries, count); + } } diff --git a/src/object/ObjectManager.h b/src/object/ObjectManager.h index a2a2ad1ea4..21c37b260b 100644 --- a/src/object/ObjectManager.h +++ b/src/object/ObjectManager.h @@ -39,6 +39,7 @@ interface IObjectManager virtual Object * LoadObject(const rct_object_entry * entry) abstract; virtual bool LoadObjects(const rct_object_entry * entries, size_t count) abstract; + virtual void UnloadObjects(const rct_object_entry * entries, size_t count) abstract; virtual void UnloadAll() abstract; }; @@ -49,5 +50,6 @@ IObjectManager * GetObjectManager(); void * object_manager_get_loaded_object(const rct_object_entry * entry); uint8 object_manager_get_loaded_object_entry_index(const void * loadedObject); void * object_manager_load_object(const rct_object_entry * entry); +void object_manager_unload_objects(const rct_object_entry * entries, size_t count); #endif diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index e89f21dd7c..cc2e742d46 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -711,11 +711,6 @@ extern "C" return (void *)object; } - void object_repository_unload(size_t itemIndex) - { - // TODO - } - void object_unload_all() { IObjectManager * objectManager = GetObjectManager(); diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 9652f13708..6779471b2b 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -86,7 +86,6 @@ const ObjectRepositoryItem * object_repository_get_items(); const ObjectRepositoryItem * object_repository_find_object_by_entry(const rct_object_entry * entry); const ObjectRepositoryItem * object_repository_find_object_by_name(const char * name); void * object_repository_load_object(const rct_object_entry * objectEntry); -void object_repository_unload(size_t itemIndex); void object_delete(void * object); const utf8 * object_get_description(const void * object); diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 946cce1152..a9f67bf558 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -27,6 +27,7 @@ #include "../management/research.h" #include "../object.h" #include "../object_list.h" +#include "../object/ObjectManager.h" #include "../object/ObjectRepository.h" #include "../rct1.h" #include "../ride/ride.h" @@ -714,12 +715,21 @@ void unload_unselected_objects() { int numItems = object_repository_get_items_count(); const ObjectRepositoryItem * items = object_repository_get_items(); + + size_t numObjectsToUnload = 0; + rct_object_entry * objectsToUnload = (rct_object_entry *)malloc(numItems * sizeof(rct_object_entry)); + for (int i = 0; i < numItems; i++) { if (!(_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED)) { - remove_selected_objects_from_research(&items[i].ObjectEntry); - object_repository_unload(i); + const rct_object_entry * entry = &items[i].ObjectEntry; + + remove_selected_objects_from_research(entry); + objectsToUnload[numObjectsToUnload++] = *entry; } } + + object_manager_unload_objects(objectsToUnload, numObjectsToUnload); + free(objectsToUnload); } /** @@ -1703,27 +1713,28 @@ static void window_editor_object_selection_manage_tracks() */ static void editor_load_selected_objects() { - int numObjects = (int)object_repository_get_items_count(); + int numItems = (int)object_repository_get_items_count(); const ObjectRepositoryItem * items = object_repository_get_items(); - for (int i = 0; i < numObjects; i++) { + for (int i = 0; i < numItems; i++) { if (_objectSelectionFlags[i] & OBJECT_SELECTION_FLAG_SELECTED) { - uint8 entry_index, entry_type; - if (!find_object_in_entry_group(&items[i].ObjectEntry, &entry_type, &entry_index)) { - if (!object_load_chunk(-1, &items[i].ObjectEntry, NULL)) { - log_error("Failed to load entry %.8s", items->Name); + const ObjectRepositoryItem * item = &items[i]; + const rct_object_entry * entry = &item->ObjectEntry; + void * loadedObject = object_manager_get_loaded_object(entry); + if (loadedObject == NULL) { + loadedObject = object_manager_load_object(entry); + if (loadedObject == NULL) { + log_error("Failed to load entry %.8s", entry->name); } - - // For in game use (cheat) - if (!(gScreenFlags & SCREEN_FLAGS_EDITOR)) { - // Defaults selected items to researched. - if (find_object_in_entry_group(&items[i].ObjectEntry, &entry_type, &entry_index)) { - if (entry_type == OBJECT_TYPE_RIDE) { - rct_ride_entry* rideType = get_ride_entry(entry_index); - research_insert(1, 0x10000 | (rideType->ride_type[0] << 8) | entry_index, rideType->category[0]); - } - else if (entry_type == OBJECT_TYPE_SCENERY_SETS) { - research_insert(1, entry_index, RESEARCH_CATEGORY_SCENERYSET); - } + else if (!(gScreenFlags & SCREEN_FLAGS_EDITOR)) { + // Defaults selected items to researched (if in-game) + uint8 objectType = entry->flags & 0x0F; + uint8 entryIndex = object_manager_get_loaded_object_entry_index(loadedObject); + if (objectType == OBJECT_TYPE_RIDE) { + rct_ride_entry *rideType = get_ride_entry(entryIndex); + research_insert(1, 0x10000 | (rideType->ride_type[0] << 8) | entryIndex, rideType->category[0]); + } + else if (objectType == OBJECT_TYPE_SCENERY_SETS) { + research_insert(1, entryIndex, RESEARCH_CATEGORY_SCENERYSET); } } } From fa951a29cdcf3dfea447e4eab2679a080c56ef1c Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 6 Jul 2016 23:01:54 +0100 Subject: [PATCH 078/116] use object manager for S4Importer --- src/object/ObjectManager.h | 2 ++ src/rct1/S4Importer.cpp | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/object/ObjectManager.h b/src/object/ObjectManager.h index 21c37b260b..452ff979bb 100644 --- a/src/object/ObjectManager.h +++ b/src/object/ObjectManager.h @@ -29,6 +29,8 @@ extern "C" #ifdef __cplusplus +class Object; + interface IObjectManager { virtual ~IObjectManager() { } diff --git a/src/rct1/S4Importer.cpp b/src/rct1/S4Importer.cpp index 00d67f96c4..b4110a24bc 100644 --- a/src/rct1/S4Importer.cpp +++ b/src/rct1/S4Importer.cpp @@ -22,6 +22,7 @@ #include "../core/Path.hpp" #include "../core/String.hpp" #include "../core/Util.hpp" +#include "../object/ObjectManager.h" #include "Tables.h" extern "C" @@ -740,6 +741,8 @@ void S4Importer::LoadObjects() void S4Importer::LoadObjects(uint8 objectType, List entries) { + IObjectManager * objectManager = GetObjectManager(); + uint32 entryIndex = 0; for (const char * objectName : entries) { @@ -747,8 +750,9 @@ void S4Importer::LoadObjects(uint8 objectType, List entries) entry.flags = 0x00008000 + objectType; Memory::Copy(entry.name, objectName, 8); entry.checksum = 0; - - if (!object_load_chunk(entryIndex, &entry, NULL)) + + Object * object = objectManager->LoadObject(&entry); + if (object == nullptr) { log_error("Failed to load %s.", objectName); throw Exception("Failed to load object."); From d7e1933f12182327640dd76565611a499b521ede Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 7 Jul 2016 00:09:31 +0100 Subject: [PATCH 079/116] fix track manager preview --- src/object/ObjectManager.cpp | 6 ++++++ src/object/ObjectManager.h | 1 + src/ride/track_design.c | 23 ++++++++--------------- src/windows/editor_object_selection.c | 2 -- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index f430c668cb..ac9c8b72eb 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -462,4 +462,10 @@ extern "C" IObjectManager * objectManager = GetObjectManager(); objectManager->UnloadObjects(entries, count); } + + void object_manager_unload_all_objects() + { + IObjectManager * objectManager = GetObjectManager(); + objectManager->UnloadAll(); + } } diff --git a/src/object/ObjectManager.h b/src/object/ObjectManager.h index 452ff979bb..2a1c12dbc6 100644 --- a/src/object/ObjectManager.h +++ b/src/object/ObjectManager.h @@ -53,5 +53,6 @@ void * object_manager_get_loaded_object(const rct_object_entry * entry); uint8 object_manager_get_loaded_object_entry_index(const void * loadedObject); void * object_manager_load_object(const rct_object_entry * entry); void object_manager_unload_objects(const rct_object_entry * entries, size_t count); +void object_manager_unload_all_objects(); #endif diff --git a/src/ride/track_design.c b/src/ride/track_design.c index d09a3b90b8..e70f18d668 100644 --- a/src/ride/track_design.c +++ b/src/ride/track_design.c @@ -22,6 +22,7 @@ #include "../localisation/string_ids.h" #include "../management/finance.h" #include "../network/network.h" +#include "../object/ObjectManager.h" #include "../rct1.h" #include "../util/sawyercoding.h" #include "../util/util.h" @@ -325,26 +326,18 @@ void track_design_dispose(rct_track_td6 *td6) */ static void track_design_load_scenery_objects(rct_track_td6 *td6) { - uint8 entry_index = RCT2_GLOBAL(0xF44157, uint8); - rct_object_entry_extended* object_entry = &object_entry_groups[0].entries[entry_index]; + object_manager_unload_all_objects(); - rct_object_entry* copied_entry = RCT2_ADDRESS(0xF43414, rct_object_entry); - memcpy(copied_entry, object_entry, sizeof(rct_object_entry)); - - object_unload_all(); - object_load_chunk(-1, copied_entry, 0); - uint8 entry_type; - find_object_in_entry_group(copied_entry, &entry_type, &entry_index); - RCT2_GLOBAL(0xF44157, uint8) = entry_index; + // Load ride object + rct_object_entry * rideEntry = &td6->vehicle_object; + void * loadedObject = object_manager_load_object(rideEntry); + // Load scenery objects rct_td6_scenery_element *scenery = td6->scenery_elements; for (; (scenery->scenery_object.flags & 0xFF) != 0xFF; scenery++) { - if (!find_object_in_entry_group(&scenery->scenery_object, &entry_type, &entry_index)) { - object_load_chunk(-1, &scenery->scenery_object, 0); - } + rct_object_entry * sceneryEntry = &scenery->scenery_object; + object_manager_load_object(sceneryEntry); } - - reset_loaded_objects(); } /** diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index a9f67bf558..8350eb933c 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -1693,8 +1693,6 @@ static void window_editor_object_selection_manage_tracks() int entry_index = 0; for (; ((int)object_entry_groups[0].chunks[entry_index]) == -1; ++entry_index); - RCT2_GLOBAL(0xF44157, uint8) = entry_index; - rct_ride_entry* ride_entry = get_ride_entry(entry_index); uint8* ride_type_array = &ride_entry->ride_type[0]; From 9801e92d794249ec09832bc933e0263403b0258e Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 7 Jul 2016 17:50:02 +0100 Subject: [PATCH 080/116] fix track manager object filtering --- src/windows/editor_object_selection.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 8350eb933c..bd60391e68 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -472,26 +472,15 @@ static void setup_track_manager_objects() uint8 * selectionFlags = &_objectSelectionFlags[i]; const ObjectRepositoryItem * item = &items[i]; uint8 object_type = item->ObjectEntry.flags & 0xF; - if (object_type == OBJECT_TYPE_RIDE){ + if (object_type == OBJECT_TYPE_RIDE) { *selectionFlags |= OBJECT_SELECTION_FLAG_6; for (uint8 j = 0; j < 3; j++) { uint8 rideType = item->RideType[j]; - if (rideType == 0xFF) - continue; - - if (!ride_type_has_flag(rideType, RIDE_TYPE_FLAG_HAS_TRACK)) - continue; - - if (item->RideType[3] & (1 << 0)) { - *selectionFlags &= ~OBJECT_SELECTION_FLAG_6; - } else if (ride_list[rideType] & (1 << 0)) { - continue; - } else { - ride_list[rideType] |= (1 << 0); + if (rideType != 0xFF && ride_type_has_flag(rideType, RIDE_TYPE_FLAG_HAS_TRACK)) { *selectionFlags &= ~OBJECT_SELECTION_FLAG_6; + break; } - break; } } } From 65e14fb1dfa9820d21c22d151fefd084a9142645 Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 7 Jul 2016 17:55:07 +0100 Subject: [PATCH 081/116] fix, not adding end tile to large scenery --- src/object/LargeSceneryObject.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index a51918eadf..83accca6b1 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -139,6 +139,7 @@ rct_large_scenery_tile * LargeSceneryObject::ReadTiles(IStream * stream) auto tile = stream->ReadValue(); tiles.push_back(tile); } + tiles.push_back({ -1, -1, -1, 255, 0xFFFF }); return Memory::DuplicateArray(tiles.data(), tiles.size()); } From 03674a450f9df3c81127f3d30ecb762dcff2755b Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 7 Jul 2016 19:17:09 +0100 Subject: [PATCH 082/116] improve performance of objects.idx loading --- src/object/ObjectRepository.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index cc2e742d46..958121f7f9 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -25,6 +25,7 @@ #include "../core/Guard.hpp" #include "../core/IStream.hpp" #include "../core/Memory.hpp" +#include "../core/MemoryStream.h" #include "../core/Path.hpp" #include "../core/Stopwatch.hpp" #include "../core/String.hpp" @@ -321,9 +322,16 @@ private: header.PathChecksum == _queryDirectoryResult.PathChecksum) { // Header matches, so the index is not out of date + + // Buffer the rest of file into memory to speed up item reading + size_t dataSize = (size_t)(fs.GetLength() - fs.GetPosition()); + void * data = fs.ReadArray(dataSize); + auto ms = MemoryStream(data, dataSize, MEMORY_ACCESS_READ | MEMORY_ACCESS_OWNER); + + // Read items for (uint32 i = 0; i < header.NumItems; i++) { - ObjectRepositoryItem item = ReadItem(&fs); + ObjectRepositoryItem item = ReadItem(&ms); AddItem(&item); } return true; From 60098aeef07de1c7283349c58bf60fbc3f6ff420 Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 7 Jul 2016 22:18:34 +0100 Subject: [PATCH 083/116] remove last use of object_load_chunk --- src/object.h | 1 - src/object/ObjectRepository.cpp | 52 --------------------------------- src/windows/install_track.c | 5 ++-- 3 files changed, 3 insertions(+), 55 deletions(-) diff --git a/src/object.h b/src/object.h index d5a2dea50a..c0ec05d5ed 100644 --- a/src/object.h +++ b/src/object.h @@ -115,7 +115,6 @@ bool object_saved_packed(SDL_RWops* rw, const rct_object_entry * entry); void object_unload_all(); int check_object_entry(const rct_object_entry *entry); -bool object_load_chunk(int groupIndex, const rct_object_entry * entry, int * outGroupIndex); bool object_entry_compare(const rct_object_entry *a, const rct_object_entry *b); int object_calculate_checksum(const rct_object_entry * entry, const void * data, size_t dataLength); void reset_loaded_objects(); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 958121f7f9..67b3656dcc 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -622,58 +622,6 @@ extern "C" objectRepository->LoadOrConstruct(); } - bool object_load_chunk(int groupIndex, const rct_object_entry * entry, int * outGroupIndex) - { - return false; - - // IObjectRepository * objectRepository = GetObjectRepository(); - // const ObjectRepositoryItem * ori = objectRepository->FindObject(entry); - // if (ori == nullptr) - // { - // ReportMissingObject(entry); - // return false; - // } - // - // Object * object = objectRepository->LoadObject(ori); - // if (object == nullptr) - // { - // utf8 objName[9] = { 0 }; - // Memory::Copy(objName, ori->ObjectEntry.name, 8); - // Console::Error::WriteFormat("[%s]: Object could not be loaded.", objName); - // Console::Error::WriteLine(); - // return false; - // } - // - // uint8 objectType = object->GetObjectType(); - // void * * chunkList = object_entry_groups[objectType].chunks; - // if (groupIndex == -1) - // { - // for (groupIndex = 0; chunkList[groupIndex] != (void*)-1; groupIndex++) - // { - // if (groupIndex + 1 >= object_entry_group_counts[objectType]) - // { - // log_error("Object Load failed due to too many objects of a certain type."); - // delete object; - // return false; - // } - // } - // } - // chunkList[groupIndex] = object->GetLegacyData(); - // if (outGroupIndex != nullptr) - // { - // *outGroupIndex = groupIndex; - // } - // - // rct_object_entry_extended * extendedEntry = &object_entry_groups[objectType].entries[groupIndex]; - // Memory::Copy(extendedEntry, object->GetObjectEntry(), sizeof(rct_object_entry)); - // extendedEntry->chunk_size = 0; - // - // int loadedObjectIndex = GetObjectEntryIndex(objectType, groupIndex); - // delete _loadedObjects[loadedObjectIndex]; - // _loadedObjects[loadedObjectIndex] = object; - // return true; - } - bool object_load_entries(rct_object_entry * entries) { log_verbose("loading required objects"); diff --git a/src/windows/install_track.c b/src/windows/install_track.c index f24e16f298..8d5da61a57 100644 --- a/src/windows/install_track.c +++ b/src/windows/install_track.c @@ -24,6 +24,7 @@ #include "../ride/ride.h" #include "../ride/track.h" #include "../ride/track_design.h" +#include "../object/ObjectManager.h" #include "../sprites.h" #include "../util/util.h" #include "error.h" @@ -108,12 +109,12 @@ void window_install_track_open(const utf8 *path) return; } - object_unload_all(); + object_manager_unload_all_objects(); if (_trackDesign->type == RIDE_TYPE_NULL){ log_error("Failed to load track (ride type null): %s", path); return; } - if (!object_load_chunk(0, &_trackDesign->vehicle_object, NULL)){ + if (object_manager_load_object(&_trackDesign->vehicle_object) == NULL) { log_error("Failed to load track (vehicle load fail): %s", path); return; } From 3f19becc2b7786b4311e8edd6be89ccd52605ebf Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 7 Jul 2016 22:58:48 +0100 Subject: [PATCH 084/116] remove object_unload_all --- src/editor.c | 9 +++++---- src/object.h | 1 - src/rct1/S4Importer.cpp | 3 ++- src/rct2.c | 3 ++- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/editor.c b/src/editor.c index 28adee5d2d..3262ca8a6d 100644 --- a/src/editor.c +++ b/src/editor.c @@ -26,6 +26,7 @@ #include "management/finance.h" #include "management/news_item.h" #include "object.h" +#include "object/ObjectManager.h" #include "peep/staff.h" #include "platform/platform.h" #include "rct1.h" @@ -59,7 +60,7 @@ void editor_load() audio_pause_sounds(); audio_unpause_sounds(); - object_unload_all(); + object_manager_unload_all_objects(); object_list_load(); map_init(150); banner_init(); @@ -146,7 +147,7 @@ void trackdesigner_load() gScreenFlags = SCREEN_FLAGS_TRACK_DESIGNER; gScreenAge = 0; - object_unload_all(); + object_manager_unload_all_objects(); object_list_load(); map_init(150); set_all_land_owned(); @@ -185,7 +186,7 @@ void trackmanager_load() gScreenFlags = SCREEN_FLAGS_TRACK_MANAGER; gScreenAge = 0; - object_unload_all(); + object_manager_unload_all_objects(); object_list_load(); map_init(150); set_all_land_owned(); @@ -484,7 +485,7 @@ void editor_open_windows_for_current_step() return; if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) { - object_unload_all(); + object_manager_unload_all_objects(); } window_editor_object_selection_open(); diff --git a/src/object.h b/src/object.h index c0ec05d5ed..201b8ab2c4 100644 --- a/src/object.h +++ b/src/object.h @@ -112,7 +112,6 @@ bool object_read_and_load_entries(SDL_RWops* rw); bool object_load_entries(rct_object_entry* entries); int object_load_packed(SDL_RWops* rw); bool object_saved_packed(SDL_RWops* rw, const rct_object_entry * entry); -void object_unload_all(); int check_object_entry(const rct_object_entry *entry); bool object_entry_compare(const rct_object_entry *a, const rct_object_entry *b); diff --git a/src/rct1/S4Importer.cpp b/src/rct1/S4Importer.cpp index b4110a24bc..fcdd6343d4 100644 --- a/src/rct1/S4Importer.cpp +++ b/src/rct1/S4Importer.cpp @@ -37,6 +37,7 @@ extern "C" #include "../management/finance.h" #include "../management/marketing.h" #include "../object.h" + #include "../object/ObjectManager.h" #include "../peep/staff.h" #include "../rct1.h" #include "../util/sawyercoding.h" @@ -111,7 +112,7 @@ void S4Importer::Initialise() // Do map initialisation, same kind of stuff done when loading scenario editor audio_pause_sounds(); audio_unpause_sounds(); - object_unload_all(); + GetObjectManager()->UnloadAll(); map_init(mapSize); banner_init(); reset_park_entrances(); diff --git a/src/rct2.c b/src/rct2.c index b081a7db5b..98d4e536c0 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -35,6 +35,7 @@ #include "network/network.h" #include "network/twitch.h" #include "object.h" +#include "object/ObjectManager.h" #include "openrct2.h" #include "peep/staff.h" #include "platform/platform.h" @@ -140,7 +141,7 @@ void rct2_dispose() { gfx_unload_g2(); gfx_unload_g1(); - object_unload_all(); + object_manager_unload_all_objects(); } int rct2_init() From 8b03b996c01cce1186e457250f43cf3634e0c0cc Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 7 Jul 2016 23:05:55 +0100 Subject: [PATCH 085/116] ensure _objectRepository and _objectManager are freed --- src/object/ObjectManager.cpp | 7 ++++--- src/object/ObjectRepository.cpp | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index ac9c8b72eb..3fcccd6a71 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -15,6 +15,7 @@ #pragma endregion #include +#include #include #include "../core/Console.hpp" #include "../core/Memory.hpp" @@ -421,16 +422,16 @@ private: } }; -ObjectManager * _objectManager; +static std::unique_ptr _objectManager; IObjectManager * GetObjectManager() { if (_objectManager == nullptr) { IObjectRepository * objectRepository = GetObjectRepository(); - _objectManager = new ObjectManager(objectRepository); + _objectManager = std::unique_ptr(new ObjectManager(objectRepository)); } - return _objectManager; + return _objectManager.get(); } extern "C" diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 67b3656dcc..646f7b37fc 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -15,6 +15,7 @@ #pragma endregion #include +#include #include #include @@ -578,15 +579,15 @@ private: } }; -static ObjectRepository * _objectRepository = nullptr; +static std::unique_ptr _objectRepository; IObjectRepository * GetObjectRepository() { if (_objectRepository == nullptr) { - _objectRepository = new ObjectRepository(); + _objectRepository = std::unique_ptr(new ObjectRepository()); } - return _objectRepository; + return _objectRepository.get(); } static int GetObjectEntryIndex(uint8 objectType, uint8 entryIndex) From 4664b734888a292c1222d2c8755505d0ffdf68b9 Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 7 Jul 2016 23:22:42 +0100 Subject: [PATCH 086/116] remove object_unload_all --- src/object/ObjectRepository.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 646f7b37fc..8f45087742 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -668,12 +668,6 @@ extern "C" return (void *)object; } - void object_unload_all() - { - IObjectManager * objectManager = GetObjectManager(); - objectManager->UnloadAll(); - } - void scenario_translate(scenario_index_entry * scenarioEntry, const rct_object_entry * stexObjectEntry) { rct_string_id localisedStringIds[3]; From 78c6b6a2513a30e615ee1f12be187dccbee012dd Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 7 Jul 2016 23:32:45 +0100 Subject: [PATCH 087/116] remove all unnecessary object resets --- src/editor.c | 1 - src/localisation/language.cpp | 11 +++++------ src/object.h | 1 - src/object/ObjectManager.cpp | 16 ++++++++++++++++ src/object/ObjectManager.h | 2 ++ src/object/ObjectRepository.cpp | 18 ------------------ src/rct1/S4Importer.cpp | 2 -- src/rct2/S6Exporter.cpp | 3 --- src/rct2/S6Importer.cpp | 1 - src/windows/editor_object_selection.c | 1 - 10 files changed, 23 insertions(+), 33 deletions(-) diff --git a/src/editor.c b/src/editor.c index 3262ca8a6d..1b41d24749 100644 --- a/src/editor.c +++ b/src/editor.c @@ -370,7 +370,6 @@ static int editor_read_s6(const char *path) return 0; } - reset_loaded_objects(); map_update_tile_pointers(); game_convert_strings_to_utf8(); diff --git a/src/localisation/language.cpp b/src/localisation/language.cpp index d154358954..64f86c4576 100644 --- a/src/localisation/language.cpp +++ b/src/localisation/language.cpp @@ -15,6 +15,7 @@ #pragma endregion #include +#include "../object/ObjectManager.h" #include "LanguagePack.h" extern "C" { @@ -189,13 +190,12 @@ bool language_open(int id) gCurrentTTFFontSet = &TTFFontCustom; bool font_initialised = ttf_initialise(); - if(!font_initialised) { + if (!font_initialised) { log_warning("Unable to initialise configured TrueType font -- falling back to Language default."); } else { // Objects and their localized strings need to be refreshed - reset_loaded_objects(); - - return 1; + GetObjectManager()->ResetObjects(); + return true; } } ttf_dispose(); @@ -220,8 +220,7 @@ bool language_open(int id) } // Objects and their localized strings need to be refreshed - reset_loaded_objects(); - + GetObjectManager()->ResetObjects(); return true; } diff --git a/src/object.h b/src/object.h index 201b8ab2c4..dfc9c3519c 100644 --- a/src/object.h +++ b/src/object.h @@ -116,7 +116,6 @@ bool object_saved_packed(SDL_RWops* rw, const rct_object_entry * entry); int check_object_entry(const rct_object_entry *entry); bool object_entry_compare(const rct_object_entry *a, const rct_object_entry *b); int object_calculate_checksum(const rct_object_entry * entry, const void * data, size_t dataLength); -void reset_loaded_objects(); int find_object_in_entry_group(const rct_object_entry* entry, uint8* entry_type, uint8* entry_index); void object_create_identifier_name(char* string_buffer, const rct_object_entry* object); diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index 3fcccd6a71..fa67e51406 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -180,6 +180,22 @@ public: reset_type_to_ride_entry_index_map(); } + void ResetObjects() override + { + if (_loadedObjects != nullptr) + { + for (size_t i = 0; i < OBJECT_ENTRY_COUNT; i++) + { + Object * loadedObject = _loadedObjects[i]; + if (loadedObject != nullptr) + { + loadedObject->Unload(); + loadedObject->Load(); + } + } + } + } + private: sint32 FindSpareSlot(uint8 objectType) { diff --git a/src/object/ObjectManager.h b/src/object/ObjectManager.h index 2a1c12dbc6..efa219dba6 100644 --- a/src/object/ObjectManager.h +++ b/src/object/ObjectManager.h @@ -43,6 +43,8 @@ interface IObjectManager virtual bool LoadObjects(const rct_object_entry * entries, size_t count) abstract; virtual void UnloadObjects(const rct_object_entry * entries, size_t count) abstract; virtual void UnloadAll() abstract; + + virtual void ResetObjects() abstract; }; IObjectManager * GetObjectManager(); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 8f45087742..8ede7696ff 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -634,24 +634,6 @@ extern "C" return true; } - void reset_loaded_objects() - { - // if (_loadedObjects != nullptr) - // { - // for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) - // { - // Object * object = _loadedObjects[i]; - // if (object != nullptr) - // { - // object->Unload(); - // object->Load(); - // } - // } - // } - // - // reset_type_to_ride_entry_index_map(); - } - void * object_repository_load_object(const rct_object_entry * objectEntry) { Object * object = nullptr; diff --git a/src/rct1/S4Importer.cpp b/src/rct1/S4Importer.cpp index fcdd6343d4..dbdb0686bd 100644 --- a/src/rct1/S4Importer.cpp +++ b/src/rct1/S4Importer.cpp @@ -736,8 +736,6 @@ void S4Importer::LoadObjects() })); LoadObjects(OBJECT_TYPE_PARK_ENTRANCE, List({ "PKENT1 " })); LoadObjects(OBJECT_TYPE_WATER, List({ "WTRCYAN " })); - - reset_loaded_objects(); } void S4Importer::LoadObjects(uint8 objectType, List entries) diff --git a/src/rct2/S6Exporter.cpp b/src/rct2/S6Exporter.cpp index be20a8e3b2..e379c293c0 100644 --- a/src/rct2/S6Exporter.cpp +++ b/src/rct2/S6Exporter.cpp @@ -507,7 +507,6 @@ extern "C" } delete s6exporter; - reset_loaded_objects(); gfx_invalidate_screen(); if (result && !(flags & S6_SAVE_FLAG_AUTOMATIC)) @@ -540,8 +539,6 @@ extern "C" return 0; } - reset_loaded_objects(); - // Write other data not in normal save files SDL_WriteLE32(rw, gGamePaused); SDL_WriteLE32(rw, _guestGenerationProbability); diff --git a/src/rct2/S6Importer.cpp b/src/rct2/S6Importer.cpp index 286da59971..711c1b0be3 100644 --- a/src/rct2/S6Importer.cpp +++ b/src/rct2/S6Importer.cpp @@ -362,7 +362,6 @@ void S6Importer::Import() { throw ObjectLoadException(); } - reset_loaded_objects(); map_update_tile_pointers(); if (network_get_mode() == NETWORK_MODE_CLIENT) { diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index bd60391e68..dad3614819 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -732,7 +732,6 @@ static void window_editor_object_selection_close(rct_window *w) unload_unselected_objects(); editor_load_selected_objects(); - reset_loaded_objects(); editor_object_flags_free(); object_delete(_loadedObject); From a8c1c451d51a2d248bea7bb264e442b666f2f9b1 Mon Sep 17 00:00:00 2001 From: Ted John Date: Fri, 8 Jul 2016 21:47:20 +0100 Subject: [PATCH 088/116] fix freeing of non-pointer / union issue --- src/object/ObjectRepository.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 8ede7696ff..c538ae9457 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -480,10 +480,16 @@ private: { Memory::Free(item->Path); Memory::Free(item->Name); - Memory::Free(item->ThemeObjects); item->Path = nullptr; item->Name = nullptr; - item->ThemeObjects = nullptr; + + uint8 objectType = item->ObjectEntry.flags & 0x0F; + switch (objectType) { + case OBJECT_TYPE_SCENERY_SETS: + Memory::Free(item->ThemeObjects); + item->ThemeObjects = nullptr; + break; + } } static void SaveObject(const utf8 * path, const rct_object_entry * entry, const void * data, size_t dataSize) From 4d3fca767de2af1a111bdf31222fcdf2553db980 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 00:27:21 +0100 Subject: [PATCH 089/116] document and name G1 flags --- src/drawing/drawing.h | 7 +++++-- src/drawing/sprite.c | 10 +++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/drawing/drawing.h b/src/drawing/drawing.h index 4c0d568ea8..d89a620c9d 100644 --- a/src/drawing/drawing.h +++ b/src/drawing/drawing.h @@ -71,8 +71,11 @@ assert_struct_size(rct_g1_element_32bit, 0x10); enum { - G1_FLAG_BMP = (1 << 0), //No invisible sections - G1_FLAG_RLE_COMPRESSION = (1<<2), + G1_FLAG_BMP = (1 << 0), // Image data is encoded as raw pixels (no transparancy) + G1_FLAG_1 = (1 << 1), + G1_FLAG_RLE_COMPRESSION = (1 << 2), // Image data is encoded using RCT2's form of run length encoding + G1_FLAG_HAS_ZOOM_SPRITE = (1 << 4), // Use a different sprite for higher zoom levels + G1_FLAG_NO_ZOOM_DRAW = (1 << 5), // Does not get drawn at higher zoom levels (only zoom 0) }; enum { diff --git a/src/drawing/sprite.c b/src/drawing/sprite.c index 26458bb1ab..ab1b8bfa3a 100644 --- a/src/drawing/sprite.c +++ b/src/drawing/sprite.c @@ -425,7 +425,7 @@ void FASTCALL gfx_draw_sprite_palette_set_software(rct_drawpixelinfo *dpi, int i rct_g1_element *g1_source = gfx_get_g1_element(image_element); - if ( dpi->zoom_level && (g1_source->flags & (1<<4)) ){ + if (dpi->zoom_level != 0 && (g1_source->flags & G1_FLAG_HAS_ZOOM_SPRITE)) { rct_drawpixelinfo zoomed_dpi = { .bits = dpi->bits, .x = dpi->x >> 1, @@ -439,7 +439,7 @@ void FASTCALL gfx_draw_sprite_palette_set_software(rct_drawpixelinfo *dpi, int i return; } - if ( dpi->zoom_level && (g1_source->flags & (1<<5)) ){ + if (dpi->zoom_level != 0 && (g1_source->flags & G1_FLAG_NO_ZOOM_DRAW)) { return; } @@ -554,7 +554,7 @@ void FASTCALL gfx_draw_sprite_palette_set_software(rct_drawpixelinfo *dpi, int i //Move the pointer to the start point of the source source_pointer += g1_source->width*source_start_y + source_start_x; - if (!(g1_source->flags & 0x02)){ + if (!(g1_source->flags & G1_FLAG_1)) { gfx_bmp_sprite_to_buffer(palette_pointer, unknown_pointer, source_pointer, dest_pointer, g1_source, dpi, height, width, image_type); return; } @@ -609,8 +609,8 @@ void FASTCALL gfx_draw_sprite_raw_masked_software(rct_drawpixelinfo *dpi, int x, rct_g1_element *imgMask = &g1Elements[maskImage & 0x7FFFF]; rct_g1_element *imgColour = &g1Elements[colourImage & 0x7FFFF]; - assert(imgMask->flags & 1); - assert(imgColour->flags & 1); + assert(imgMask->flags & G1_FLAG_BMP); + assert(imgColour->flags & G1_FLAG_BMP); if (dpi->zoom_level != 0) { // TODO implement other zoom levels (probably not used though) From 3d291b027aa36e29cf217d0d9a03a8c72f77cc5f Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 01:28:48 +0100 Subject: [PATCH 090/116] load objects with larger than expected image data --- src/object/ImageTable.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/object/ImageTable.cpp b/src/object/ImageTable.cpp index 7d6ddb34b6..a8c81266d5 100644 --- a/src/object/ImageTable.cpp +++ b/src/object/ImageTable.cpp @@ -34,6 +34,14 @@ void ImageTable::Read(IReadObjectContext * context, IStream * stream) uint32 numImages = stream->ReadValue(); uint32 imageDataSize = stream->ReadValue(); + uint64 headerTableSize = numImages * 16; + uint64 remainingBytes = stream->GetLength() - stream->GetPosition() - headerTableSize; + if (remainingBytes > imageDataSize) + { + context->LogWarning(OBJECT_ERROR_BAD_IMAGE_TABLE, "Image table size longer than expected."); + imageDataSize = (uint32)remainingBytes; + } + _dataSize = imageDataSize; _data = Memory::Reallocate(_data, _dataSize); @@ -68,6 +76,8 @@ void ImageTable::Read(IReadObjectContext * context, IStream * stream) context->LogWarning(OBJECT_ERROR_BAD_IMAGE_TABLE, "Image table size shorter than expected."); } + + // TODO validate the image data to prevent crashes in-game } catch (Exception ex) { From 5785020b077b7f405ded57a74dceb523b6d94881 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 01:28:57 +0100 Subject: [PATCH 091/116] fix clip size of preview --- src/windows/editor_inventions_list.c | 4 ++-- src/windows/editor_object_selection.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/windows/editor_inventions_list.c b/src/windows/editor_inventions_list.c index 25fee9c2eb..575b07e8c8 100644 --- a/src/windows/editor_inventions_list.c +++ b/src/windows/editor_inventions_list.c @@ -794,8 +794,8 @@ static void window_editor_inventions_list_paint(rct_window *w, rct_drawpixelinfo rct_drawpixelinfo clipDPI; x = w->x + widget->left + 1; y = w->y + widget->top + 1; - int width = widget->right - widget->left; - int height = widget->bottom - widget->top; + int width = widget->right - widget->left - 1; + int height = widget->bottom - widget->top - 1; if (clip_drawpixelinfo(&clipDPI, dpi, x, y, width, height)) { object_draw_preview(object, &clipDPI); } diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index dad3614819..65064ee936 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -1319,8 +1319,8 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf rct_drawpixelinfo clipDPI; x = w->x + widget->left + 1; y = w->y + widget->top + 1; - int width = widget->right - widget->left; - int height = widget->bottom - widget->top; + int width = widget->right - widget->left - 1; + int height = widget->bottom - widget->top - 1; if (clip_drawpixelinfo(&clipDPI, dpi, x, y, width, height)) { object_draw_preview(_loadedObject, &clipDPI); } From 7c8fbf35883bea6ca04689d07660457727c389c2 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 02:01:27 +0100 Subject: [PATCH 092/116] fix scenery group population --- src/object/ObjectManager.cpp | 24 ++++++++++++++ src/object/SceneryGroupObject.cpp | 52 +++++++++++++++++++------------ src/object/SceneryGroupObject.h | 1 + 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index fa67e51406..f2fa25a423 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -22,6 +22,7 @@ #include "Object.h" #include "ObjectManager.h" #include "ObjectRepository.h" +#include "SceneryGroupObject.h" extern "C" { @@ -94,6 +95,7 @@ public: { _loadedObjects[slot] = loadedObject; UpdateLegacyLoadedObjectList(); + UpdateSceneryGroupIndexes(); reset_type_to_ride_entry_index_map(); } } @@ -130,6 +132,7 @@ public: { SetNewLoadedObjectList(loadedObjects); UpdateLegacyLoadedObjectList(); + UpdateSceneryGroupIndexes(); reset_type_to_ride_entry_index_map(); // Console::WriteLine("%u / %u new objects loaded", numNewLoadedObjects, numRequiredObjects); return true; @@ -162,6 +165,7 @@ public: if (numObjectsUnloaded > 0) { UpdateLegacyLoadedObjectList(); + UpdateSceneryGroupIndexes(); reset_type_to_ride_entry_index_map(); } } @@ -177,6 +181,7 @@ public: } } UpdateLegacyLoadedObjectList(); + UpdateSceneryGroupIndexes(); reset_type_to_ride_entry_index_map(); } @@ -329,6 +334,25 @@ private: } } + void UpdateSceneryGroupIndexes() + { + if (_loadedObjects != nullptr) + { + for (size_t i = 0; i < OBJECT_ENTRY_COUNT; i++) + { + Object * loadedObject = _loadedObjects[i]; + if (loadedObject != nullptr) + { + if (loadedObject->GetObjectType() == OBJECT_TYPE_SCENERY_SETS) + { + auto sgObject = static_cast(loadedObject); + sgObject->UpdateEntryIndexes(); + } + } + } + } + } + bool GetRequiredObjects(const rct_object_entry * entries, const ObjectRepositoryItem * * requiredObjects, size_t * outNumRequiredObjects) diff --git a/src/object/SceneryGroupObject.cpp b/src/object/SceneryGroupObject.cpp index 2976d6c2a9..45bc7bd6d8 100644 --- a/src/object/SceneryGroupObject.cpp +++ b/src/object/SceneryGroupObject.cpp @@ -16,6 +16,7 @@ #include "../core/IStream.hpp" #include "../core/Memory.hpp" +#include "ObjectManager.h" #include "ObjectRepository.h" #include "SceneryGroupObject.h" @@ -56,27 +57,7 @@ void SceneryGroupObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); - _legacyType.entry_count = 0; - for (uint32 i = 0; i < _numItems; i++) - { - uint8 entryType; - uint8 entryIndex; - if (find_object_in_entry_group(&_items[i], &entryType, &entryIndex)) - { - uint16 sceneryEntry = entryIndex; - switch (entryType) { - case OBJECT_TYPE_SMALL_SCENERY: break; - case OBJECT_TYPE_LARGE_SCENERY: sceneryEntry |= 0x300; break; - case OBJECT_TYPE_WALLS: sceneryEntry |= 0x200; break; - case OBJECT_TYPE_PATH_BITS: sceneryEntry |= 0x100; break; - default: sceneryEntry |= 0x400; break; - } - - _legacyType.scenery_entries[_legacyType.entry_count] = sceneryEntry; - _legacyType.entry_count++; - } - } } void SceneryGroupObject::Unload() @@ -97,6 +78,37 @@ void SceneryGroupObject::DrawPreview(rct_drawpixelinfo * dpi) const gfx_draw_sprite(dpi, imageId, x - 15, y - 14, 0); } +void SceneryGroupObject::UpdateEntryIndexes() +{ + IObjectRepository * objectRepository = GetObjectRepository(); + IObjectManager * objectManager = GetObjectManager(); + + _legacyType.entry_count = 0; + for (uint32 i = 0; i < _numItems; i++) + { + const rct_object_entry * objectEntry = &_items[i]; + + const ObjectRepositoryItem * ori = objectRepository->FindObject(objectEntry); + if (ori == nullptr) continue; + if (ori->LoadedObject == nullptr) continue; + + uint16 sceneryEntry = objectManager->GetLoadedObjectEntryIndex(ori->LoadedObject); + Guard::Assert(sceneryEntry != UINT8_MAX); + + uint8 objectType = objectEntry->flags & 0x0F; + switch (objectType) { + case OBJECT_TYPE_SMALL_SCENERY: break; + case OBJECT_TYPE_LARGE_SCENERY: sceneryEntry |= 0x300; break; + case OBJECT_TYPE_WALLS: sceneryEntry |= 0x200; break; + case OBJECT_TYPE_PATH_BITS: sceneryEntry |= 0x100; break; + default: sceneryEntry |= 0x400; break; + } + + _legacyType.scenery_entries[_legacyType.entry_count] = sceneryEntry; + _legacyType.entry_count++; + } +} + void SceneryGroupObject::SetRepositoryItem(ObjectRepositoryItem * item) const { Memory::Free(item->ThemeObjects); diff --git a/src/object/SceneryGroupObject.h b/src/object/SceneryGroupObject.h index af4df3cd44..93697ee0c7 100644 --- a/src/object/SceneryGroupObject.h +++ b/src/object/SceneryGroupObject.h @@ -41,6 +41,7 @@ public: void ReadLegacy(IReadObjectContext * context, IStream * stream) override; void Load() override; void Unload() override; + void UpdateEntryIndexes(); void DrawPreview(rct_drawpixelinfo * dpi) const override; From abda262b138de218a1fd32c895f0e90919570423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Sat, 9 Jul 2016 13:14:46 +0200 Subject: [PATCH 093/116] Add missing override specifier --- src/object/RideObject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/object/RideObject.h b/src/object/RideObject.h index 70d9b81b60..40f229452d 100644 --- a/src/object/RideObject.h +++ b/src/object/RideObject.h @@ -45,7 +45,7 @@ public: const utf8 * GetDescription() const; const utf8 * GetCapacity() const; - void SetRepositoryItem(ObjectRepositoryItem * item) const; + void SetRepositoryItem(ObjectRepositoryItem * item) const override; private: void ReadLegacyVehicle(IReadObjectContext * context, IStream * stream, rct_ride_entry_vehicle * vehicle); From a25d7aa53518740dc4df4feb4275f8cf16ffe846 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 14:13:46 +0100 Subject: [PATCH 094/116] check for LoadObjects failure --- src/object/ObjectRepository.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index c538ae9457..47405bc71d 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -207,6 +207,8 @@ public: // TODO append checksum match bytes + // TODO check object is loadable before writing it + utf8 path[MAX_PATH]; GetPathForNewObject(path, sizeof(path), objectName); @@ -540,11 +542,12 @@ private: Path::Append(buffer, bufferSize, normalisedName); String::Append(buffer, bufferSize, ".DAT"); + uint32 counter = 2; for (; platform_file_exists(buffer);) { - uint32 counter = 2; utf8 counterString[8]; snprintf(counterString, sizeof(counterString), "-%02X", counter); + counter++; GetUserObjectPath(buffer, bufferSize); Path::Append(buffer, bufferSize, normalisedName); @@ -634,10 +637,10 @@ extern "C" log_verbose("loading required objects"); IObjectManager * objectManger = GetObjectManager(); - objectManger->LoadObjects(entries, OBJECT_ENTRY_COUNT); + bool result = objectManger->LoadObjects(entries, OBJECT_ENTRY_COUNT); log_verbose("finished loading required objects"); - return true; + return result; } void * object_repository_load_object(const rct_object_entry * objectEntry) From 8c2393f5c5076f986f7509aed58d606ef5036c01 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 14:52:56 +0100 Subject: [PATCH 095/116] don't export invalid objects --- src/object/ObjectFactory.cpp | 24 ++++++++++++++++++++++++ src/object/ObjectFactory.h | 1 + src/object/ObjectManager.cpp | 4 ++-- src/object/ObjectRepository.cpp | 32 ++++++++++++++++++++------------ 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 0fa7a36fdd..8446f76f5a 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -167,6 +167,30 @@ namespace ObjectFactory return result; } + Object * CreateObjectFromLegacyData(const rct_object_entry * entry, const void * data, size_t dataSize) + { + Guard::ArgumentNotNull(entry); + Guard::ArgumentNotNull(data); + + Object * result = CreateObject(*entry); + if (result != nullptr) + { + utf8 objectName[9] = { 0 }; + Memory::Copy(objectName, entry->name, 8); + + auto readContext = ReadObjectContext(objectName); + auto chunkStream = MemoryStream(data, dataSize); + ReadObjectLegacy(result, &readContext, &chunkStream); + + if (readContext.WasError()) + { + delete result; + result = nullptr; + } + } + return result; + } + Object * CreateObject(const rct_object_entry &entry) { Object * result = nullptr; diff --git a/src/object/ObjectFactory.h b/src/object/ObjectFactory.h index 1f1ac4647e..455fa256b9 100644 --- a/src/object/ObjectFactory.h +++ b/src/object/ObjectFactory.h @@ -23,5 +23,6 @@ class Object; namespace ObjectFactory { Object * CreateObjectFromLegacyFile(const utf8 * path); + Object * CreateObjectFromLegacyData(const rct_object_entry * entry, const void * data, size_t dataSize); Object * CreateObject(const rct_object_entry &entry); } diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index f2fa25a423..eb3f0e4941 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -438,7 +438,7 @@ private: { utf8 objName[9] = { 0 }; Memory::Copy(objName, entry->name, 8); - Console::Error::WriteFormat("[%s]: Object not found.", objName); + Console::Error::WriteFormat("[%s] Object not found.", objName); Console::Error::WriteLine(); } @@ -446,7 +446,7 @@ private: { utf8 objName[9] = { 0 }; Memory::Copy(objName, entry->name, 8); - Console::Error::WriteFormat("[%s]: Object could not be loaded.", objName); + Console::Error::WriteFormat("[%s] Object could not be loaded.", objName); Console::Error::WriteLine(); } diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 47405bc71d..07e3fdbf0e 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -207,20 +207,28 @@ public: // TODO append checksum match bytes - // TODO check object is loadable before writing it - - utf8 path[MAX_PATH]; - GetPathForNewObject(path, sizeof(path), objectName); - - Console::WriteLine("Adding object: [%s]", objectName); - try + // Check that the object is loadable before writing it + Object * object = ObjectFactory::CreateObjectFromLegacyData(objectEntry, data, dataSize); + if (object == nullptr) { - SaveObject(path, objectEntry, data, dataSize); - ScanObject(path); + Console::Error::WriteFormat("[%s] Unable to export object.", objectName); + Console::Error::WriteLine(); } - catch (Exception ex) + else { - Console::WriteLine("Failed saving object: [%s] to '%s'.", objectName, path); + utf8 path[MAX_PATH]; + GetPathForNewObject(path, sizeof(path), objectName); + + Console::WriteLine("Adding object: [%s]", objectName); + try + { + SaveObject(path, objectEntry, data, dataSize); + ScanObject(path); + } + catch (Exception ex) + { + Console::WriteLine("Failed saving object: [%s] to '%s'.", objectName, path); + } } } @@ -895,6 +903,6 @@ static void ReportMissingObject(const rct_object_entry * entry) { utf8 objName[9] = { 0 }; Memory::Copy(objName, entry->name, 8); - Console::Error::WriteFormat("[%s]: Object not found.", objName); + Console::Error::WriteFormat("[%s] Object not found.", objName); Console::Error::WriteLine(); } From 3c64010fe13d05f26e97bb64c287f02cc7e6d7e8 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 15:02:05 +0100 Subject: [PATCH 096/116] Make Console::Error::WriteLine formattable --- src/cmdline/CommandLine.cpp | 20 ++++++------------- src/cmdline/RootCommands.cpp | 9 +++------ src/core/Console.cpp | 10 +++++++--- src/core/Console.hpp | 2 +- src/drawing/engines/opengl/OpenGLAPI.cpp | 2 +- .../engines/opengl/OpenGLShaderProgram.cpp | 4 ++-- src/object/ObjectFactory.cpp | 9 +++------ src/object/ObjectManager.cpp | 6 ++---- src/object/ObjectRepository.cpp | 12 ++++------- 9 files changed, 29 insertions(+), 45 deletions(-) diff --git a/src/cmdline/CommandLine.cpp b/src/cmdline/CommandLine.cpp index d3801122b6..1a65a055e2 100644 --- a/src/cmdline/CommandLine.cpp +++ b/src/cmdline/CommandLine.cpp @@ -397,8 +397,7 @@ namespace CommandLine const CommandLineOptionDefinition * option = FindOption(options, optionName); if (option == nullptr) { - Console::Error::Write("Unknown option: --"); - Console::Error::WriteLine(optionName); + Console::Error::WriteLine("Unknown option: --%s", optionName); return false; } @@ -413,8 +412,7 @@ namespace CommandLine const char * valueString = nullptr; if (!argEnumerator->TryPopString(&valueString)) { - Console::Error::Write("Expected value for option: "); - Console::Error::WriteLine(optionName); + Console::Error::WriteLine("Expected value for option: %s", optionName); return false; } @@ -428,8 +426,7 @@ namespace CommandLine { if (option->Type == CMDLINE_TYPE_SWITCH) { - Console::Error::Write("Option is a switch: "); - Console::Error::WriteLine(optionName); + Console::Error::WriteLine("Option is a switch: %s", optionName); return false; } else @@ -456,9 +453,7 @@ namespace CommandLine option = FindOption(options, shortOption[0]); if (option == nullptr) { - Console::Error::Write("Unknown option: -"); - Console::Error::Write(shortOption[0]); - Console::Error::WriteLine(); + Console::Error::WriteLine("Unknown option: -%c", shortOption[0]); return false; } if (option->Type == CMDLINE_TYPE_SWITCH) @@ -483,9 +478,7 @@ namespace CommandLine const char * valueString = nullptr; if (!argEnumerator->TryPopString(&valueString)) { - Console::Error::Write("Expected value for option: "); - Console::Error::Write(option->ShortName); - Console::Error::WriteLine(); + Console::Error::WriteLine("Expected value for option: %c", option->ShortName); return false; } @@ -516,8 +509,7 @@ namespace CommandLine *((utf8 * *)option->OutAddress) = String::Duplicate(valueString); return true; default: - Console::Error::Write("Unknown CMDLINE_TYPE for: "); - Console::Error::WriteLine(option->LongName); + Console::Error::WriteLine("Unknown CMDLINE_TYPE for: %s", option->LongName); return false; } } diff --git a/src/cmdline/RootCommands.cpp b/src/cmdline/RootCommands.cpp index 89f0a29571..c224e00cb5 100644 --- a/src/cmdline/RootCommands.cpp +++ b/src/cmdline/RootCommands.cpp @@ -312,8 +312,7 @@ static exitcode_t HandleCommandSetRCT2(CommandLineArgEnumerator * enumerator) Console::WriteLine("Checking path..."); if (!platform_directory_exists(path)) { - Console::Error::WriteFormat("The path '%s' does not exist", path); - Console::Error::WriteLine(); + Console::Error::WriteLine("The path '%s' does not exist", path); return EXITCODE_FAIL; } @@ -327,8 +326,7 @@ static exitcode_t HandleCommandSetRCT2(CommandLineArgEnumerator * enumerator) if (!platform_file_exists(pathG1Check)) { Console::Error::WriteLine("RCT2 path not valid."); - Console::Error::WriteFormat("Unable to find %s.", pathG1Check); - Console::Error::WriteLine(); + Console::Error::WriteLine("Unable to find %s.", pathG1Check); return EXITCODE_FAIL; } @@ -337,8 +335,7 @@ static exitcode_t HandleCommandSetRCT2(CommandLineArgEnumerator * enumerator) platform_resolve_user_data_path(); platform_get_user_directory(userPath, NULL); if (!platform_ensure_directory_exists(userPath)) { - Console::Error::WriteFormat("Unable to access or create directory '%s'.", userPath); - Console::Error::WriteLine(); + Console::Error::WriteLine("Unable to access or create directory '%s'.", userPath); return EXITCODE_FAIL; } diff --git a/src/core/Console.cpp b/src/core/Console.cpp index f1b8c937b2..d82064022d 100644 --- a/src/core/Console.cpp +++ b/src/core/Console.cpp @@ -91,10 +91,14 @@ namespace Console fputs(platform_get_new_line(), stderr); } - void WriteLine(const utf8 * str) + void WriteLine(const utf8 * format, ...) { - fputs(str, stderr); - WriteLine(); + va_list args; + + va_start(args, format); + vfprintf(stdout, format, args); + puts(""); + va_end(args); } } } \ No newline at end of file diff --git a/src/core/Console.hpp b/src/core/Console.hpp index 64ac7a765b..4f8171235b 100644 --- a/src/core/Console.hpp +++ b/src/core/Console.hpp @@ -36,6 +36,6 @@ namespace Console void Write(const utf8 * str); void WriteFormat(const utf8 * format, ...); void WriteLine(); - void WriteLine(const utf8 * str); + void WriteLine(const utf8 * format, ...); } } diff --git a/src/drawing/engines/opengl/OpenGLAPI.cpp b/src/drawing/engines/opengl/OpenGLAPI.cpp index 42f661ae8b..8683262160 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.cpp +++ b/src/drawing/engines/opengl/OpenGLAPI.cpp @@ -133,7 +133,7 @@ bool OpenGLAPI::Initialise() const char * failedProcName = TryLoadAllProcAddresses(); if (failedProcName != nullptr) { - Console::Error::WriteFormat("Failed to load %s.\n", failedProcName); + Console::Error::WriteLine("Failed to load %s.", failedProcName); return false; } #endif diff --git a/src/drawing/engines/opengl/OpenGLShaderProgram.cpp b/src/drawing/engines/opengl/OpenGLShaderProgram.cpp index 3cc4162078..922b3af625 100644 --- a/src/drawing/engines/opengl/OpenGLShaderProgram.cpp +++ b/src/drawing/engines/opengl/OpenGLShaderProgram.cpp @@ -51,7 +51,7 @@ OpenGLShader::OpenGLShader(const char * name, GLenum type) glGetShaderInfoLog(_id, sizeof(buffer), nullptr, buffer); glDeleteShader(_id); - Console::Error::WriteFormat("Error compiling %s\n", path); + Console::Error::WriteLine("Error compiling %s", path); Console::Error::WriteLine(buffer); throw Exception("Error compiling shader."); @@ -115,7 +115,7 @@ OpenGLShaderProgram::OpenGLShaderProgram(const char * name) GLsizei length; glGetProgramInfoLog(_id, sizeof(buffer), &length, buffer); - Console::Error::WriteFormat("Error linking %s\n", name); + Console::Error::WriteLine("Error linking %s", name); Console::Error::WriteLine(buffer); throw Exception("Failed to link OpenGL shader."); diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 8446f76f5a..2900f9130e 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -68,8 +68,7 @@ public: if (!String::IsNullOrEmpty(text)) { - Console::Error::WriteFormat("[%s] Warning: %s", _objectName, text); - Console::Error::WriteLine(); + Console::Error::WriteLine("[%s] Warning: %s", _objectName, text); } } @@ -79,8 +78,7 @@ public: if (!String::IsNullOrEmpty(text)) { - Console::Error::WriteFormat("[%s] Error: %s", _objectName, text); - Console::Error::WriteLine(); + Console::Error::WriteLine("[%s] Error: %s", _objectName, text); } } }; @@ -154,8 +152,7 @@ namespace ObjectFactory if (readContext.WasError()) { - Console::Error::WriteFormat("Error reading object: '%s'", path); - Console::Error::WriteLine(); + Console::Error::WriteLine("Error reading object: '%s'", path); delete result; result = nullptr; diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index eb3f0e4941..8045ea11cb 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -438,16 +438,14 @@ private: { utf8 objName[9] = { 0 }; Memory::Copy(objName, entry->name, 8); - Console::Error::WriteFormat("[%s] Object not found.", objName); - Console::Error::WriteLine(); + Console::Error::WriteLine("[%s] Object not found.", objName); } static void ReportObjectLoadProblem(const rct_object_entry * entry) { utf8 objName[9] = { 0 }; Memory::Copy(objName, entry->name, 8); - Console::Error::WriteFormat("[%s] Object could not be loaded.", objName); - Console::Error::WriteLine(); + Console::Error::WriteLine("[%s] Object could not be loaded.", objName); } static sint32 GetIndexFromTypeEntry(uint8 objectType, uint8 entryIndex) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 07e3fdbf0e..f7417fddc9 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -211,8 +211,7 @@ public: Object * object = ObjectFactory::CreateObjectFromLegacyData(objectEntry, data, dataSize); if (object == nullptr) { - Console::Error::WriteFormat("[%s] Unable to export object.", objectName); - Console::Error::WriteLine(); + Console::Error::WriteLine("[%s] Unable to export object.", objectName); } else { @@ -418,10 +417,8 @@ private: } else { - Console::Error::WriteFormat("Object conflict: '%s'", conflict->Path); - Console::Error::WriteLine(); - Console::Error::WriteFormat(" : '%s'", item->Path); - Console::Error::WriteLine(); + Console::Error::WriteLine("Object conflict: '%s'", conflict->Path); + Console::Error::WriteLine(" : '%s'", item->Path); return false; } } @@ -903,6 +900,5 @@ static void ReportMissingObject(const rct_object_entry * entry) { utf8 objName[9] = { 0 }; Memory::Copy(objName, entry->name, 8); - Console::Error::WriteFormat("[%s] Object not found.", objName); - Console::Error::WriteLine(); + Console::Error::WriteLine("[%s] Object not found.", objName); } From ce878723d7f56968e0c3c18175c8d9a268dfd01d Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 15:24:00 +0100 Subject: [PATCH 097/116] add helper methods for object entry names --- src/object.h | 3 +++ src/object/ObjectFactory.cpp | 4 ++-- src/object/ObjectRepository.cpp | 4 ++-- src/object_list.c | 22 ++++++++++++++++++++++ 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/object.h b/src/object.h index dfc9c3519c..b4b95ca07f 100644 --- a/src/object.h +++ b/src/object.h @@ -122,4 +122,7 @@ void object_create_identifier_name(char* string_buffer, const rct_object_entry* rct_object_entry *object_list_find_by_name(const char *name); rct_object_entry *object_list_find(rct_object_entry *entry); +void object_entry_get_name(utf8 * buffer, size_t bufferSize, const rct_object_entry * entry); +void object_entry_get_name_fixed(utf8 * buffer, size_t bufferSize, const rct_object_entry * entry); + #endif diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 2900f9130e..83a292d2a5 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -172,8 +172,8 @@ namespace ObjectFactory Object * result = CreateObject(*entry); if (result != nullptr) { - utf8 objectName[9] = { 0 }; - Memory::Copy(objectName, entry->name, 8); + utf8 objectName[9]; + object_entry_get_name_fixed(objectName, sizeof(objectName), entry); auto readContext = ReadObjectContext(objectName); auto chunkStream = MemoryStream(data, dataSize); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index f7417fddc9..cb29d02549 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -192,8 +192,8 @@ public: void AddObject(const rct_object_entry * objectEntry, const void * data, size_t dataSize) override { - char objectName[9] = { 0 }; - Memory::Copy(objectName, objectEntry->name, 8); + utf8 objectName[9]; + object_entry_get_name_fixed(objectName, sizeof(objectName), objectEntry); int realChecksum = object_calculate_checksum(objectEntry, (const uint8 *)data, (int)dataSize); if (realChecksum != objectEntry->checksum) diff --git a/src/object_list.c b/src/object_list.c index d43f0070fa..9bebda6519 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -26,6 +26,7 @@ #include "ride/track.h" #include "ride/track_design.h" #include "util/sawyercoding.h" +#include "util/util.h" #include "world/entrance.h" #include "world/footpath.h" #include "world/scenery.h" @@ -255,3 +256,24 @@ void * get_loaded_object_chunk(size_t index) void *entry = object_entry_groups[objectType].chunks[entryIndex]; return entry; } + +void object_entry_get_name(utf8 * buffer, size_t bufferSize, const rct_object_entry * entry) +{ + size_t nameLength = 8; + const char * end = memchr(entry->name, ' ', 8); + if (end != NULL) + { + nameLength = (size_t)(end - entry->name); + } + + bufferSize = min(nameLength + 1, bufferSize); + memcpy(buffer, entry->name, bufferSize - 1); + buffer[bufferSize - 1] = 0; +} + +void object_entry_get_name_fixed(utf8 * buffer, size_t bufferSize, const rct_object_entry * entry) +{ + bufferSize = min(9, bufferSize); + memcpy(buffer, entry->name, bufferSize - 1); + buffer[bufferSize - 1] = 0; +} From 4de1f2912a8c4adddbbec0c8a4d5c8dd7b03ec0b Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 15:36:48 +0100 Subject: [PATCH 098/116] remove unnecessary functions --- src/editor.c | 3 +- src/object.h | 1 - src/object_list.c | 67 ----------------------------------------- src/object_list.h | 1 - src/openrct2.c | 2 -- src/rct2/S6Importer.cpp | 5 ++- 6 files changed, 3 insertions(+), 76 deletions(-) diff --git a/src/editor.c b/src/editor.c index 1b41d24749..e1f6ad78cf 100644 --- a/src/editor.c +++ b/src/editor.c @@ -364,9 +364,8 @@ static int editor_read_s6(const char *path) } SDL_RWclose(rw); - if (!load_success){ + if (!load_success) { log_error("failed to load all entries."); - set_load_objects_fail_reason(); return 0; } diff --git a/src/object.h b/src/object.h index b4b95ca07f..a0b6215c40 100644 --- a/src/object.h +++ b/src/object.h @@ -107,7 +107,6 @@ assert_struct_size(rct_object_filters, 3); extern const rct_object_entry_group object_entry_groups[]; void object_list_load(); -void set_load_objects_fail_reason(); bool object_read_and_load_entries(SDL_RWops* rw); bool object_load_entries(rct_object_entry* entries); int object_load_packed(SDL_RWops* rw); diff --git a/src/object_list.c b/src/object_list.c index 9bebda6519..b172e3e65e 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -15,22 +15,12 @@ #pragma endregion #include "addresses.h" -#include "config.h" #include "game.h" -#include "localisation/localisation.h" #include "object.h" #include "object_list.h" #include "object/ObjectRepository.h" -#include "platform/platform.h" -#include "rct1.h" -#include "ride/track.h" -#include "ride/track_design.h" #include "util/sawyercoding.h" #include "util/util.h" -#include "world/entrance.h" -#include "world/footpath.h" -#include "world/scenery.h" -#include "world/water.h" // 98DA00 int object_entry_group_counts[] = { @@ -126,54 +116,6 @@ void object_create_identifier_name(char* string_buffer, const rct_object_entry* *string_buffer++ = '\0'; } -/** - * - * rct2: 0x675827 - */ -void set_load_objects_fail_reason() -{ - return; - - rct_object_entry *object; - memcpy(&object, gCommonFormatArgs, sizeof(rct_object_entry*)); - - int expansion = (object->flags & 0xFF) >> 4; - if (expansion == 0 || - expansion == 8 || - RCT2_GLOBAL(RCT2_ADDRESS_EXPANSION_FLAGS, uint16) & (1 << expansion) - ) { - char* string_buffer = RCT2_ADDRESS(0x9BC677, char); - - format_string(string_buffer, STR_MISSING_OBJECT_DATA_ID, 0); - - object_create_identifier_name(string_buffer, object); - gErrorType = ERROR_TYPE_FILE_LOAD; - gErrorStringId = STR_PLACEHOLDER; - return; - } - - rct_string_id expansionNameId; - switch(expansion) { - case 1: // Wacky Worlds - expansionNameId = STR_OBJECT_FILTER_WW; - break; - case 2: // Time Twister - expansionNameId = STR_OBJECT_FILTER_TT; - break; - default: - gErrorType = ERROR_TYPE_FILE_LOAD; - gErrorStringId = STR_REQUIRES_AN_ADDON_PACK; - return; - } - - char* string_buffer = RCT2_ADDRESS(0x9BC677, char); - - format_string(string_buffer, STR_REQUIRES_THE_FOLLOWING_ADDON_PACK, &expansionNameId); - - gErrorType = ERROR_TYPE_FILE_LOAD; - gErrorStringId = STR_PLACEHOLDER; -} - /** * * rct2: 0x006AA0C6 @@ -213,15 +155,6 @@ int find_object_in_entry_group(const rct_object_entry* entry, uint8* entry_type, return 1; } -void object_list_init() -{ - for (uint8 objectType = 0; objectType < OBJECT_ENTRY_GROUP_COUNT; objectType++) { - for (size_t i = 0; i < (size_t)object_entry_group_counts[objectType]; i++) { - object_entry_groups[objectType].chunks[i] = (void*)-1; - } - } -} - void get_type_entry_index(size_t index, uint8 * outObjectType, uint8 * outEntryIndex) { uint8 objectType = OBJECT_TYPE_RIDE; diff --git a/src/object_list.h b/src/object_list.h index 040b1d6e3d..d8cf0fae0c 100644 --- a/src/object_list.h +++ b/src/object_list.h @@ -33,7 +33,6 @@ #define gStexEntries RCT2_ADDRESS(RCT2_ADDRESS_SCENARIO_TEXT_ENTRIES, rct_stex_entry*) #endif -void object_list_init(); void get_type_entry_index(size_t index, uint8 * outObjectType, uint8 * outEntryIndex); const rct_object_entry * get_loaded_object_entry(size_t index); void * get_loaded_object_chunk(size_t index); diff --git a/src/openrct2.c b/src/openrct2.c index fcfe3fee32..c9cefd18eb 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -222,8 +222,6 @@ bool openrct2_initialise() audio_populate_devices(); } - object_list_init(); - if (!language_open(gConfigGeneral.language)) { log_error("Failed to open configured language..."); diff --git a/src/rct2/S6Importer.cpp b/src/rct2/S6Importer.cpp index 711c1b0be3..edc5181a18 100644 --- a/src/rct2/S6Importer.cpp +++ b/src/rct2/S6Importer.cpp @@ -409,7 +409,6 @@ extern "C" } catch (ObjectLoadException) { - set_load_objects_fail_reason(); } catch (Exception) { @@ -442,7 +441,8 @@ extern "C" } catch (ObjectLoadException) { - set_load_objects_fail_reason(); + gErrorType = ERROR_TYPE_FILE_LOAD; + gErrorStringId = STR_GAME_SAVE_FAILED; } catch (IOException) { @@ -475,7 +475,6 @@ extern "C" } catch (ObjectLoadException) { - set_load_objects_fail_reason(); } catch (Exception) { From 234471c3fcc5db7eac921cd938bf1b14ef7c96c2 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 15:57:48 +0100 Subject: [PATCH 099/116] cope with same loaded object for multiple slots --- src/object/ObjectManager.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index 8045ea11cb..6c2c790a96 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -156,8 +156,6 @@ public: size_t index = GetLoadedObjectIndex(loadedObject); UnloadObject(loadedObject); - _loadedObjects[index] = nullptr; - numObjectsUnloaded++; } } @@ -177,7 +175,6 @@ public: for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) { UnloadObject(_loadedObjects[i]); - _loadedObjects[i] = nullptr; } } UpdateLegacyLoadedObjectList(); @@ -263,6 +260,19 @@ private: object->Unload(); delete object; + + // Because its possible to have the same loaded object for multiple + // slots, we have to make sure find and set all of them to nullptr + if (_loadedObjects != nullptr) + { + for (size_t i = 0; i < OBJECT_ENTRY_COUNT; i++) + { + if (_loadedObjects[i] == object) + { + _loadedObjects[i] = nullptr; + } + } + } } } @@ -296,7 +306,6 @@ private: if (exceptSet.find(object) == exceptSet.end()) { UnloadObject(object); - _loadedObjects[i] = nullptr; numObjectsUnloaded++; } } From 440c021951b3263ce93235ad72b796d8afd2404a Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 19:16:38 +0100 Subject: [PATCH 100/116] create base scenery object for scenery objects --- openrct2.vcxproj | 1 + src/object/BannerObject.cpp | 13 ++---------- src/object/BannerObject.h | 7 +++---- src/object/FootpathItemObject.cpp | 11 ++-------- src/object/FootpathItemObject.h | 7 +++---- src/object/LargeSceneryObject.cpp | 13 ++---------- src/object/LargeSceneryObject.h | 7 +++---- src/object/SceneryObject.h | 34 +++++++++++++++++++++++++++++++ src/object/SmallSceneryObject.cpp | 11 ++-------- src/object/SmallSceneryObject.h | 7 +++---- src/object/WallObject.cpp | 13 ++---------- src/object/WallObject.h | 7 +++---- 12 files changed, 60 insertions(+), 71 deletions(-) create mode 100644 src/object/SceneryObject.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index d8f417eea1..5d22df490c 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -449,6 +449,7 @@ + diff --git a/src/object/BannerObject.cpp b/src/object/BannerObject.cpp index 73eac1caf4..c86a74cd4a 100644 --- a/src/object/BannerObject.cpp +++ b/src/object/BannerObject.cpp @@ -39,7 +39,8 @@ void BannerObject::ReadLegacy(IReadObjectContext * context, IStream * stream) GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); - _sceneryTabEntry = stream->ReadValue(); + rct_object_entry sgEntry = stream->ReadValue(); + SetPrimarySceneryGroup(&sgEntry); GetImageTable()->Read(context, stream); @@ -54,16 +55,6 @@ void BannerObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); - - _legacyType.banner.scenery_tab_id = 0xFF; - if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) - { - uint8 entryType, entryIndex; - if (find_object_in_entry_group(&_sceneryTabEntry, &entryType, &entryIndex)) - { - _legacyType.banner.scenery_tab_id = entryIndex; - } - } } void BannerObject::Unload() diff --git a/src/object/BannerObject.h b/src/object/BannerObject.h index 4ef47e405c..fb20f37038 100644 --- a/src/object/BannerObject.h +++ b/src/object/BannerObject.h @@ -16,21 +16,20 @@ #pragma once -#include "Object.h" +#include "SceneryObject.h" extern "C" { #include "../world/scenery.h" } -class BannerObject : public Object +class BannerObject : public SceneryObject { private: rct_scenery_entry _legacyType = { 0 }; - rct_object_entry _sceneryTabEntry = { 0 }; public: - explicit BannerObject(const rct_object_entry &entry) : Object(entry) { }; + explicit BannerObject(const rct_object_entry &entry) : SceneryObject(entry) { }; void * GetLegacyData() override { return &_legacyType; } diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp index dfcec859d9..80b0cc1cbc 100644 --- a/src/object/FootpathItemObject.cpp +++ b/src/object/FootpathItemObject.cpp @@ -39,7 +39,8 @@ void FootpathItemObject::ReadLegacy(IReadObjectContext * context, IStream * stre GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); - _sceneryTabEntry = stream->ReadValue(); + rct_object_entry sgEntry = stream->ReadValue(); + SetPrimarySceneryGroup(&sgEntry); GetImageTable()->Read(context, stream); @@ -56,14 +57,6 @@ void FootpathItemObject::Load() _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.path_bit.scenery_tab_id = 0xFF; - if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) - { - uint8 entryType, entryIndex; - if (find_object_in_entry_group(&_sceneryTabEntry, &entryType, &entryIndex)) - { - _legacyType.path_bit.scenery_tab_id = entryIndex; - } - } } void FootpathItemObject::Unload() diff --git a/src/object/FootpathItemObject.h b/src/object/FootpathItemObject.h index e3812781a9..5ce31cc233 100644 --- a/src/object/FootpathItemObject.h +++ b/src/object/FootpathItemObject.h @@ -16,21 +16,20 @@ #pragma once -#include "Object.h" +#include "SceneryObject.h" extern "C" { #include "../world/scenery.h" } -class FootpathItemObject : public Object +class FootpathItemObject : public SceneryObject { private: rct_scenery_entry _legacyType = { 0 }; - rct_object_entry _sceneryTabEntry = { 0 }; public: - explicit FootpathItemObject(const rct_object_entry &entry) : Object(entry) { }; + explicit FootpathItemObject(const rct_object_entry &entry) : SceneryObject(entry) { }; void * GetLegacyData() override { return &_legacyType; } diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index 83accca6b1..6007af165a 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -49,7 +49,8 @@ void LargeSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); - _sceneryTabEntry = stream->ReadValue(); + rct_object_entry sgEntry = stream->ReadValue(); + SetPrimarySceneryGroup(&sgEntry); if (_legacyType.large_scenery.flags & (1 << 2)) { @@ -86,16 +87,6 @@ void LargeSceneryObject::Load() _legacyType.large_scenery.tiles = _tiles; - _legacyType.large_scenery.scenery_tab_id = 0xFF; - if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) - { - uint8 entryType, entryIndex; - if (find_object_in_entry_group(&_sceneryTabEntry, &entryType, &entryIndex)) - { - _legacyType.large_scenery.scenery_tab_id = entryIndex; - } - } - if (_legacyType.large_scenery.flags & (1 << 2)) { _legacyType.large_scenery.text_image = _legacyType.image; diff --git a/src/object/LargeSceneryObject.h b/src/object/LargeSceneryObject.h index 5f28210852..e4a86339c6 100644 --- a/src/object/LargeSceneryObject.h +++ b/src/object/LargeSceneryObject.h @@ -16,24 +16,23 @@ #pragma once -#include "Object.h" +#include "SceneryObject.h" extern "C" { #include "../world/scenery.h" } -class LargeSceneryObject : public Object +class LargeSceneryObject : public SceneryObject { private: rct_scenery_entry _legacyType = { 0 }; uint32 _baseImageId = 0; - rct_object_entry _sceneryTabEntry = { 0 }; rct_large_scenery_text * _3dFont = nullptr; rct_large_scenery_tile * _tiles = nullptr; public: - explicit LargeSceneryObject(const rct_object_entry &entry) : Object(entry) { }; + explicit LargeSceneryObject(const rct_object_entry &entry) : SceneryObject(entry) { }; ~LargeSceneryObject(); void * GetLegacyData() override { return &_legacyType; } diff --git a/src/object/SceneryObject.h b/src/object/SceneryObject.h new file mode 100644 index 0000000000..612079f221 --- /dev/null +++ b/src/object/SceneryObject.h @@ -0,0 +1,34 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "Object.h" + +class SceneryObject : public Object +{ +private: + rct_object_entry _primarySceneryGroupEntry = { 0 }; + +public: + explicit SceneryObject(const rct_object_entry &entry) : Object(entry) { } + virtual ~SceneryObject() { } + + const rct_object_entry * GetPrimarySceneryGroup() { return &_primarySceneryGroupEntry; } + +protected: + void SetPrimarySceneryGroup(const rct_object_entry * entry) { _primarySceneryGroupEntry = *entry; } +}; diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index ccb335da01..dcc45a748e 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -51,7 +51,8 @@ void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); - _sceneryTabEntry = stream->ReadValue(); + rct_object_entry sgEntry = stream->ReadValue(); + SetPrimarySceneryGroup(&sgEntry); if (_legacyType.small_scenery.flags & SMALL_SCENERY_FLAG16) { @@ -82,14 +83,6 @@ void SmallSceneryObject::Load() _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.small_scenery.scenery_tab_id = 0xFF; - if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) - { - uint8 entryType, entryIndex; - if (find_object_in_entry_group(&_sceneryTabEntry, &entryType, &entryIndex)) - { - _legacyType.small_scenery.scenery_tab_id = entryIndex; - } - } if (_legacyType.small_scenery.flags & SMALL_SCENERY_FLAG16) { diff --git a/src/object/SmallSceneryObject.h b/src/object/SmallSceneryObject.h index 36a14111ea..c44b9276c7 100644 --- a/src/object/SmallSceneryObject.h +++ b/src/object/SmallSceneryObject.h @@ -16,22 +16,21 @@ #pragma once -#include "Object.h" +#include "SceneryObject.h" extern "C" { #include "../world/scenery.h" } -class SmallSceneryObject : public Object +class SmallSceneryObject : public SceneryObject { private: rct_scenery_entry _legacyType = { 0 }; - rct_object_entry _sceneryTabEntry = { 0 }; uint8 * _var10data = nullptr; public: - explicit SmallSceneryObject(const rct_object_entry &entry) : Object(entry) { }; + explicit SmallSceneryObject(const rct_object_entry &entry) : SceneryObject(entry) { }; ~SmallSceneryObject(); void * GetLegacyData() override { return &_legacyType; } diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp index 233c62dd3d..5f960d2b75 100644 --- a/src/object/WallObject.cpp +++ b/src/object/WallObject.cpp @@ -42,7 +42,8 @@ void WallObject::ReadLegacy(IReadObjectContext * context, IStream * stream) GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); - _sceneryTabEntry = stream->ReadValue(); + rct_object_entry sgEntry = stream->ReadValue(); + SetPrimarySceneryGroup(&sgEntry); GetImageTable()->Read(context, stream); @@ -57,16 +58,6 @@ void WallObject::Load() { _legacyType.name = language_allocate_object_string(GetName()); _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); - - _legacyType.small_scenery.scenery_tab_id = 0xFF; - if ((_sceneryTabEntry.flags & 0xFF) != 0xFF) - { - uint8 entryType, entryIndex; - if (find_object_in_entry_group(&_sceneryTabEntry, &entryType, &entryIndex)) - { - _legacyType.small_scenery.scenery_tab_id = entryIndex; - } - } } void WallObject::Unload() diff --git a/src/object/WallObject.h b/src/object/WallObject.h index dc538c6405..7fcc26e1e0 100644 --- a/src/object/WallObject.h +++ b/src/object/WallObject.h @@ -16,21 +16,20 @@ #pragma once -#include "Object.h" +#include "SceneryObject.h" extern "C" { #include "../world/scenery.h" } -class WallObject : public Object +class WallObject : public SceneryObject { private: rct_scenery_entry _legacyType = { 0 }; - rct_object_entry _sceneryTabEntry = { 0 }; public: - explicit WallObject(const rct_object_entry &entry) : Object(entry) { }; + explicit WallObject(const rct_object_entry &entry) : SceneryObject(entry) { }; void * GetLegacyData() override { return &_legacyType; } From 7b17b603f3f88962b118c82e8d88531bb3770000 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 20:37:12 +0100 Subject: [PATCH 101/116] set scenery tab IDs --- src/object/ObjectManager.cpp | 46 ++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index 6c2c790a96..8db4fdf1f8 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -19,10 +19,14 @@ #include #include "../core/Console.hpp" #include "../core/Memory.hpp" +#include "FootpathItemObject.h" +#include "LargeSceneryObject.h" #include "Object.h" #include "ObjectManager.h" #include "ObjectRepository.h" #include "SceneryGroupObject.h" +#include "SmallSceneryObject.h" +#include "WallObject.h" extern "C" { @@ -218,6 +222,8 @@ private: size_t GetLoadedObjectIndex(const Object * object) { + Guard::ArgumentNotNull(object); + size_t result = SIZE_MAX; if (_loadedObjects != nullptr) { @@ -352,16 +358,52 @@ private: Object * loadedObject = _loadedObjects[i]; if (loadedObject != nullptr) { - if (loadedObject->GetObjectType() == OBJECT_TYPE_SCENERY_SETS) - { + rct_scenery_entry * sceneryEntry; + switch (loadedObject->GetObjectType()) { + case OBJECT_TYPE_SMALL_SCENERY: + sceneryEntry = (rct_scenery_entry *)loadedObject->GetLegacyData(); + sceneryEntry->small_scenery.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject); + break; + case OBJECT_TYPE_LARGE_SCENERY: + sceneryEntry = (rct_scenery_entry *)loadedObject->GetLegacyData(); + sceneryEntry->large_scenery.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject); + break; + case OBJECT_TYPE_WALLS: + sceneryEntry = (rct_scenery_entry *)loadedObject->GetLegacyData(); + sceneryEntry->wall.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject); + break; + case OBJECT_TYPE_BANNERS: + sceneryEntry = (rct_scenery_entry *)loadedObject->GetLegacyData(); + sceneryEntry->banner.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject); + break; + case OBJECT_TYPE_PATH_BITS: + sceneryEntry = (rct_scenery_entry *)loadedObject->GetLegacyData(); + sceneryEntry->path_bit.scenery_tab_id = GetPrimarySceneryGroupEntryIndex(loadedObject); + break; + case OBJECT_TYPE_SCENERY_SETS: auto sgObject = static_cast(loadedObject); sgObject->UpdateEntryIndexes(); + break; } } } } } + uint8 GetPrimarySceneryGroupEntryIndex(Object * loadedObject) + { + auto sceneryObject = static_cast(loadedObject); + const rct_object_entry * primarySGEntry = sceneryObject->GetPrimarySceneryGroup(); + Object * sgObject = GetLoadedObject(primarySGEntry); + + uint8 entryIndex = 255; + if (sgObject != nullptr) + { + entryIndex = GetLoadedObjectEntryIndex(sgObject); + } + return entryIndex; + } + bool GetRequiredObjects(const rct_object_entry * entries, const ObjectRepositoryItem * * requiredObjects, size_t * outNumRequiredObjects) From 3d824142ee81f96689d36b17ea7a548f730ad8f7 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 21:06:54 +0100 Subject: [PATCH 102/116] clean up init_scenery a bit --- src/management/research.c | 8 ++++++++ src/management/research.h | 1 + src/windows/scenery.c | 35 ++++++++++++++++------------------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/management/research.c b/src/management/research.c index f23bf8ec58..9d6f2a79e6 100644 --- a/src/management/research.c +++ b/src/management/research.c @@ -643,3 +643,11 @@ static void ride_entry_set_invented(int rideEntryIndex) int bitIndex = rideEntryIndex & 0x1F; gResearchedRideEntries[quadIndex] |= 1 << bitIndex; } + +bool scenery_is_invented(uint16 sceneryItem) +{ + int quadIndex = sceneryItem >> 5; + int bitIndex = sceneryItem & 0x1F; + bool invented = (gResearchedSceneryItems[quadIndex] & ((uint32)1 << bitIndex)); + return invented; +} diff --git a/src/management/research.h b/src/management/research.h index 3ab2a3327b..bd46a59801 100644 --- a/src/management/research.h +++ b/src/management/research.h @@ -105,5 +105,6 @@ void research_insert_scenery_group_entry(uint8 entryIndex, bool researched); bool ride_type_is_invented(int rideType); bool ride_entry_is_invented(int rideEntryIndex); bool track_type_is_invented(uint8 rideType, int trackType); +bool scenery_is_invented(uint16 sceneryItem); #endif diff --git a/src/windows/scenery.c b/src/windows/scenery.c index ab95070966..8e12837f8d 100644 --- a/src/windows/scenery.c +++ b/src/windows/scenery.c @@ -187,7 +187,7 @@ void window_scenery_update_scroll(rct_window *w); */ void init_scenery_entry(rct_scenery_entry *sceneryEntry, int index, uint8 sceneryTabId) { - if (gResearchedSceneryItems[index >> 5] & (1UL << (index & 0x1F))) { + if (scenery_is_invented(index)) { if (sceneryTabId != 0xFF) { for (int i = 0; i < SCENERY_ENTRIES_BY_TAB; i++) { if (window_scenery_tab_entries[sceneryTabId][i] == -1) @@ -199,7 +199,7 @@ void init_scenery_entry(rct_scenery_entry *sceneryEntry, int index, uint8 scener } } - for (int i = 0; i < 0x13; i++) { + for (int i = 0; i < 19; i++) { int counter = 0; while (window_scenery_tab_entries[i][counter] != -1) @@ -213,10 +213,10 @@ void init_scenery_entry(rct_scenery_entry *sceneryEntry, int index, uint8 scener } for (int i = 0; i < SCENERY_ENTRIES_BY_TAB; i++) { - if (window_scenery_tab_entries[0x13][i] == -1) + if (window_scenery_tab_entries[19][i] == -1) { - window_scenery_tab_entries[0x13][i] = index; - window_scenery_tab_entries[0x13][i + 1] = -1; + window_scenery_tab_entries[19][i] = index; + window_scenery_tab_entries[19][i + 1] = -1; break; } } @@ -229,24 +229,21 @@ void init_scenery_entry(rct_scenery_entry *sceneryEntry, int index, uint8 scener */ void init_scenery() { - bool enabledScenerySets[0x14] = { false }; + bool enabledScenerySets[20] = { false }; - for (int scenerySetIndex = 0; scenerySetIndex < 0x14; scenerySetIndex++) { + for (int scenerySetIndex = 0; scenerySetIndex < 20; scenerySetIndex++) { window_scenery_tab_entries[scenerySetIndex][0] = -1; - if (scenerySetIndex == 0x13) + if (scenerySetIndex == 19) continue; rct_scenery_set_entry* scenerySetEntry = get_scenery_group_entry(scenerySetIndex); - if ((uint32)scenerySetEntry == 0xFFFFFFFF) + if (scenerySetEntry == (rct_scenery_set_entry *)-1) continue; int sceneryTabEntryCount = 0; - for (int i = 0; i < scenerySetEntry->entry_count; i++) { uint16 sceneryEntryId = scenerySetEntry->scenery_entries[i]; - uint32 ecx = gResearchedSceneryItems[sceneryEntryId >> 5]; - uint32 edx = 1u << (sceneryEntryId & 0x1F); - if (ecx & edx) { + if (scenery_is_invented(sceneryEntryId)) { window_scenery_tab_entries[scenerySetIndex][sceneryTabEntryCount] = sceneryEntryId; window_scenery_tab_entries[scenerySetIndex][++sceneryTabEntryCount] = -1; } else { @@ -257,7 +254,7 @@ void init_scenery() // small scenery for (uint16 sceneryId = 0; sceneryId < 0xFC; sceneryId++) { - if ((uint32)get_small_scenery_entry(sceneryId) == 0xFFFFFFFF) + if (get_small_scenery_entry(sceneryId) == (rct_scenery_entry *)-1) continue; rct_scenery_entry* sceneryEntry = get_small_scenery_entry(sceneryId); @@ -268,7 +265,7 @@ void init_scenery() for (int sceneryId = 0x300; sceneryId < 0x380; sceneryId++) { int largeSceneryIndex = sceneryId - 0x300; - if ((uint32)get_large_scenery_entry(largeSceneryIndex) == 0xFFFFFFFF) + if (get_large_scenery_entry(largeSceneryIndex) == (rct_scenery_entry *)-1) continue; rct_scenery_entry* sceneryEntry = get_large_scenery_entry(largeSceneryIndex); @@ -279,7 +276,7 @@ void init_scenery() for (int sceneryId = 0x200; sceneryId < 0x280; sceneryId++) { int wallSceneryIndex = sceneryId - 0x200; - if ((uint32)get_wall_entry(wallSceneryIndex) == 0xFFFFFFFF) + if (get_wall_entry(wallSceneryIndex) == (rct_scenery_entry *)-1) continue; rct_scenery_entry* sceneryEntry = get_wall_entry(wallSceneryIndex); @@ -290,7 +287,7 @@ void init_scenery() for (int sceneryId = 0x400; sceneryId < 0x420; sceneryId++) { int bannerIndex = sceneryId - 0x400; - if ((uint32)get_banner_entry(bannerIndex) == 0xFFFFFFFF) + if (get_banner_entry(bannerIndex) == (rct_scenery_entry *)-1) continue; rct_scenery_entry* sceneryEntry = get_banner_entry(bannerIndex); @@ -301,7 +298,7 @@ void init_scenery() for (int sceneryId = 0x100; sceneryId < 0x10F; sceneryId++) { int pathBitIndex = sceneryId - 0x100; - if ((uint32)get_footpath_item_entry(pathBitIndex) == 0xFFFFFFFF) + if (get_footpath_item_entry(pathBitIndex) == (rct_scenery_entry *)-1) continue; rct_scenery_entry* sceneryEntry = get_footpath_item_entry(pathBitIndex); @@ -317,7 +314,7 @@ void init_scenery() for (int scenerySetId = 0; scenerySetId < 19; scenerySetId++) { rct_scenery_set_entry* sceneryEntry = get_scenery_group_entry(scenerySetId); - if ((uint32)sceneryEntry == 0xFFFFFFFF) + if (sceneryEntry == (rct_scenery_set_entry *)-1) continue; tabIndexes[usedValues] = scenerySetId; From b10b57e9dce60b21126653cbacf9536511caea18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Sat, 9 Jul 2016 22:15:02 +0200 Subject: [PATCH 103/116] add language 8 as a multibyte language --- src/localisation/language.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/localisation/language.cpp b/src/localisation/language.cpp index 64f86c4576..a3fb5c4489 100644 --- a/src/localisation/language.cpp +++ b/src/localisation/language.cpp @@ -315,6 +315,7 @@ static bool rct2_language_is_multibyte_charset(int languageId) case RCT2_LANGUAGE_ID_KOREAN: case RCT2_LANGUAGE_ID_CHINESE_TRADITIONAL: case RCT2_LANGUAGE_ID_CHINESE_SIMPLIFIED: + case RCT2_LANGUAGE_ID_8: return true; default: return false; From 8fd81c3b75586922f41861cd22e93e9c09503271 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 22:37:22 +0100 Subject: [PATCH 104/116] initialise legacy object list on startup --- src/object/ObjectRepository.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index cb29d02549..22075de61b 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -635,6 +635,9 @@ extern "C" { IObjectRepository * objectRepository = GetObjectRepository(); objectRepository->LoadOrConstruct(); + + IObjectManager * objectManager = GetObjectManager(); + objectManager->UnloadAll(); } bool object_load_entries(rct_object_entry * entries) From 50f3ba001e237b3a87f92e3116fa1d9fb0f018c8 Mon Sep 17 00:00:00 2001 From: LRFLEW Date: Sat, 9 Jul 2016 16:42:22 -0500 Subject: [PATCH 105/116] Update Xcode Project for #4024 --- OpenRCT2.xcodeproj/project.pbxproj | 138 +++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 6 deletions(-) diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 9d130b35e3..0b1f92a418 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -193,7 +193,6 @@ D44272341CC81B3200D84D28 /* network.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D44271521CC81B3200D84D28 /* network.cpp */; }; D44272351CC81B3200D84D28 /* twitch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D44271541CC81B3200D84D28 /* twitch.cpp */; }; D44272361CC81B3200D84D28 /* object_list.c in Sources */ = {isa = PBXBuildFile; fileRef = D44271561CC81B3200D84D28 /* object_list.c */; }; - D44272371CC81B3200D84D28 /* object.c in Sources */ = {isa = PBXBuildFile; fileRef = D44271571CC81B3200D84D28 /* object.c */; }; D44272381CC81B3200D84D28 /* openrct2.c in Sources */ = {isa = PBXBuildFile; fileRef = D44271591CC81B3200D84D28 /* openrct2.c */; }; D44272391CC81B3200D84D28 /* peep.c in Sources */ = {isa = PBXBuildFile; fileRef = D442715C1CC81B3200D84D28 /* peep.c */; }; D442723A1CC81B3200D84D28 /* staff.c in Sources */ = {isa = PBXBuildFile; fileRef = D442715E1CC81B3200D84D28 /* staff.c */; }; @@ -320,6 +319,27 @@ D45A395E1CF300AF00659A24 /* libSDL2.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B81CF3006400659A24 /* libSDL2.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; D45A395F1CF300AF00659A24 /* libspeexdsp.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B91CF3006400659A24 /* libspeexdsp.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; D45B202D1D1E92DB00B67CC7 /* custom_currency.c in Sources */ = {isa = PBXBuildFile; fileRef = D45B202C1D1E92DB00B67CC7 /* custom_currency.c */; }; + D464FEB91D31A64100CBABAC /* FileEnumerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEB71D31A64100CBABAC /* FileEnumerator.cpp */; }; + D464FEBB1D31A65300CBABAC /* IStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEBA1D31A65300CBABAC /* IStream.cpp */; }; + D464FEBE1D31A66E00CBABAC /* MemoryStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEBC1D31A66E00CBABAC /* MemoryStream.cpp */; }; + D464FEC01D31A68800CBABAC /* Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEBF1D31A68800CBABAC /* Image.cpp */; }; + D464FEE51D31A6AA00CBABAC /* BannerObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEC21D31A6AA00CBABAC /* BannerObject.cpp */; }; + D464FEE61D31A6AA00CBABAC /* EntranceObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEC41D31A6AA00CBABAC /* EntranceObject.cpp */; }; + D464FEE71D31A6AA00CBABAC /* FootpathItemObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEC61D31A6AA00CBABAC /* FootpathItemObject.cpp */; }; + D464FEE81D31A6AA00CBABAC /* FootpathObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEC81D31A6AA00CBABAC /* FootpathObject.cpp */; }; + D464FEE91D31A6AA00CBABAC /* ImageTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FECA1D31A6AA00CBABAC /* ImageTable.cpp */; }; + D464FEEA1D31A6AA00CBABAC /* LargeSceneryObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FECC1D31A6AA00CBABAC /* LargeSceneryObject.cpp */; }; + D464FEEB1D31A6AA00CBABAC /* Object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FECE1D31A6AA00CBABAC /* Object.cpp */; }; + D464FEEC1D31A6AA00CBABAC /* ObjectFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FED01D31A6AA00CBABAC /* ObjectFactory.cpp */; }; + D464FEED1D31A6AA00CBABAC /* ObjectManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FED21D31A6AA00CBABAC /* ObjectManager.cpp */; }; + D464FEEE1D31A6AA00CBABAC /* ObjectRepository.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FED41D31A6AA00CBABAC /* ObjectRepository.cpp */; }; + D464FEEF1D31A6AA00CBABAC /* RideObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FED61D31A6AA00CBABAC /* RideObject.cpp */; }; + D464FEF01D31A6AA00CBABAC /* SceneryGroupObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FED81D31A6AA00CBABAC /* SceneryGroupObject.cpp */; }; + D464FEF11D31A6AA00CBABAC /* SmallSceneryObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEDB1D31A6AA00CBABAC /* SmallSceneryObject.cpp */; }; + D464FEF21D31A6AA00CBABAC /* StexObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEDD1D31A6AA00CBABAC /* StexObject.cpp */; }; + D464FEF31D31A6AA00CBABAC /* StringTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEDF1D31A6AA00CBABAC /* StringTable.cpp */; }; + D464FEF41D31A6AA00CBABAC /* WallObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEE11D31A6AA00CBABAC /* WallObject.cpp */; }; + D464FEF51D31A6AA00CBABAC /* WaterObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D464FEE31D31A6AA00CBABAC /* WaterObject.cpp */; }; D47304D51C4FF8250015C0EA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D47304D41C4FF8250015C0EA /* libz.tbd */; }; D48A8D831D00272F00649DA7 /* TcpSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D48A8D811D00272F00649DA7 /* TcpSocket.cpp */; }; D49766831D03B9FE002222CD /* SoftwareDrawingEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D49766811D03B9FE002222CD /* SoftwareDrawingEngine.cpp */; }; @@ -527,7 +547,6 @@ D44270E61CC81B3200D84D28 /* FileStream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FileStream.hpp; sourceTree = ""; usesTabs = 0; }; D44270E71CC81B3200D84D28 /* Guard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Guard.cpp; sourceTree = ""; usesTabs = 0; }; D44270E81CC81B3200D84D28 /* Guard.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Guard.hpp; sourceTree = ""; usesTabs = 0; }; - D44270E91CC81B3200D84D28 /* IDisposable.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = IDisposable.hpp; sourceTree = ""; usesTabs = 0; }; D44270EA1CC81B3200D84D28 /* IStream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = IStream.hpp; sourceTree = ""; usesTabs = 0; }; D44270EB1CC81B3200D84D28 /* Json.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Json.cpp; sourceTree = ""; usesTabs = 0; }; D44270EC1CC81B3200D84D28 /* Json.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Json.hpp; sourceTree = ""; usesTabs = 0; }; @@ -629,7 +648,6 @@ D44271541CC81B3200D84D28 /* twitch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = twitch.cpp; sourceTree = ""; usesTabs = 0; }; D44271551CC81B3200D84D28 /* twitch.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = twitch.h; sourceTree = ""; usesTabs = 0; }; D44271561CC81B3200D84D28 /* object_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = object_list.c; sourceTree = ""; }; - D44271571CC81B3200D84D28 /* object.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = object.c; sourceTree = ""; }; D44271581CC81B3200D84D28 /* object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = object.h; sourceTree = ""; }; D44271591CC81B3200D84D28 /* openrct2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = openrct2.c; sourceTree = ""; }; D442715A1CC81B3200D84D28 /* openrct2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = openrct2.h; sourceTree = ""; }; @@ -935,6 +953,47 @@ D45A39571CF3007A00659A24 /* speexdsp_config_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speexdsp_config_types.h; sourceTree = ""; }; D45A39581CF3007A00659A24 /* speexdsp_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speexdsp_types.h; sourceTree = ""; }; D45B202C1D1E92DB00B67CC7 /* custom_currency.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = custom_currency.c; sourceTree = ""; }; + D464FEB71D31A64100CBABAC /* FileEnumerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileEnumerator.cpp; sourceTree = ""; }; + D464FEB81D31A64100CBABAC /* FileEnumerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileEnumerator.h; sourceTree = ""; }; + D464FEBA1D31A65300CBABAC /* IStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IStream.cpp; sourceTree = ""; }; + D464FEBC1D31A66E00CBABAC /* MemoryStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryStream.cpp; sourceTree = ""; }; + D464FEBD1D31A66E00CBABAC /* MemoryStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryStream.h; sourceTree = ""; }; + D464FEBF1D31A68800CBABAC /* Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Image.cpp; sourceTree = ""; }; + D464FEC21D31A6AA00CBABAC /* BannerObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BannerObject.cpp; sourceTree = ""; }; + D464FEC31D31A6AA00CBABAC /* BannerObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BannerObject.h; sourceTree = ""; }; + D464FEC41D31A6AA00CBABAC /* EntranceObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EntranceObject.cpp; sourceTree = ""; }; + D464FEC51D31A6AA00CBABAC /* EntranceObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EntranceObject.h; sourceTree = ""; }; + D464FEC61D31A6AA00CBABAC /* FootpathItemObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FootpathItemObject.cpp; sourceTree = ""; }; + D464FEC71D31A6AA00CBABAC /* FootpathItemObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FootpathItemObject.h; sourceTree = ""; }; + D464FEC81D31A6AA00CBABAC /* FootpathObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FootpathObject.cpp; sourceTree = ""; }; + D464FEC91D31A6AA00CBABAC /* FootpathObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FootpathObject.h; sourceTree = ""; }; + D464FECA1D31A6AA00CBABAC /* ImageTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageTable.cpp; sourceTree = ""; }; + D464FECB1D31A6AA00CBABAC /* ImageTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageTable.h; sourceTree = ""; }; + D464FECC1D31A6AA00CBABAC /* LargeSceneryObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LargeSceneryObject.cpp; sourceTree = ""; }; + D464FECD1D31A6AA00CBABAC /* LargeSceneryObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LargeSceneryObject.h; sourceTree = ""; }; + D464FECE1D31A6AA00CBABAC /* Object.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Object.cpp; sourceTree = ""; }; + D464FECF1D31A6AA00CBABAC /* Object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Object.h; sourceTree = ""; }; + D464FED01D31A6AA00CBABAC /* ObjectFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectFactory.cpp; sourceTree = ""; }; + D464FED11D31A6AA00CBABAC /* ObjectFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectFactory.h; sourceTree = ""; }; + D464FED21D31A6AA00CBABAC /* ObjectManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectManager.cpp; sourceTree = ""; }; + D464FED31D31A6AA00CBABAC /* ObjectManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectManager.h; sourceTree = ""; }; + D464FED41D31A6AA00CBABAC /* ObjectRepository.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectRepository.cpp; sourceTree = ""; }; + D464FED51D31A6AA00CBABAC /* ObjectRepository.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectRepository.h; sourceTree = ""; }; + D464FED61D31A6AA00CBABAC /* RideObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideObject.cpp; sourceTree = ""; }; + D464FED71D31A6AA00CBABAC /* RideObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideObject.h; sourceTree = ""; }; + D464FED81D31A6AA00CBABAC /* SceneryGroupObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SceneryGroupObject.cpp; sourceTree = ""; }; + D464FED91D31A6AA00CBABAC /* SceneryGroupObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneryGroupObject.h; sourceTree = ""; }; + D464FEDA1D31A6AA00CBABAC /* SceneryObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SceneryObject.h; sourceTree = ""; }; + D464FEDB1D31A6AA00CBABAC /* SmallSceneryObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SmallSceneryObject.cpp; sourceTree = ""; }; + D464FEDC1D31A6AA00CBABAC /* SmallSceneryObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SmallSceneryObject.h; sourceTree = ""; }; + D464FEDD1D31A6AA00CBABAC /* StexObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StexObject.cpp; sourceTree = ""; }; + D464FEDE1D31A6AA00CBABAC /* StexObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StexObject.h; sourceTree = ""; }; + D464FEDF1D31A6AA00CBABAC /* StringTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringTable.cpp; sourceTree = ""; }; + D464FEE01D31A6AA00CBABAC /* StringTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringTable.h; sourceTree = ""; }; + D464FEE11D31A6AA00CBABAC /* WallObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WallObject.cpp; sourceTree = ""; }; + D464FEE21D31A6AA00CBABAC /* WallObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WallObject.h; sourceTree = ""; }; + D464FEE31D31A6AA00CBABAC /* WaterObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WaterObject.cpp; sourceTree = ""; }; + D464FEE41D31A6AA00CBABAC /* WaterObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WaterObject.h; sourceTree = ""; }; D47304D41C4FF8250015C0EA /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; D4895D321C23EFDD000CD788 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = distribution/osx/Info.plist; sourceTree = SOURCE_ROOT; }; D48A8D811D00272F00649DA7 /* TcpSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TcpSocket.cpp; sourceTree = ""; usesTabs = 0; }; @@ -1166,6 +1225,7 @@ D44271321CC81B3200D84D28 /* localisation */, D44271441CC81B3200D84D28 /* management */, D442714F1CC81B3200D84D28 /* network */, + D464FEC11D31A6AA00CBABAC /* object */, C686F8961CDBC37E009F9BFC /* paint */, D442715B1CC81B3200D84D28 /* peep */, D44271601CC81B3200D84D28 /* platform */, @@ -1188,7 +1248,6 @@ D44271161CC81B3200D84D28 /* input.c */, D44271301CC81B3200D84D28 /* intro.c */, D44271561CC81B3200D84D28 /* object_list.c */, - D44271571CC81B3200D84D28 /* object.c */, D44271591CC81B3200D84D28 /* openrct2.c */, D44271691CC81B3200D84D28 /* rct1.c */, D442716B1CC81B3200D84D28 /* rct2.c */, @@ -1293,16 +1352,20 @@ D44270E31CC81B3200D84D28 /* Diagnostics.cpp */, D44270E41CC81B3200D84D28 /* Diagnostics.hpp */, D44270E51CC81B3200D84D28 /* Exception.hpp */, + D464FEB71D31A64100CBABAC /* FileEnumerator.cpp */, + D464FEB81D31A64100CBABAC /* FileEnumerator.h */, D44270E61CC81B3200D84D28 /* FileStream.hpp */, D44270E71CC81B3200D84D28 /* Guard.cpp */, D44270E81CC81B3200D84D28 /* Guard.hpp */, - D44270E91CC81B3200D84D28 /* IDisposable.hpp */, + D464FEBA1D31A65300CBABAC /* IStream.cpp */, D44270EA1CC81B3200D84D28 /* IStream.hpp */, D44270EB1CC81B3200D84D28 /* Json.cpp */, D44270EC1CC81B3200D84D28 /* Json.hpp */, D44270ED1CC81B3200D84D28 /* List.hpp */, D44270EE1CC81B3200D84D28 /* Math.hpp */, D44270EF1CC81B3200D84D28 /* Memory.hpp */, + D464FEBC1D31A66E00CBABAC /* MemoryStream.cpp */, + D464FEBD1D31A66E00CBABAC /* MemoryStream.h */, D44270F01CC81B3200D84D28 /* Path.cpp */, D44270F11CC81B3200D84D28 /* Path.hpp */, D44270F21CC81B3200D84D28 /* Stopwatch.cpp */, @@ -1330,6 +1393,7 @@ D44271051CC81B3200D84D28 /* font.h */, D497668A1D03BAC8002222CD /* IDrawingContext.h */, D497668B1D03BAC8002222CD /* IDrawingEngine.h */, + D464FEBF1D31A68800CBABAC /* Image.cpp */, D44271061CC81B3200D84D28 /* line.c */, D49766841D03BAA5002222CD /* NewDrawing.cpp */, D49766851D03BAA5002222CD /* NewDrawing.h */, @@ -1805,6 +1869,48 @@ path = speex; sourceTree = ""; }; + D464FEC11D31A6AA00CBABAC /* object */ = { + isa = PBXGroup; + children = ( + D464FEC21D31A6AA00CBABAC /* BannerObject.cpp */, + D464FEC31D31A6AA00CBABAC /* BannerObject.h */, + D464FEC41D31A6AA00CBABAC /* EntranceObject.cpp */, + D464FEC51D31A6AA00CBABAC /* EntranceObject.h */, + D464FEC61D31A6AA00CBABAC /* FootpathItemObject.cpp */, + D464FEC71D31A6AA00CBABAC /* FootpathItemObject.h */, + D464FEC81D31A6AA00CBABAC /* FootpathObject.cpp */, + D464FEC91D31A6AA00CBABAC /* FootpathObject.h */, + D464FECA1D31A6AA00CBABAC /* ImageTable.cpp */, + D464FECB1D31A6AA00CBABAC /* ImageTable.h */, + D464FECC1D31A6AA00CBABAC /* LargeSceneryObject.cpp */, + D464FECD1D31A6AA00CBABAC /* LargeSceneryObject.h */, + D464FECE1D31A6AA00CBABAC /* Object.cpp */, + D464FECF1D31A6AA00CBABAC /* Object.h */, + D464FED01D31A6AA00CBABAC /* ObjectFactory.cpp */, + D464FED11D31A6AA00CBABAC /* ObjectFactory.h */, + D464FED21D31A6AA00CBABAC /* ObjectManager.cpp */, + D464FED31D31A6AA00CBABAC /* ObjectManager.h */, + D464FED41D31A6AA00CBABAC /* ObjectRepository.cpp */, + D464FED51D31A6AA00CBABAC /* ObjectRepository.h */, + D464FED61D31A6AA00CBABAC /* RideObject.cpp */, + D464FED71D31A6AA00CBABAC /* RideObject.h */, + D464FED81D31A6AA00CBABAC /* SceneryGroupObject.cpp */, + D464FED91D31A6AA00CBABAC /* SceneryGroupObject.h */, + D464FEDA1D31A6AA00CBABAC /* SceneryObject.h */, + D464FEDB1D31A6AA00CBABAC /* SmallSceneryObject.cpp */, + D464FEDC1D31A6AA00CBABAC /* SmallSceneryObject.h */, + D464FEDD1D31A6AA00CBABAC /* StexObject.cpp */, + D464FEDE1D31A6AA00CBABAC /* StexObject.h */, + D464FEDF1D31A6AA00CBABAC /* StringTable.cpp */, + D464FEE01D31A6AA00CBABAC /* StringTable.h */, + D464FEE11D31A6AA00CBABAC /* WallObject.cpp */, + D464FEE21D31A6AA00CBABAC /* WallObject.h */, + D464FEE31D31A6AA00CBABAC /* WaterObject.cpp */, + D464FEE41D31A6AA00CBABAC /* WaterObject.h */, + ); + path = object; + sourceTree = ""; + }; D497667F1D03B9FE002222CD /* engines */ = { isa = PBXGroup; children = ( @@ -2063,6 +2169,8 @@ C686F9381CDBC3B7009F9BFC /* observation_tower.c in Sources */, D44272A41CC81B3200D84D28 /* park.c in Sources */, C686F9391CDBC3B7009F9BFC /* space_rings.c in Sources */, + D464FEEF1D31A6AA00CBABAC /* RideObject.cpp in Sources */, + D464FEEA1D31A6AA00CBABAC /* LargeSceneryObject.cpp in Sources */, C686F9371CDBC3B7009F9BFC /* monorail_cycles.c in Sources */, D49766891D03BABB002222CD /* rain.cpp in Sources */, D44272441CC81B3200D84D28 /* cable_lift.c in Sources */, @@ -2098,12 +2206,14 @@ C686F9341CDBC3B7009F9BFC /* merry_go_round.c in Sources */, C686F8B81CDBC37E009F9BFC /* sprite.c in Sources */, D45B202D1D1E92DB00B67CC7 /* custom_currency.c in Sources */, + D464FEEB1D31A6AA00CBABAC /* Object.cpp in Sources */, C686F9221CDBC3B7009F9BFC /* stand_up_roller_coaster.c in Sources */, C686F94F1CDBC3B7009F9BFC /* dingy_slide.c in Sources */, D44272341CC81B3200D84D28 /* network.cpp in Sources */, C686F9151CDBC3B7009F9BFC /* junior_roller_coaster.c in Sources */, C686F9131CDBC3B7009F9BFC /* inverted_impulse_coaster.c in Sources */, D44272001CC81B3200D84D28 /* Diagnostics.cpp in Sources */, + D464FEF11D31A6AA00CBABAC /* SmallSceneryObject.cpp in Sources */, D44272471CC81B3200D84D28 /* ride_ratings.c in Sources */, D44272721CC81B3200D84D28 /* new_campaign.c in Sources */, C686F93A1CDBC3B7009F9BFC /* spiral_slide.c in Sources */, @@ -2120,10 +2230,12 @@ C686F9461CDBC3B7009F9BFC /* swinging_inverter_ship.c in Sources */, D442720B1CC81B3200D84D28 /* font.c in Sources */, C686F90D1CDBC3B7009F9BFC /* compact_inverted_coaster.c in Sources */, + D464FEF31D31A6AA00CBABAC /* StringTable.cpp in Sources */, C686F8B01CDBC37E009F9BFC /* path.c in Sources */, D44272361CC81B3200D84D28 /* object_list.c in Sources */, D44272581CC81B3200D84D28 /* demolish_ride_prompt.c in Sources */, D442723E1CC81B3200D84D28 /* posix.c in Sources */, + D464FEB91D31A64100CBABAC /* FileEnumerator.cpp in Sources */, D44271F91CC81B3200D84D28 /* CommandLine.cpp in Sources */, 00EFEE721CF1D80B0035213B /* NetworkKey.cpp in Sources */, C686F90B1CDBC3B7009F9BFC /* air_powered_vertical_coaster.c in Sources */, @@ -2136,6 +2248,8 @@ D44272381CC81B3200D84D28 /* openrct2.c in Sources */, C686F92C1CDBC3B7009F9BFC /* circus_show.c in Sources */, D44271FD1CC81B3200D84D28 /* cmdline_sprite.c in Sources */, + D464FEEE1D31A6AA00CBABAC /* ObjectRepository.cpp in Sources */, + D464FEF51D31A6AA00CBABAC /* WaterObject.cpp in Sources */, D442720C1CC81B3200D84D28 /* line.c in Sources */, C686F9321CDBC3B7009F9BFC /* haunted_house.c in Sources */, D442720A1CC81B3200D84D28 /* drawing_fast.cpp in Sources */, @@ -2144,20 +2258,22 @@ C61FB7241CF86356004CE991 /* NetworkUser.cpp in Sources */, D44272191CC81B3200D84D28 /* colour.c in Sources */, D442724C1CC81B3200D84D28 /* vehicle.c in Sources */, + D464FEED1D31A6AA00CBABAC /* ObjectManager.cpp in Sources */, D44272261CC81B3200D84D28 /* currency.c in Sources */, C686F92B1CDBC3B7009F9BFC /* car_ride.c in Sources */, D44272921CC81B3200D84D28 /* tooltip.c in Sources */, C686F91C1CDBC3B7009F9BFC /* mini_suspended_coaster.c in Sources */, D44271FA1CC81B3200D84D28 /* RootCommands.cpp in Sources */, D442726B1CC81B3200D84D28 /* map.c in Sources */, + D464FEE71D31A6AA00CBABAC /* FootpathItemObject.cpp in Sources */, D442721E1CC81B3200D84D28 /* Theme.cpp in Sources */, C686F9271CDBC3B7009F9BFC /* virginia_reel.c in Sources */, D44272271CC81B3200D84D28 /* date.c in Sources */, - D44272371CC81B3200D84D28 /* object.c in Sources */, D44272971CC81B3200D84D28 /* viewport.c in Sources */, C686F90F1CDBC3B7009F9BFC /* flying_roller_coaster.c in Sources */, D44272661CC81B3200D84D28 /* install_track.c in Sources */, D49766831D03B9FE002222CD /* SoftwareDrawingEngine.cpp in Sources */, + D464FEF21D31A6AA00CBABAC /* StexObject.cpp in Sources */, C686F9331CDBC3B7009F9BFC /* maze.c in Sources */, C686F9241CDBC3B7009F9BFC /* suspended_swinging_coaster.c in Sources */, C686F92D1CDBC3B7009F9BFC /* crooked_house.c in Sources */, @@ -2166,6 +2282,7 @@ D442723A1CC81B3200D84D28 /* staff.c in Sources */, D44272931CC81B3200D84D28 /* top_toolbar.c in Sources */, D43407DA1D0E14BE00C2B3D4 /* FillRectShader.cpp in Sources */, + D464FEBE1D31A66E00CBABAC /* MemoryStream.cpp in Sources */, D44271F61CC81B3200D84D28 /* audio.c in Sources */, D442728A1CC81B3200D84D28 /* tile_inspector.c in Sources */, D43407D91D0E14BE00C2B3D4 /* DrawLineShader.cpp in Sources */, @@ -2230,11 +2347,14 @@ C686F9431CDBC3B7009F9BFC /* motion_simulator.c in Sources */, D44272281CC81B3200D84D28 /* language.cpp in Sources */, D442729B1CC81B3200D84D28 /* climate.c in Sources */, + D464FEC01D31A68800CBABAC /* Image.cpp in Sources */, C686F9261CDBC3B7009F9BFC /* vertical_drop_roller_coaster.c in Sources */, + D464FEE91D31A6AA00CBABAC /* ImageTable.cpp in Sources */, D442726F1CC81B3200D84D28 /* multiplayer.c in Sources */, 007A05D21CFB2C8B00F419C3 /* NetworkPlayer.cpp in Sources */, D442725B1CC81B3200D84D28 /* editor_inventions_list.c in Sources */, D44272311CC81B3200D84D28 /* news_item.c in Sources */, + D464FEF41D31A6AA00CBABAC /* WallObject.cpp in Sources */, D44272011CC81B3200D84D28 /* Guard.cpp in Sources */, D43407E01D0E14BE00C2B3D4 /* TextureCache.cpp in Sources */, D44272951CC81B3200D84D28 /* track_manage.c in Sources */, @@ -2255,6 +2375,7 @@ C686F8B11CDBC37E009F9BFC /* scenery.c in Sources */, C686F9251CDBC3B7009F9BFC /* twister_roller_coaster.c in Sources */, D44272251CC81B3200D84D28 /* convert.c in Sources */, + D464FEEC1D31A6AA00CBABAC /* ObjectFactory.cpp in Sources */, D442727B1CC81B3200D84D28 /* ride.c in Sources */, D44272031CC81B3200D84D28 /* Path.cpp in Sources */, C686F9301CDBC3B7009F9BFC /* flying_saucers.c in Sources */, @@ -2267,6 +2388,7 @@ 007A05D01CFB2C8B00F419C3 /* NetworkGroup.cpp in Sources */, C686F9491CDBC3B7009F9BFC /* chairlift.c in Sources */, C686F9501CDBC3B7009F9BFC /* log_flume.c in Sources */, + D464FEE81D31A6AA00CBABAC /* FootpathObject.cpp in Sources */, D43407D61D0E14BE00C2B3D4 /* CopyFramebufferShader.cpp in Sources */, D44272241CC81B3200D84D28 /* intro.c in Sources */, D44272631CC81B3200D84D28 /* game_bottom_toolbar.c in Sources */, @@ -2284,14 +2406,17 @@ D44272731CC81B3200D84D28 /* new_ride.c in Sources */, D442721A1CC81B3200D84D28 /* console.c in Sources */, D44271FB1CC81B3200D84D28 /* ScreenshotCommands.cpp in Sources */, + D464FEBB1D31A65300CBABAC /* IStream.cpp in Sources */, D442729E1CC81B3200D84D28 /* fountain.c in Sources */, C686F94B1CDBC3B7009F9BFC /* minature_railway.c in Sources */, C686F94D1CDBC3B7009F9BFC /* suspended_monorail.c in Sources */, D44272131CC81B3200D84D28 /* editor.c in Sources */, D442729F1CC81B3200D84D28 /* map.c in Sources */, + D464FEF01D31A6AA00CBABAC /* SceneryGroupObject.cpp in Sources */, C686F9351CDBC3B7009F9BFC /* mini_golf.c in Sources */, D44272541CC81B3200D84D28 /* banner.c in Sources */, D44272A31CC81B3200D84D28 /* money_effect.c in Sources */, + D464FEE61D31A6AA00CBABAC /* EntranceObject.cpp in Sources */, D43407DE1D0E14BE00C2B3D4 /* OpenGLShaderProgram.cpp in Sources */, D43407DC1D0E14BE00C2B3D4 /* OpenGLDrawingEngine.cpp in Sources */, D44272761CC81B3200D84D28 /* options.c in Sources */, @@ -2327,6 +2452,7 @@ C686F9361CDBC3B7009F9BFC /* mini_helicopters.c in Sources */, C686F93F1CDBC3B7009F9BFC /* enterprise.c in Sources */, C686F91B1CDBC3B7009F9BFC /* mini_roller_coaster.c in Sources */, + D464FEE51D31A6AA00CBABAC /* BannerObject.cpp in Sources */, D44272391CC81B3200D84D28 /* peep.c in Sources */, D44272681CC81B3200D84D28 /* land_rights.c in Sources */, D44272601CC81B3200D84D28 /* error.c in Sources */, From f7757c79913db490a21a85c1950a15c0c6d31a9a Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 9 Jul 2016 23:03:09 +0100 Subject: [PATCH 106/116] fix wall price check --- src/object/WallObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp index 5f960d2b75..11f19b4e77 100644 --- a/src/object/WallObject.cpp +++ b/src/object/WallObject.cpp @@ -48,7 +48,7 @@ void WallObject::ReadLegacy(IReadObjectContext * context, IStream * stream) GetImageTable()->Read(context, stream); // Validate properties - if (_legacyType.large_scenery.price <= 0) + if (_legacyType.wall.price <= 0) { context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Price can not be free or negative."); } From 324d690eaf11f72a04b552ec3f96f15702243a90 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 10 Jul 2016 00:00:23 +0100 Subject: [PATCH 107/116] fix unloading of null objects --- src/object/ObjectManager.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index 8db4fdf1f8..49eed6bdf9 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -157,10 +157,13 @@ public: if (ori != nullptr) { Object * loadedObject = ori->LoadedObject; - size_t index = GetLoadedObjectIndex(loadedObject); - - UnloadObject(loadedObject); - numObjectsUnloaded++; + if (loadedObject != nullptr) + { + size_t index = GetLoadedObjectIndex(loadedObject); + + UnloadObject(loadedObject); + numObjectsUnloaded++; + } } } From 66eee6d89de42cc2c0916852715f589680d381e2 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 10 Jul 2016 00:15:27 +0100 Subject: [PATCH 108/116] fix reading of large scenery objects --- src/object/LargeSceneryObject.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index 6007af165a..777c3b387b 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -42,10 +42,10 @@ void LargeSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre _legacyType.large_scenery.flags = stream->ReadValue(); _legacyType.large_scenery.price = stream->ReadValue(); _legacyType.large_scenery.removal_price = stream->ReadValue(); - stream->Seek(4, STREAM_SEEK_CURRENT); + stream->Seek(5, STREAM_SEEK_CURRENT); _legacyType.large_scenery.scenery_tab_id = 0xFF; _legacyType.large_scenery.var_11 = stream->ReadValue(); - stream->Seek(5, STREAM_SEEK_CURRENT); + stream->Seek(4, STREAM_SEEK_CURRENT); GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME); From 853e002b4ffa146b5898b8b58c1e83bd3c952702 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 10 Jul 2016 00:29:32 +0100 Subject: [PATCH 109/116] disable checksum validation --- src/object/ObjectRepository.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 22075de61b..f2915c34e8 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -195,15 +195,11 @@ public: utf8 objectName[9]; object_entry_get_name_fixed(objectName, sizeof(objectName), objectEntry); - int realChecksum = object_calculate_checksum(objectEntry, (const uint8 *)data, (int)dataSize); - if (realChecksum != objectEntry->checksum) - { - log_error("Checksum mismatch from packed object: %.8s", objectName); - if (!gConfigGeneral.allow_loading_with_incorrect_checksum) - { - return; - } - } + // Currently disable checksum validation + // int realChecksum = object_calculate_checksum(objectEntry, (const uint8 *)data, (int)dataSize); + // if (realChecksum != objectEntry->checksum) + // { + // } // TODO append checksum match bytes From 0a5ce82632dc42830de6e5f48869727fd218e243 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 10 Jul 2016 16:34:54 +0100 Subject: [PATCH 110/116] log warnings and information as verbose --- src/object/ObjectFactory.cpp | 2 +- src/object/ObjectManager.cpp | 4 ++-- src/object/ObjectRepository.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp index 83a292d2a5..080adb6bdc 100644 --- a/src/object/ObjectFactory.cpp +++ b/src/object/ObjectFactory.cpp @@ -68,7 +68,7 @@ public: if (!String::IsNullOrEmpty(text)) { - Console::Error::WriteLine("[%s] Warning: %s", _objectName, text); + log_verbose("[%s] Warning: %s", _objectName, text); } } diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index 49eed6bdf9..e162744130 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -138,7 +138,7 @@ public: UpdateLegacyLoadedObjectList(); UpdateSceneryGroupIndexes(); reset_type_to_ride_entry_index_map(); - // Console::WriteLine("%u / %u new objects loaded", numNewLoadedObjects, numRequiredObjects); + log_verbose("%u / %u new objects loaded", numNewLoadedObjects, numRequiredObjects); return true; } } @@ -320,7 +320,7 @@ private: } } - // Console::WriteLine("%u / %u objects unloaded", numObjectsUnloaded, totalObjectsLoaded); + log_verbose("%u / %u objects unloaded", numObjectsUnloaded, totalObjectsLoaded); } void UpdateLegacyLoadedObjectList() diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index f2915c34e8..c768a87a00 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -214,7 +214,7 @@ public: utf8 path[MAX_PATH]; GetPathForNewObject(path, sizeof(path), objectName); - Console::WriteLine("Adding object: [%s]", objectName); + log_verbose("Adding object: [%s]", objectName); try { SaveObject(path, objectEntry, data, dataSize); @@ -222,7 +222,7 @@ public: } catch (Exception ex) { - Console::WriteLine("Failed saving object: [%s] to '%s'.", objectName, path); + Console::Error::WriteLine("Failed saving object: [%s] to '%s'.", objectName, path); } } } From cf59929eaa1b7c1e214a5e56df7c29c385a13555 Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 11 Jul 2016 18:33:10 +0100 Subject: [PATCH 111/116] add extra salt bytes to exported objects if checksum is wrong --- src/object/ObjectRepository.cpp | 74 +++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index c768a87a00..4570bd11b5 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -195,14 +195,6 @@ public: utf8 objectName[9]; object_entry_get_name_fixed(objectName, sizeof(objectName), objectEntry); - // Currently disable checksum validation - // int realChecksum = object_calculate_checksum(objectEntry, (const uint8 *)data, (int)dataSize); - // if (realChecksum != objectEntry->checksum) - // { - // } - - // TODO append checksum match bytes - // Check that the object is loadable before writing it Object * object = ObjectFactory::CreateObjectFromLegacyData(objectEntry, data, dataSize); if (object == nullptr) @@ -506,6 +498,36 @@ private: uint8 * encodedDataBuffer = Memory::Allocate(0x600000); size_t encodedDataSize = sawyercoding_write_chunk_buffer(encodedDataBuffer, (uint8 *)data, chunkHeader); + void * extraBytes = nullptr; + size_t extraBytesCount = 0; + + int realChecksum = object_calculate_checksum(entry, data, dataSize); + if (realChecksum != entry->checksum) + { + char objectName[9]; + object_entry_get_name_fixed(objectName, sizeof(objectName), entry); + log_verbose("[%s] Incorrect checksum, adding salt bytes...", objectName); + + // Calculate the value of extra bytes that can be appended to the data so that the + // data is then valid for the object's checksum + extraBytes = CalculateExtraBytesToFixChecksum(realChecksum, entry->checksum, &extraBytesCount); +#ifdef DEBUG + { + // Check that CalculateExtraBytesToFixChecksum did the job + size_t newDataSize = dataSize + extraBytesCount; + void * newData = Memory::Allocate(newDataSize); + void * newDataSaltOffset = (void *)((uintptr_t)newData + dataSize); + Memory::Copy(newData, data, dataSize); + Memory::Copy(newDataSaltOffset, extraBytes, extraBytesCount); + + int actualChecksum = object_calculate_checksum(entry, newData, newDataSize); + Guard::Assert(actualChecksum == realChecksum, "CalculateExtraBytesToFixChecksum failed to fix checksum."); + + Memory::Free(newData); + } +#endif + } + // Save to file try { @@ -513,15 +535,51 @@ private: fs.Write(entry, sizeof(rct_object_entry)); fs.Write(encodedDataBuffer, encodedDataSize); + if (extraBytes != nullptr) + { + fs.Write(extraBytes, extraBytesCount); + } + + Memory::Free(extraBytes); Memory::Free(encodedDataBuffer); } catch (Exception ex) { + Memory::Free(extraBytes); Memory::Free(encodedDataBuffer); throw; } } + static void * CalculateExtraBytesToFixChecksum(int currentChecksum, int targetChecksum, size_t * outSize) + { + // Allocate 11 extra bytes to manipulate the checksum + uint8 * salt = Memory::Allocate(11); + if (outSize != nullptr) *outSize = 11; + + // Next work out which bits need to be flipped to make the current checksum match the one in the file + // The bitwise rotation compensates for the rotation performed during the checksum calculation*/ + int bitsToFlip = targetChecksum ^ ((currentChecksum << 25) | (currentChecksum >> 7)); + + // Each set bit encountered during encoding flips one bit of the resulting checksum (so each bit of the checksum is an + // XOR of bits from the file). Here, we take each bit that should be flipped in the checksum and set one of the bits in + // the data that maps to it. 11 bytes is the minimum needed to touch every bit of the checksum - with less than that, + // you wouldn't always be able to make the checksum come out to the desired target + salt[0] = (bitsToFlip & 0x00000001) << 7; + salt[1] = ((bitsToFlip & 0x00200000) >> 14); + salt[2] = ((bitsToFlip & 0x000007F8) >> 3); + salt[3] = ((bitsToFlip & 0xFF000000) >> 24); + salt[4] = ((bitsToFlip & 0x00100000) >> 13); + salt[5] = (bitsToFlip & 0x00000004) >> 2; + salt[6] = 0; + salt[7] = ((bitsToFlip & 0x000FF000) >> 12); + salt[8] = (bitsToFlip & 0x00000002) >> 1; + salt[9] = (bitsToFlip & 0x00C00000) >> 22; + salt[10] = (bitsToFlip & 0x00000800) >> 11; + + return salt; + } + static void GetPathForNewObject(utf8 * buffer, size_t bufferSize, const char * name) { char normalisedName[9] = { 0 }; From 81a597ab0d6c9c9bc834263bdbc07e9c144db0e1 Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 11 Jul 2016 19:09:16 +0100 Subject: [PATCH 112/116] append salt bytes inside encoded data chunk --- src/core/Guard.cpp | 13 +++++ src/core/Guard.hpp | 1 + src/object/ObjectRepository.cpp | 84 +++++++++++++++++++-------------- 3 files changed, 63 insertions(+), 35 deletions(-) diff --git a/src/core/Guard.cpp b/src/core/Guard.cpp index 73c7ef2301..f88d871846 100644 --- a/src/core/Guard.cpp +++ b/src/core/Guard.cpp @@ -32,6 +32,19 @@ namespace Guard Console::Error::WriteLine(message); } +#if DEBUG + Debug::Break(); +#endif + assert(false); + } + + void Fail(const char * message) + { + if (message != nullptr) + { + Console::Error::WriteLine(message); + } + #if DEBUG Debug::Break(); #endif diff --git a/src/core/Guard.hpp b/src/core/Guard.hpp index 904aaf6f99..c4ba8cdefa 100644 --- a/src/core/Guard.hpp +++ b/src/core/Guard.hpp @@ -22,6 +22,7 @@ namespace Guard { void Assert(bool expression, const char * message = nullptr); + void Fail(const char * message = nullptr); template void ArgumentNotNull(T * argument, const char * message = nullptr) diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 4570bd11b5..0a005b1b39 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -487,47 +487,68 @@ private: } } - static void SaveObject(const utf8 * path, const rct_object_entry * entry, const void * data, size_t dataSize) + static void SaveObject(const utf8 * path, + const rct_object_entry * entry, + const void * data, size_t dataSize, + bool fixChecksum = true) { - uint8 objectType = entry->flags & 0x0F; - - // Encode data - sawyercoding_chunk_header chunkHeader; - chunkHeader.encoding = object_entry_group_encoding[objectType]; - chunkHeader.length = dataSize; - uint8 * encodedDataBuffer = Memory::Allocate(0x600000); - size_t encodedDataSize = sawyercoding_write_chunk_buffer(encodedDataBuffer, (uint8 *)data, chunkHeader); - - void * extraBytes = nullptr; - size_t extraBytesCount = 0; - - int realChecksum = object_calculate_checksum(entry, data, dataSize); - if (realChecksum != entry->checksum) + if (fixChecksum) { - char objectName[9]; - object_entry_get_name_fixed(objectName, sizeof(objectName), entry); - log_verbose("[%s] Incorrect checksum, adding salt bytes...", objectName); - - // Calculate the value of extra bytes that can be appended to the data so that the - // data is then valid for the object's checksum - extraBytes = CalculateExtraBytesToFixChecksum(realChecksum, entry->checksum, &extraBytesCount); -#ifdef DEBUG + int realChecksum = object_calculate_checksum(entry, data, dataSize); + if (realChecksum != entry->checksum) { - // Check that CalculateExtraBytesToFixChecksum did the job + char objectName[9]; + object_entry_get_name_fixed(objectName, sizeof(objectName), entry); + log_verbose("[%s] Incorrect checksum, adding salt bytes...", objectName); + + // Calculate the value of extra bytes that can be appended to the data so that the + // data is then valid for the object's checksum + size_t extraBytesCount = 0; + void * extraBytes = CalculateExtraBytesToFixChecksum(realChecksum, entry->checksum, &extraBytesCount); + + // Create new data blob with appended bytes size_t newDataSize = dataSize + extraBytesCount; void * newData = Memory::Allocate(newDataSize); void * newDataSaltOffset = (void *)((uintptr_t)newData + dataSize); Memory::Copy(newData, data, dataSize); Memory::Copy(newDataSaltOffset, extraBytes, extraBytesCount); - int actualChecksum = object_calculate_checksum(entry, newData, newDataSize); - Guard::Assert(actualChecksum == realChecksum, "CalculateExtraBytesToFixChecksum failed to fix checksum."); + try + { + int newRealChecksum = object_calculate_checksum(entry, newData, newDataSize); + if (newRealChecksum != entry->checksum) + { + Guard::Fail("CalculateExtraBytesToFixChecksum failed to fix checksum."); - Memory::Free(newData); + // Save old data form + SaveObject(path, entry, data, dataSize, false); + } + else + { + // Save new data form + SaveObject(path, entry, newData, newDataSize, false); + } + Memory::Free(newData); + Memory::Free(extraBytes); + } + catch (Exception ex) + { + Memory::Free(newData); + Memory::Free(extraBytes); + throw; + } + return; } -#endif } + // Encode data + uint8 objectType = entry->flags & 0x0F; + sawyercoding_chunk_header chunkHeader; + chunkHeader.encoding = object_entry_group_encoding[objectType]; + chunkHeader.length = dataSize; + uint8 * encodedDataBuffer = Memory::Allocate(0x600000); + size_t encodedDataSize = sawyercoding_write_chunk_buffer(encodedDataBuffer, (uint8 *)data, chunkHeader); + // Save to file try { @@ -535,17 +556,10 @@ private: fs.Write(entry, sizeof(rct_object_entry)); fs.Write(encodedDataBuffer, encodedDataSize); - if (extraBytes != nullptr) - { - fs.Write(extraBytes, extraBytesCount); - } - - Memory::Free(extraBytes); Memory::Free(encodedDataBuffer); } catch (Exception ex) { - Memory::Free(extraBytes); Memory::Free(encodedDataBuffer); throw; } From 4bf9748143718504d0bcbc44d119b36ee28978d8 Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 11 Jul 2016 22:09:15 +0100 Subject: [PATCH 113/116] fix drawing of object preview We can't use dpi->width and dpi->height as they only define the clip region, not the viewport --- src/object/BannerObject.cpp | 6 +++--- src/object/BannerObject.h | 2 +- src/object/EntranceObject.cpp | 6 +++--- src/object/EntranceObject.h | 2 +- src/object/FootpathItemObject.cpp | 6 +++--- src/object/FootpathItemObject.h | 2 +- src/object/FootpathObject.cpp | 6 +++--- src/object/FootpathObject.h | 2 +- src/object/LargeSceneryObject.cpp | 6 +++--- src/object/LargeSceneryObject.h | 2 +- src/object/Object.h | 2 +- src/object/ObjectRepository.cpp | 4 ++-- src/object/ObjectRepository.h | 2 +- src/object/RideObject.cpp | 2 +- src/object/RideObject.h | 2 +- src/object/SceneryGroupObject.cpp | 6 +++--- src/object/SceneryGroupObject.h | 2 +- src/object/SmallSceneryObject.cpp | 8 ++++---- src/object/SmallSceneryObject.h | 2 +- src/object/StexObject.cpp | 6 +++--- src/object/StexObject.h | 2 +- src/object/WallObject.cpp | 6 +++--- src/object/WallObject.h | 2 +- src/object/WaterObject.cpp | 6 +++--- src/object/WaterObject.h | 2 +- src/windows/editor_inventions_list.c | 2 +- src/windows/editor_object_selection.c | 2 +- 27 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/object/BannerObject.cpp b/src/object/BannerObject.cpp index c86a74cd4a..b9d23f33a0 100644 --- a/src/object/BannerObject.cpp +++ b/src/object/BannerObject.cpp @@ -66,10 +66,10 @@ void BannerObject::Unload() _legacyType.image = 0; } -void BannerObject::DrawPreview(rct_drawpixelinfo * dpi) const +void BannerObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const { - int x = dpi->width / 2; - int y = dpi->height / 2; + sint32 x = width / 2; + sint32 y = height / 2; uint32 imageId = 0x20D00000 | _legacyType.image; gfx_draw_sprite(dpi, imageId + 0, x - 12, y + 8, 0); diff --git a/src/object/BannerObject.h b/src/object/BannerObject.h index fb20f37038..aebac64ae0 100644 --- a/src/object/BannerObject.h +++ b/src/object/BannerObject.h @@ -37,5 +37,5 @@ public: void Load() override; void Unload() override; - void DrawPreview(rct_drawpixelinfo * dpi) const override; + void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override; }; diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index 0469a3b0f1..b2a22e62c0 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -53,10 +53,10 @@ void EntranceObject::Unload() _legacyType.image_id = 0; } -void EntranceObject::DrawPreview(rct_drawpixelinfo * dpi) const +void EntranceObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const { - int x = dpi->width / 2; - int y = dpi->height / 2; + sint32 x = width / 2; + sint32 y = height / 2; uint32 imageId = _legacyType.image_id; gfx_draw_sprite(dpi, imageId + 1, x - 32, y + 14, 0); diff --git a/src/object/EntranceObject.h b/src/object/EntranceObject.h index 9da64b57f5..93e2d7763d 100644 --- a/src/object/EntranceObject.h +++ b/src/object/EntranceObject.h @@ -37,5 +37,5 @@ public: void Load() override; void Unload() override; - void DrawPreview(rct_drawpixelinfo * dpi) const override; + void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override; }; diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp index 80b0cc1cbc..e567e57284 100644 --- a/src/object/FootpathItemObject.cpp +++ b/src/object/FootpathItemObject.cpp @@ -68,9 +68,9 @@ void FootpathItemObject::Unload() _legacyType.image = 0; } -void FootpathItemObject::DrawPreview(rct_drawpixelinfo * dpi) const +void FootpathItemObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const { - int x = dpi->width / 2; - int y = dpi->height / 2; + sint32 x = width / 2; + sint32 y = height / 2; gfx_draw_sprite(dpi, _legacyType.image, x - 22, y - 24, 0); } diff --git a/src/object/FootpathItemObject.h b/src/object/FootpathItemObject.h index 5ce31cc233..889a309825 100644 --- a/src/object/FootpathItemObject.h +++ b/src/object/FootpathItemObject.h @@ -37,5 +37,5 @@ public: void Load() override; void Unload() override; - void DrawPreview(rct_drawpixelinfo * dpi) const override; + void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override; }; diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp index 8cc43bacbf..5e875cf5a7 100644 --- a/src/object/FootpathObject.cpp +++ b/src/object/FootpathObject.cpp @@ -63,10 +63,10 @@ void FootpathObject::Unload() _legacyType.image = 0; } -void FootpathObject::DrawPreview(rct_drawpixelinfo * dpi) const +void FootpathObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const { - int x = dpi->width / 2; - int y = dpi->height / 2; + sint32 x = width / 2; + sint32 y = height / 2; gfx_draw_sprite(dpi, _legacyType.image + 71, x - 49, y - 17, 0); gfx_draw_sprite(dpi, _legacyType.image + 72, x + 4, y - 17, 0); } diff --git a/src/object/FootpathObject.h b/src/object/FootpathObject.h index 7000c8776d..327a061538 100644 --- a/src/object/FootpathObject.h +++ b/src/object/FootpathObject.h @@ -37,5 +37,5 @@ public: void Load() override; void Unload() override; - void DrawPreview(rct_drawpixelinfo * dpi) const override; + void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override; }; diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index 777c3b387b..7af89b614b 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -110,10 +110,10 @@ void LargeSceneryObject::Unload() _legacyType.image = 0; } -void LargeSceneryObject::DrawPreview(rct_drawpixelinfo * dpi) const +void LargeSceneryObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const { - int x = dpi->width / 2; - int y = (dpi->height / 2) - 39; + sint32 x = width / 2; + sint32 y = (height / 2) - 39; uint32 imageId = 0xB2D00000 | _legacyType.image; gfx_draw_sprite(dpi, imageId, x, y, 0); diff --git a/src/object/LargeSceneryObject.h b/src/object/LargeSceneryObject.h index e4a86339c6..ebe3a4c3a9 100644 --- a/src/object/LargeSceneryObject.h +++ b/src/object/LargeSceneryObject.h @@ -41,7 +41,7 @@ public: void Load() override; void Unload() override; - void DrawPreview(rct_drawpixelinfo * dpi) const override; + void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override; private: static rct_large_scenery_tile * ReadTiles(IStream * stream); diff --git a/src/object/Object.h b/src/object/Object.h index b1e84eb377..96f78ad046 100644 --- a/src/object/Object.h +++ b/src/object/Object.h @@ -66,7 +66,7 @@ public: virtual void Load() abstract; virtual void Unload() abstract; - virtual void DrawPreview(rct_drawpixelinfo * dpi) const { } + virtual void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const { } virtual uint8 GetObjectType() const { return _objectEntry.flags & 0x0F; } virtual const utf8 * GetName() const; diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 0a005b1b39..46c84b5009 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -903,10 +903,10 @@ extern "C" } } - void object_draw_preview(const void * object, rct_drawpixelinfo * dpi) + void object_draw_preview(const void * object, rct_drawpixelinfo * dpi, sint32 width, sint32 height) { const Object * baseObject = (const Object *)object; - baseObject->DrawPreview(dpi); + baseObject->DrawPreview(dpi, width, height); } bool object_entry_compare(const rct_object_entry * a, const rct_object_entry * b) diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 6779471b2b..6aaa978e22 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -89,7 +89,7 @@ void * object_repository_load_object(const rct_object_e void object_delete(void * object); const utf8 * object_get_description(const void * object); -void object_draw_preview(const void * object, rct_drawpixelinfo * dpi); +void object_draw_preview(const void * object, rct_drawpixelinfo * dpi, sint32 width, sint32 height); #endif diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index 4d91204d03..b8d773eaa1 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -348,7 +348,7 @@ void RideObject::Unload() _legacyType.images_offset = 0; } -void RideObject::DrawPreview(rct_drawpixelinfo * dpi) const +void RideObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const { uint32 imageId = _legacyType.images_offset; if (_legacyType.ride_type[0] == 0xFF) diff --git a/src/object/RideObject.h b/src/object/RideObject.h index 40f229452d..0a152ea301 100644 --- a/src/object/RideObject.h +++ b/src/object/RideObject.h @@ -40,7 +40,7 @@ public: void Load() override; void Unload() override; - void DrawPreview(rct_drawpixelinfo * dpi) const override; + void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override; const utf8 * GetDescription() const; const utf8 * GetCapacity() const; diff --git a/src/object/SceneryGroupObject.cpp b/src/object/SceneryGroupObject.cpp index 45bc7bd6d8..7633805168 100644 --- a/src/object/SceneryGroupObject.cpp +++ b/src/object/SceneryGroupObject.cpp @@ -69,10 +69,10 @@ void SceneryGroupObject::Unload() _legacyType.image = 0; } -void SceneryGroupObject::DrawPreview(rct_drawpixelinfo * dpi) const +void SceneryGroupObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const { - int x = dpi->width / 2; - int y = dpi->height / 2; + sint32 x = width / 2; + sint32 y = height / 2; uint32 imageId = _legacyType.image + 0x20600001; gfx_draw_sprite(dpi, imageId, x - 15, y - 14, 0); diff --git a/src/object/SceneryGroupObject.h b/src/object/SceneryGroupObject.h index 93697ee0c7..03b0697a8a 100644 --- a/src/object/SceneryGroupObject.h +++ b/src/object/SceneryGroupObject.h @@ -43,7 +43,7 @@ public: void Unload() override; void UpdateEntryIndexes(); - void DrawPreview(rct_drawpixelinfo * dpi) const override; + void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override; void SetRepositoryItem(ObjectRepositoryItem * item) const override; diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index dcc45a748e..79d08c840d 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -99,7 +99,7 @@ void SmallSceneryObject::Unload() _legacyType.image = 0; } -void SmallSceneryObject::DrawPreview(rct_drawpixelinfo * dpi) const +void SmallSceneryObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const { uint32 flags = _legacyType.small_scenery.flags; uint32 imageId = _legacyType.image; @@ -112,9 +112,9 @@ void SmallSceneryObject::DrawPreview(rct_drawpixelinfo * dpi) const } } - int x = dpi->width / 2; - int y = (dpi->height / 2) + (_legacyType.small_scenery.height / 2); - y = Math::Min(y, dpi->height - 16); + sint32 x = width / 2; + sint32 y = (height / 2) + (_legacyType.small_scenery.height / 2); + y = Math::Min(y, height - 16); if ((flags & SMALL_SCENERY_FLAG_FULL_TILE) && (flags & SMALL_SCENERY_FLAG_VOFFSET_CENTRE)) diff --git a/src/object/SmallSceneryObject.h b/src/object/SmallSceneryObject.h index c44b9276c7..a7f77b5e8b 100644 --- a/src/object/SmallSceneryObject.h +++ b/src/object/SmallSceneryObject.h @@ -39,7 +39,7 @@ public: void Load() override; void Unload() override; - void DrawPreview(rct_drawpixelinfo * dpi) const override; + void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override; private: static uint8 * ReadVar10(IStream * stream); diff --git a/src/object/StexObject.cpp b/src/object/StexObject.cpp index 9b83b4515f..3abb215ed5 100644 --- a/src/object/StexObject.cpp +++ b/src/object/StexObject.cpp @@ -58,11 +58,11 @@ void StexObject::Unload() _legacyType.details = 0; } -void StexObject::DrawPreview(rct_drawpixelinfo * dpi) const +void StexObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const { // Write (no image) - int x = dpi->width / 2; - int y = dpi->height / 2; + sint32 x = width / 2; + sint32 y = height / 2; gfx_draw_string_centred(dpi, 3326, x, y, 0, nullptr); } diff --git a/src/object/StexObject.h b/src/object/StexObject.h index ba09077ebd..b922951b63 100644 --- a/src/object/StexObject.h +++ b/src/object/StexObject.h @@ -37,7 +37,7 @@ public: void Load() override; void Unload() override; - void DrawPreview(rct_drawpixelinfo * dpi) const override; + void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override; const utf8 * GetName() const override; diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp index 11f19b4e77..fc92db4b89 100644 --- a/src/object/WallObject.cpp +++ b/src/object/WallObject.cpp @@ -69,10 +69,10 @@ void WallObject::Unload() _legacyType.image = 0; } -void WallObject::DrawPreview(rct_drawpixelinfo * dpi) const +void WallObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const { - int x = dpi->width / 2; - int y = dpi->height / 2; + sint32 x = width / 2; + sint32 y = height / 2; x += 14; y += (_legacyType.wall.height * 2) + 16; diff --git a/src/object/WallObject.h b/src/object/WallObject.h index 7fcc26e1e0..3b3f44b95d 100644 --- a/src/object/WallObject.h +++ b/src/object/WallObject.h @@ -37,5 +37,5 @@ public: void Load() override; void Unload() override; - void DrawPreview(rct_drawpixelinfo * dpi) const override; + void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override; }; diff --git a/src/object/WaterObject.cpp b/src/object/WaterObject.cpp index 41e7e32d6d..da7d3e9dd6 100644 --- a/src/object/WaterObject.cpp +++ b/src/object/WaterObject.cpp @@ -57,10 +57,10 @@ void WaterObject::Unload() _legacyType.string_idx = 0; } -void WaterObject::DrawPreview(rct_drawpixelinfo * dpi) const +void WaterObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const { // Write (no image) - int x = dpi->width / 2; - int y = dpi->height / 2; + sint32 x = width / 2; + sint32 y = height / 2; gfx_draw_string_centred(dpi, 3326, x, y, 0, nullptr); } diff --git a/src/object/WaterObject.h b/src/object/WaterObject.h index 151daf42cc..1c946d0372 100644 --- a/src/object/WaterObject.h +++ b/src/object/WaterObject.h @@ -37,5 +37,5 @@ public: void Load() override; void Unload() override; - void DrawPreview(rct_drawpixelinfo * dpi) const override; + void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override; }; diff --git a/src/windows/editor_inventions_list.c b/src/windows/editor_inventions_list.c index 575b07e8c8..83faf6dda4 100644 --- a/src/windows/editor_inventions_list.c +++ b/src/windows/editor_inventions_list.c @@ -797,7 +797,7 @@ static void window_editor_inventions_list_paint(rct_window *w, rct_drawpixelinfo int width = widget->right - widget->left - 1; int height = widget->bottom - widget->top - 1; if (clip_drawpixelinfo(&clipDPI, dpi, x, y, width, height)) { - object_draw_preview(object, &clipDPI); + object_draw_preview(object, &clipDPI, width, height); } } diff --git a/src/windows/editor_object_selection.c b/src/windows/editor_object_selection.c index 65064ee936..497bfd375b 100644 --- a/src/windows/editor_object_selection.c +++ b/src/windows/editor_object_selection.c @@ -1322,7 +1322,7 @@ static void window_editor_object_selection_paint(rct_window *w, rct_drawpixelinf int width = widget->right - widget->left - 1; int height = widget->bottom - widget->top - 1; if (clip_drawpixelinfo(&clipDPI, dpi, x, y, width, height)) { - object_draw_preview(_loadedObject, &clipDPI); + object_draw_preview(_loadedObject, &clipDPI, width, height); } } From eb275604fa4416cb0adebc64569782eacdb3ba3d Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 11 Jul 2016 22:16:14 +0100 Subject: [PATCH 114/116] update changelog --- distribution/changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 3d0f127baf..08a630a481 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -16,6 +16,9 @@ - Feature: Add Cheat that allows any track piece to use a chain lift. - Feature: Add Console command to set vehicle friction. - Feature: Add console command to set scenario initial cash. +- Feature: Objects are scanned from the user directory as well as the RCT2 directory. +- Feature: Objects directory is scanned recursively. +- Improve: Performance and reliability of loading objects. - Removed: BMP screenshots. - Removed: Intamin and Phoenix easter eggs. - Fix: [#1038] Guest List is out of order. From edb4a4a8228fcf4c283de7760d9d536c1abde507 Mon Sep 17 00:00:00 2001 From: Ted John Date: Mon, 11 Jul 2016 22:50:55 +0100 Subject: [PATCH 115/116] fix get capacity string for vehicles --- src/object/BannerObject.cpp | 1 + src/object/EntranceObject.cpp | 1 + src/object/FootpathItemObject.cpp | 1 + src/object/FootpathObject.cpp | 1 + src/object/LargeSceneryObject.cpp | 1 + src/object/ObjectManager.cpp | 7 +++++++ src/object/ObjectManager.h | 1 + src/object/ObjectRepository.cpp | 14 ++++++++++++++ src/object/ObjectRepository.h | 1 + src/object/RideObject.cpp | 1 + src/object/SceneryGroupObject.cpp | 1 + src/object/SmallSceneryObject.cpp | 1 + src/object/StexObject.cpp | 1 + src/object/StringTable.h | 4 +--- src/object/WallObject.cpp | 1 + src/object/WaterObject.cpp | 1 + src/windows/ride.c | 13 ++++++++++--- 17 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/object/BannerObject.cpp b/src/object/BannerObject.cpp index b9d23f33a0..4daa3d3fc5 100644 --- a/src/object/BannerObject.cpp +++ b/src/object/BannerObject.cpp @@ -53,6 +53,7 @@ void BannerObject::ReadLegacy(IReadObjectContext * context, IStream * stream) void BannerObject::Load() { + GetStringTable()->Sort(); _legacyType.name = language_allocate_object_string(GetName()); _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); } diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp index b2a22e62c0..2d4656f9bd 100644 --- a/src/object/EntranceObject.cpp +++ b/src/object/EntranceObject.cpp @@ -40,6 +40,7 @@ void EntranceObject::ReadLegacy(IReadObjectContext * context, IStream * stream) void EntranceObject::Load() { + GetStringTable()->Sort(); _legacyType.string_idx = language_allocate_object_string(GetName()); _legacyType.image_id = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); } diff --git a/src/object/FootpathItemObject.cpp b/src/object/FootpathItemObject.cpp index e567e57284..7a24d7a6a1 100644 --- a/src/object/FootpathItemObject.cpp +++ b/src/object/FootpathItemObject.cpp @@ -53,6 +53,7 @@ void FootpathItemObject::ReadLegacy(IReadObjectContext * context, IStream * stre void FootpathItemObject::Load() { + GetStringTable()->Sort(); _legacyType.name = language_allocate_object_string(GetName()); _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); diff --git a/src/object/FootpathObject.cpp b/src/object/FootpathObject.cpp index 5e875cf5a7..b892d2612f 100644 --- a/src/object/FootpathObject.cpp +++ b/src/object/FootpathObject.cpp @@ -49,6 +49,7 @@ void FootpathObject::ReadLegacy(IReadObjectContext * context, IStream * stream) void FootpathObject::Load() { + GetStringTable()->Sort(); _legacyType.string_idx = language_allocate_object_string(GetName()); _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.bridge_image = _legacyType.image + 109; diff --git a/src/object/LargeSceneryObject.cpp b/src/object/LargeSceneryObject.cpp index 7af89b614b..47831c4e56 100644 --- a/src/object/LargeSceneryObject.cpp +++ b/src/object/LargeSceneryObject.cpp @@ -81,6 +81,7 @@ void LargeSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre void LargeSceneryObject::Load() { + GetStringTable()->Sort(); _legacyType.name = language_allocate_object_string(GetName()); _baseImageId = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.image = _baseImageId; diff --git a/src/object/ObjectManager.cpp b/src/object/ObjectManager.cpp index e162744130..70b18484a9 100644 --- a/src/object/ObjectManager.cpp +++ b/src/object/ObjectManager.cpp @@ -528,6 +528,13 @@ IObjectManager * GetObjectManager() extern "C" { + void * object_manager_get_loaded_object_by_index(size_t index) + { + IObjectManager * objectManager = GetObjectManager(); + Object * loadedObject = objectManager->GetLoadedObject(index); + return (void *)loadedObject; + } + void * object_manager_get_loaded_object(const rct_object_entry * entry) { IObjectManager * objectManager = GetObjectManager(); diff --git a/src/object/ObjectManager.h b/src/object/ObjectManager.h index efa219dba6..8dbeae0d86 100644 --- a/src/object/ObjectManager.h +++ b/src/object/ObjectManager.h @@ -51,6 +51,7 @@ IObjectManager * GetObjectManager(); #else +void * object_manager_get_loaded_object_by_index(size_t index); void * object_manager_get_loaded_object(const rct_object_entry * entry); uint8 object_manager_get_loaded_object_entry_index(const void * loadedObject); void * object_manager_load_object(const rct_object_entry * entry); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index 46c84b5009..1aff117211 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -903,6 +903,20 @@ extern "C" } } + const utf8 * object_get_capacity(const void * object) + { + const Object * baseObject = (const Object *)object; + switch (baseObject->GetObjectType()) { + case OBJECT_TYPE_RIDE: + { + auto rideObject = static_cast(baseObject); + return rideObject->GetCapacity(); + } + default: + return ""; + } + } + void object_draw_preview(const void * object, rct_drawpixelinfo * dpi, sint32 width, sint32 height) { const Object * baseObject = (const Object *)object; diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index 6aaa978e22..8f8eaf216e 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -89,6 +89,7 @@ void * object_repository_load_object(const rct_object_e void object_delete(void * object); const utf8 * object_get_description(const void * object); +const utf8 * object_get_capacity(const void * object); void object_draw_preview(const void * object, rct_drawpixelinfo * dpi, sint32 width, sint32 height); #endif diff --git a/src/object/RideObject.cpp b/src/object/RideObject.cpp index b8d773eaa1..ca6d6d9756 100644 --- a/src/object/RideObject.cpp +++ b/src/object/RideObject.cpp @@ -129,6 +129,7 @@ void RideObject::ReadLegacy(IReadObjectContext * context, IStream * stream) void RideObject::Load() { + GetStringTable()->Sort(); _legacyType.name = language_allocate_object_string(GetName()); _legacyType.description = language_allocate_object_string(GetDescription()); _legacyType.images_offset = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); diff --git a/src/object/SceneryGroupObject.cpp b/src/object/SceneryGroupObject.cpp index 7633805168..a0120220dc 100644 --- a/src/object/SceneryGroupObject.cpp +++ b/src/object/SceneryGroupObject.cpp @@ -55,6 +55,7 @@ void SceneryGroupObject::ReadLegacy(IReadObjectContext * context, IStream * stre void SceneryGroupObject::Load() { + GetStringTable()->Sort(); _legacyType.name = language_allocate_object_string(GetName()); _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.entry_count = 0; diff --git a/src/object/SmallSceneryObject.cpp b/src/object/SmallSceneryObject.cpp index 79d08c840d..f89b8d23a4 100644 --- a/src/object/SmallSceneryObject.cpp +++ b/src/object/SmallSceneryObject.cpp @@ -79,6 +79,7 @@ void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre void SmallSceneryObject::Load() { + GetStringTable()->Sort(); _legacyType.name = language_allocate_object_string(GetName()); _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); diff --git a/src/object/StexObject.cpp b/src/object/StexObject.cpp index 3abb215ed5..93e7471290 100644 --- a/src/object/StexObject.cpp +++ b/src/object/StexObject.cpp @@ -42,6 +42,7 @@ void StexObject::ReadLegacy(IReadObjectContext * context, IStream * stream) void StexObject::Load() { + GetStringTable()->Sort(); _legacyType.scenario_name = language_allocate_object_string(GetScenarioName()); _legacyType.park_name = language_allocate_object_string(GetParkName()); _legacyType.details = language_allocate_object_string(GetScenarioDetails()); diff --git a/src/object/StringTable.h b/src/object/StringTable.h index 38895a4c2e..8c336a8bce 100644 --- a/src/object/StringTable.h +++ b/src/object/StringTable.h @@ -38,8 +38,6 @@ public: ~StringTable(); void Read(IReadObjectContext * context, IStream * stream, uint8 id); + void Sort(); const utf8 * GetString(uint8 id) const; - -private: - void Sort(); }; \ No newline at end of file diff --git a/src/object/WallObject.cpp b/src/object/WallObject.cpp index fc92db4b89..93c5eee0bd 100644 --- a/src/object/WallObject.cpp +++ b/src/object/WallObject.cpp @@ -56,6 +56,7 @@ void WallObject::ReadLegacy(IReadObjectContext * context, IStream * stream) void WallObject::Load() { + GetStringTable()->Sort(); _legacyType.name = language_allocate_object_string(GetName()); _legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); } diff --git a/src/object/WaterObject.cpp b/src/object/WaterObject.cpp index da7d3e9dd6..cf2ee24a3c 100644 --- a/src/object/WaterObject.cpp +++ b/src/object/WaterObject.cpp @@ -41,6 +41,7 @@ void WaterObject::ReadLegacy(IReadObjectContext * context, IStream * stream) void WaterObject::Load() { + GetStringTable()->Sort(); _legacyType.string_idx = language_allocate_object_string(GetName()); _legacyType.image_id = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount()); _legacyType.var_06 = _legacyType.image_id + 1; diff --git a/src/windows/ride.c b/src/windows/ride.c index e0803f78e2..1a8e5b3112 100644 --- a/src/windows/ride.c +++ b/src/windows/ride.c @@ -26,6 +26,8 @@ #include "../interface/window.h" #include "../localisation/date.h" #include "../localisation/localisation.h" +#include "../object/ObjectManager.h" +#include "../object/ObjectRepository.h" #include "../peep/staff.h" #include "../ride/ride.h" #include "../ride/ride_data.h" @@ -2590,7 +2592,6 @@ static void window_ride_vehicle_paint(rct_window *w, rct_drawpixelinfo *dpi) { rct_ride *ride; rct_ride_entry *rideEntry; - rct_string_id stringId; int x, y; sint16 factor; @@ -2608,8 +2609,14 @@ static void window_ride_vehicle_paint(rct_window *w, rct_drawpixelinfo *dpi) y += 5; // Capacity - stringId = rideEntry->description + 1; - gfx_draw_string_left(dpi, STR_CAPACITY, &stringId, 0, x, y); + void * loadedObject = object_manager_get_loaded_object_by_index(ride->subtype); + if (loadedObject != NULL) + { + const utf8 * capacity = object_get_capacity(loadedObject); + set_format_arg(0, rct_string_id, STR_STRING); + set_format_arg(2, utf8 *, capacity); + gfx_draw_string_left(dpi, STR_CAPACITY, gCommonFormatArgs, 0, x, y); + } y += 15; if ((!(rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(rideEntry)) && var_496(w) > 1) { From ef09dcd64ac36c6e2e98c8a83d898d2e46603ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Mon, 11 Jul 2016 23:52:43 +0200 Subject: [PATCH 116/116] Add another assert to decode_chunk_rle_with_size --- src/util/sawyercoding.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/sawyercoding.c b/src/util/sawyercoding.c index 2e9dbebd05..8f43c1f410 100644 --- a/src/util/sawyercoding.c +++ b/src/util/sawyercoding.c @@ -395,6 +395,7 @@ static size_t decode_chunk_rle_with_size(const uint8* src_buffer, uint8* dst_buf if (rleCodeByte & 128) { i++; count = 257 - rleCodeByte; + assert(dst + count <= dst_buffer + dstSize); memset(dst, src_buffer[i], count); dst = (uint8*)((uintptr_t)dst + count); } else {