diff --git a/distribution/changelog.txt b/distribution/changelog.txt index b2a8d244bd..9733abaf49 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -14,6 +14,7 @@ - Feature: [#11959] Hacked go-kart tracks can now use 2x2 bends, 3x3 bends and S-bends. - Feature: [#12090] Boosters for the Wooden Roller Coaster (if the "Show all track pieces" cheat is enabled). - Feature: [#12184] .sea (RCT Classic) scenario files can now be imported. +- Feature: [#12591] Show authors of an object on the object selection dialog. - Change: [#11209] Warn when user is running OpenRCT2 through Wine. - Change: [#11358] Switch copy and paste button positions in tile inspector. - Change: [#11449] Remove complete circuit requirement from Air Powered Vertical Coaster (for RCT1 parity). diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index ffddc9c5bd..8f0e0ef9cc 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -1083,7 +1083,7 @@ static void window_editor_object_selection_paint(rct_window* w, rct_drawpixelinf dpi, gCommonFormatArgs, screenPos + ScreenCoordsXY{ 0, 5 }, width, STR_WINDOW_COLOUR_2_STRINGID, COLOUR_BLACK); } - auto screenPos = w->windowPos + ScreenCoordsXY{ w->width - 5, w->height - (LIST_ROW_HEIGHT * 4) }; + auto screenPos = w->windowPos + ScreenCoordsXY{ w->width - 5, w->height - (LIST_ROW_HEIGHT * 5) }; // Draw ride type. if (get_selected_object_type(w) == OBJECT_TYPE_RIDE) @@ -1100,14 +1100,35 @@ static void window_editor_object_selection_paint(rct_window* w, rct_drawpixelinf screenPos.y += LIST_ROW_HEIGHT; // Draw object dat name - const char* path = path_get_filename(listItem->repositoryItem->Path.c_str()); - auto ft = Formatter::Common(); - ft.Add(STR_STRING); - ft.Add(path); - gfx_draw_string_right( - dpi, STR_WINDOW_COLOUR_2_STRINGID, gCommonFormatArgs, COLOUR_BLACK, { w->windowPos.x + w->width - 5, screenPos.y }); -} + { + const char* path = path_get_filename(listItem->repositoryItem->Path.c_str()); + auto ft = Formatter::Common(); + ft.Add(STR_STRING); + ft.Add(path); + gfx_draw_string_right( + dpi, STR_WINDOW_COLOUR_2_STRINGID, gCommonFormatArgs, COLOUR_BLACK, { w->windowPos.x + w->width - 5, screenPos.y }); + screenPos.y += LIST_ROW_HEIGHT; + } + // Draw object author (will be blank space if no author in file or a non JSON object) + { + auto ft = Formatter::Common(); + std::string authorsString; + for (size_t i = 0; i < listItem->repositoryItem->Authors.size(); i++) + { + if (i > 0) + { + authorsString.append(", "); + } + authorsString.append(listItem->repositoryItem->Authors[i]); + } + ft.Add(STR_STRING); + ft.Add(authorsString.c_str()); + gfx_draw_string_right_clipped( + dpi, STR_WINDOW_COLOUR_2_STRINGID, gCommonFormatArgs, COLOUR_BLACK, { w->windowPos.x + w->width - 5, screenPos.y }, + w->width - w->widgets[WIDX_LIST].right - 4); + } +} /** * * rct2: 0x006AADA3 diff --git a/src/openrct2/object/Object.cpp b/src/openrct2/object/Object.cpp index c4308840f3..15b12c6b16 100644 --- a/src/openrct2/object/Object.cpp +++ b/src/openrct2/object/Object.cpp @@ -116,6 +116,16 @@ void rct_object_entry::SetName(const std::string_view& value) std::memcpy(name, value.data(), std::min(sizeof(name), value.size())); } +const std::vector& Object::GetAuthors() const +{ + return _authors; +} + +void Object::SetAuthors(const std::vector&& authors) +{ + _authors = authors; +} + std::optional rct_object_entry::GetSceneryType() const { switch (GetType()) diff --git a/src/openrct2/object/Object.h b/src/openrct2/object/Object.h index 7e7454f5db..714d72f0d6 100644 --- a/src/openrct2/object/Object.h +++ b/src/openrct2/object/Object.h @@ -169,6 +169,7 @@ private: StringTable _stringTable; ImageTable _imageTable; std::vector _sourceGames; + std::vector _authors; bool _isJsonObject{}; protected: @@ -247,6 +248,9 @@ public: std::vector GetSourceGames(); void SetSourceGames(const std::vector& sourceGames); + const std::vector& GetAuthors() const; + void SetAuthors(const std::vector&& authors); + const ImageTable& GetImageTable() const { return _imageTable; diff --git a/src/openrct2/object/ObjectFactory.cpp b/src/openrct2/object/ObjectFactory.cpp index 9e46319ad5..91cb63042b 100644 --- a/src/openrct2/object/ObjectFactory.cpp +++ b/src/openrct2/object/ObjectFactory.cpp @@ -442,6 +442,26 @@ namespace ObjectFactory { throw std::runtime_error("Object has errors"); } + + auto authors = json_object_get(jRoot, "authors"); + if (json_is_array(authors)) + { + std::vector authorVector; + for (size_t j = 0; j < json_array_size(authors); j++) + { + json_t* tryString = json_array_get(authors, j); + if (json_is_string(tryString)) + { + authorVector.emplace_back(json_string_value(tryString)); + } + } + result->SetAuthors(std::move(authorVector)); + } + else if (json_is_string(authors)) + { + result->SetAuthors({ json_string_value(authors) }); + } + auto sourceGames = json_object_get(jRoot, "sourceGame"); if (json_is_array(sourceGames)) { diff --git a/src/openrct2/object/ObjectRepository.cpp b/src/openrct2/object/ObjectRepository.cpp index 58ae87b7ab..32a729e407 100644 --- a/src/openrct2/object/ObjectRepository.cpp +++ b/src/openrct2/object/ObjectRepository.cpp @@ -74,7 +74,7 @@ class ObjectFileIndex final : public FileIndex { private: static constexpr uint32_t MAGIC_NUMBER = 0x5844494F; // OIDX - static constexpr uint16_t VERSION = 20; + static constexpr uint16_t VERSION = 21; static constexpr auto PATTERN = "*.dat;*.pob;*.json;*.parkobj"; IObjectRepository& _objectRepository; @@ -114,6 +114,7 @@ public: item.ObjectEntry = *object->GetObjectEntry(); item.Path = path; item.Name = object->GetName(); + item.Authors = object->GetAuthors(); item.Sources = object->GetSourceGames(); object->SetRepositoryItem(&item); delete object; @@ -128,6 +129,7 @@ protected: stream->WriteValue(item.ObjectEntry); stream->WriteString(item.Path); stream->WriteString(item.Name); + uint8_t sourceLength = static_cast(item.Sources.size()); stream->WriteValue(sourceLength); for (auto source : item.Sources) @@ -135,6 +137,13 @@ protected: stream->WriteValue(source); } + uint8_t authorsLength = static_cast(item.Authors.size()); + stream->WriteValue(authorsLength); + for (const auto& author : item.Authors) + { + stream->WriteString(author); + } + switch (item.ObjectEntry.GetType()) { case OBJECT_TYPE_RIDE: @@ -165,6 +174,7 @@ protected: item.ObjectEntry = stream->ReadValue(); item.Path = stream->ReadStdString(); item.Name = stream->ReadStdString(); + auto sourceLength = stream->ReadValue(); for (size_t i = 0; i < sourceLength; i++) { @@ -172,6 +182,13 @@ protected: item.Sources.push_back(value); } + auto authorsLength = stream->ReadValue(); + for (size_t i = 0; i < authorsLength; i++) + { + auto author = stream->ReadStdString(); + item.Authors.emplace_back(author); + } + switch (item.ObjectEntry.GetType()) { case OBJECT_TYPE_RIDE: diff --git a/src/openrct2/object/ObjectRepository.h b/src/openrct2/object/ObjectRepository.h index 3995e37f1a..f165344f48 100644 --- a/src/openrct2/object/ObjectRepository.h +++ b/src/openrct2/object/ObjectRepository.h @@ -40,6 +40,7 @@ struct ObjectRepositoryItem rct_object_entry ObjectEntry; std::string Path; std::string Name; + std::vector Authors; std::vector Sources; Object* LoadedObject{}; struct