Feature #11817: Show authors field in object selection (#12591)

* Feature #11817: Show authors field in object selection

- authors field in JSON shows as last line in bottom right on object selection
- authors field added to Object class
- ObjectFileIndex version bump as authors is serialised

* fix sign comparison warning

* Start object selection corner text higher to avoid overlap

* Use references to reduce unneccessary copies

* make GetAuthors const

* Clip drawing of authors string so it doesn't cross widgets

At max length the leftmost aligns exactly with description left

* Add a changelog message

* make SetAuthors use an rvalue reference

* remove unnecessary nullptr check
This commit is contained in:
Tom Parsons 2020-08-09 06:23:28 +01:00 committed by GitHub
parent 5f68927e88
commit c4ae579a84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 83 additions and 9 deletions

View File

@ -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).

View File

@ -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<rct_string_id>(STR_STRING);
ft.Add<const char*>(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<rct_string_id>(STR_STRING);
ft.Add<const char*>(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<rct_string_id>(STR_STRING);
ft.Add<const char*>(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

View File

@ -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<std::string>& Object::GetAuthors() const
{
return _authors;
}
void Object::SetAuthors(const std::vector<std::string>&& authors)
{
_authors = authors;
}
std::optional<uint8_t> rct_object_entry::GetSceneryType() const
{
switch (GetType())

View File

@ -169,6 +169,7 @@ private:
StringTable _stringTable;
ImageTable _imageTable;
std::vector<uint8_t> _sourceGames;
std::vector<std::string> _authors;
bool _isJsonObject{};
protected:
@ -247,6 +248,9 @@ public:
std::vector<uint8_t> GetSourceGames();
void SetSourceGames(const std::vector<uint8_t>& sourceGames);
const std::vector<std::string>& GetAuthors() const;
void SetAuthors(const std::vector<std::string>&& authors);
const ImageTable& GetImageTable() const
{
return _imageTable;

View File

@ -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<std::string> 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))
{

View File

@ -74,7 +74,7 @@ class ObjectFileIndex final : public FileIndex<ObjectRepositoryItem>
{
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<uint8_t>(item.Sources.size());
stream->WriteValue(sourceLength);
for (auto source : item.Sources)
@ -135,6 +137,13 @@ protected:
stream->WriteValue(source);
}
uint8_t authorsLength = static_cast<uint8_t>(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<rct_object_entry>();
item.Path = stream->ReadStdString();
item.Name = stream->ReadStdString();
auto sourceLength = stream->ReadValue<uint8_t>();
for (size_t i = 0; i < sourceLength; i++)
{
@ -172,6 +182,13 @@ protected:
item.Sources.push_back(value);
}
auto authorsLength = stream->ReadValue<uint8_t>();
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:

View File

@ -40,6 +40,7 @@ struct ObjectRepositoryItem
rct_object_entry ObjectEntry;
std::string Path;
std::string Name;
std::vector<std::string> Authors;
std::vector<uint8_t> Sources;
Object* LoadedObject{};
struct