2017-06-06 15:34:30 +02:00
|
|
|
/*****************************************************************************
|
2018-06-15 14:07:34 +02:00
|
|
|
* Copyright (c) 2014-2018 OpenRCT2 developers
|
2017-06-06 15:34:30 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* For a complete list of all authors, please refer to contributors.md
|
|
|
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
2017-06-06 15:34:30 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
2017-06-06 15:34:30 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2018-01-19 13:46:13 +01:00
|
|
|
#include <openrct2-ui/interface/Widget.h>
|
|
|
|
#include <openrct2-ui/windows/Window.h>
|
2019-02-02 18:49:34 +01:00
|
|
|
#include <openrct2/Context.h>
|
|
|
|
#include <openrct2/core/Json.hpp>
|
|
|
|
#include <openrct2/core/String.hpp>
|
2018-06-22 23:21:44 +02:00
|
|
|
#include <openrct2/localisation/Localisation.h>
|
2019-02-02 18:49:34 +01:00
|
|
|
#include <openrct2/network/Http.h>
|
2018-02-08 20:34:05 +01:00
|
|
|
#include <openrct2/object/ObjectList.h>
|
2018-06-22 23:21:44 +02:00
|
|
|
#include <openrct2/object/ObjectManager.h>
|
2019-02-02 18:49:34 +01:00
|
|
|
#include <openrct2/object/ObjectRepository.h>
|
2018-06-22 23:21:44 +02:00
|
|
|
#include <openrct2/platform/platform.h>
|
2019-02-03 23:42:25 +01:00
|
|
|
#include <openrct2/windows/Intent.h>
|
2018-06-22 23:21:44 +02:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2017-06-06 15:34:30 +02:00
|
|
|
|
2019-02-03 23:42:25 +01:00
|
|
|
static constexpr auto OPENRCT2_API_LEGACY_OBJECT_URL = "https://api.openrct2.io/objects/legacy/";
|
|
|
|
|
2018-05-16 20:41:29 +02:00
|
|
|
// clang-format off
|
2017-06-06 15:34:30 +02:00
|
|
|
enum WINDOW_OBJECT_LOAD_ERROR_WIDGET_IDX {
|
|
|
|
WIDX_BACKGROUND,
|
|
|
|
WIDX_TITLE,
|
|
|
|
WIDX_CLOSE,
|
|
|
|
WIDX_COLUMN_OBJECT_NAME,
|
2017-07-19 11:04:00 +02:00
|
|
|
WIDX_COLUMN_OBJECT_SOURCE,
|
2017-06-06 15:34:30 +02:00
|
|
|
WIDX_COLUMN_OBJECT_TYPE,
|
|
|
|
WIDX_SCROLL,
|
|
|
|
WIDX_COPY_CURRENT,
|
2019-02-02 18:49:34 +01:00
|
|
|
WIDX_COPY_ALL,
|
|
|
|
WIDX_DOWNLOAD_ALL
|
2017-06-06 15:34:30 +02:00
|
|
|
};
|
|
|
|
|
2017-07-19 11:04:00 +02:00
|
|
|
#define WW 450
|
2017-06-06 15:34:30 +02:00
|
|
|
#define WH 400
|
2017-07-19 11:04:00 +02:00
|
|
|
#define WW_LESS_PADDING (WW - 5)
|
|
|
|
#define NAME_COL_LEFT 4
|
|
|
|
#define SOURCE_COL_LEFT ((WW_LESS_PADDING / 4) + 1)
|
|
|
|
#define TYPE_COL_LEFT (5 * WW_LESS_PADDING / 8 + 1)
|
2017-06-06 15:34:30 +02:00
|
|
|
#define LIST_ITEM_HEIGHT 10
|
|
|
|
|
2017-09-06 20:53:30 +02:00
|
|
|
static rct_widget window_object_load_error_widgets[] = {
|
2017-07-19 11:04:00 +02:00
|
|
|
{ WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE }, // Background
|
|
|
|
{ WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_OBJECT_LOAD_ERROR_TITLE, STR_WINDOW_TITLE_TIP }, // Title bar
|
|
|
|
{ WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // Close button
|
2018-04-16 20:27:30 +02:00
|
|
|
{ WWT_TABLE_HEADER, 0, NAME_COL_LEFT, SOURCE_COL_LEFT - 1, 57, 70, STR_OBJECT_NAME, STR_NONE }, // 'Object name' header
|
|
|
|
{ WWT_TABLE_HEADER, 0, SOURCE_COL_LEFT, TYPE_COL_LEFT - 1, 57, 70, STR_OBJECT_SOURCE, STR_NONE }, // 'Object source' header
|
|
|
|
{ WWT_TABLE_HEADER, 0, TYPE_COL_LEFT, WW_LESS_PADDING - 1, 57, 70, STR_OBJECT_TYPE, STR_NONE }, // 'Object type' header
|
|
|
|
{ WWT_SCROLL, 0, 4, WW_LESS_PADDING, 70, WH - 33, SCROLL_VERTICAL, STR_NONE }, // Scrollable list area
|
2019-02-02 18:49:34 +01:00
|
|
|
{ WWT_BUTTON, 0, 4, 148, WH - 23, WH - 10, STR_COPY_SELECTED, STR_NONE }, // Copy selected btn
|
|
|
|
{ WWT_BUTTON, 0, 152, 296, WH - 23, WH - 10, STR_COPY_ALL, STR_NONE }, // Copy all btn
|
|
|
|
{ WWT_BUTTON, 0, 300, WW_LESS_PADDING, WH - 23, WH - 10, STR_DOWNLOAD_ALL, STR_NONE }, // Download all
|
2017-06-06 15:34:30 +02:00
|
|
|
{ WIDGETS_END },
|
|
|
|
};
|
|
|
|
|
|
|
|
static rct_string_id get_object_type_string(const rct_object_entry *entry);
|
|
|
|
static void window_object_load_error_close(rct_window *w);
|
|
|
|
static void window_object_load_error_update(rct_window *w);
|
|
|
|
static void window_object_load_error_mouseup(rct_window *w, rct_widgetindex widgetIndex);
|
2018-06-20 17:28:51 +02:00
|
|
|
static void window_object_load_error_scrollgetsize(rct_window *w, int32_t scrollIndex, int32_t *width, int32_t *height);
|
|
|
|
static void window_object_load_error_scrollmouseover(rct_window *w, int32_t scrollIndex, int32_t x, int32_t y);
|
|
|
|
static void window_object_load_error_scrollmousedown(rct_window *w, int32_t scrollIndex, int32_t x, int32_t y);
|
2017-06-06 15:34:30 +02:00
|
|
|
static void window_object_load_error_paint(rct_window *w, rct_drawpixelinfo *dpi);
|
2018-06-20 17:28:51 +02:00
|
|
|
static void window_object_load_error_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int32_t scrollIndex);
|
2019-02-02 18:49:34 +01:00
|
|
|
static void window_object_load_error_download_all(rct_window* w);
|
2019-02-03 23:42:25 +01:00
|
|
|
static void next_download();
|
2017-06-06 15:34:30 +02:00
|
|
|
|
|
|
|
static rct_window_event_list window_object_load_error_events = {
|
|
|
|
window_object_load_error_close,
|
|
|
|
window_object_load_error_mouseup,
|
2017-08-15 10:07:44 +02:00
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
2017-06-06 15:34:30 +02:00
|
|
|
window_object_load_error_update,
|
2017-08-15 10:07:44 +02:00
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
2017-06-06 15:34:30 +02:00
|
|
|
window_object_load_error_scrollgetsize,
|
|
|
|
window_object_load_error_scrollmousedown,
|
2017-08-15 10:07:44 +02:00
|
|
|
nullptr,
|
2017-06-06 15:34:30 +02:00
|
|
|
window_object_load_error_scrollmouseover,
|
2017-08-15 10:07:44 +02:00
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
|
|
|
nullptr,
|
2017-06-06 15:34:30 +02:00
|
|
|
window_object_load_error_paint,
|
|
|
|
window_object_load_error_scrollpaint
|
|
|
|
};
|
2018-05-16 20:41:29 +02:00
|
|
|
// clang-format on
|
2017-06-06 15:34:30 +02:00
|
|
|
|
2018-01-19 13:46:13 +01:00
|
|
|
static std::vector<rct_object_entry> _invalid_entries;
|
2018-06-20 17:28:51 +02:00
|
|
|
static int32_t highlighted_index = -1;
|
2018-01-19 13:46:13 +01:00
|
|
|
static std::string file_path;
|
2019-02-03 23:42:25 +01:00
|
|
|
static int32_t _currentDownloadIndex;
|
|
|
|
static bool _downloadingObjects;
|
2017-06-06 15:34:30 +02:00
|
|
|
|
|
|
|
/**
|
2018-06-22 23:21:44 +02:00
|
|
|
* Returns an rct_string_id that represents an rct_object_entry's type.
|
|
|
|
*
|
|
|
|
* Could possibly be moved out of the window file if other
|
|
|
|
* uses exist and a suitable location is found.
|
|
|
|
*/
|
|
|
|
static rct_string_id get_object_type_string(const rct_object_entry* entry)
|
2017-06-06 15:34:30 +02:00
|
|
|
{
|
|
|
|
rct_string_id result;
|
2018-06-20 17:28:51 +02:00
|
|
|
uint8_t objectType = object_entry_get_type(entry);
|
2018-06-22 23:21:44 +02:00
|
|
|
switch (objectType)
|
|
|
|
{
|
2017-06-06 15:34:30 +02:00
|
|
|
case OBJECT_TYPE_RIDE:
|
|
|
|
result = STR_OBJECT_SELECTION_RIDE_VEHICLES_ATTRACTIONS;
|
|
|
|
break;
|
|
|
|
case OBJECT_TYPE_SMALL_SCENERY:
|
|
|
|
result = STR_OBJECT_SELECTION_SMALL_SCENERY;
|
|
|
|
break;
|
|
|
|
case OBJECT_TYPE_LARGE_SCENERY:
|
|
|
|
result = STR_OBJECT_SELECTION_LARGE_SCENERY;
|
|
|
|
break;
|
|
|
|
case OBJECT_TYPE_WALLS:
|
|
|
|
result = STR_OBJECT_SELECTION_WALLS_FENCES;
|
|
|
|
break;
|
|
|
|
case OBJECT_TYPE_BANNERS:
|
|
|
|
result = STR_OBJECT_SELECTION_PATH_SIGNS;
|
|
|
|
break;
|
|
|
|
case OBJECT_TYPE_PATHS:
|
|
|
|
result = STR_OBJECT_SELECTION_FOOTPATHS;
|
|
|
|
break;
|
|
|
|
case OBJECT_TYPE_PATH_BITS:
|
|
|
|
result = STR_OBJECT_SELECTION_PATH_EXTRAS;
|
|
|
|
break;
|
2017-11-20 10:15:52 +01:00
|
|
|
case OBJECT_TYPE_SCENERY_GROUP:
|
2017-06-06 15:34:30 +02:00
|
|
|
result = STR_OBJECT_SELECTION_SCENERY_GROUPS;
|
|
|
|
break;
|
|
|
|
case OBJECT_TYPE_PARK_ENTRANCE:
|
|
|
|
result = STR_OBJECT_SELECTION_PARK_ENTRANCE;
|
|
|
|
break;
|
|
|
|
case OBJECT_TYPE_WATER:
|
|
|
|
result = STR_OBJECT_SELECTION_WATER;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
result = STR_UNKNOWN_OBJECT_TYPE;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-06-22 23:21:44 +02:00
|
|
|
* Returns a newline-separated string listing all object names.
|
|
|
|
* Used for placing all names on the clipboard.
|
|
|
|
*/
|
|
|
|
static void copy_object_names_to_clipboard(rct_window* w)
|
2017-06-06 15:34:30 +02:00
|
|
|
{
|
2017-12-05 09:22:07 +01:00
|
|
|
// Something has gone wrong, this shouldn't happen.
|
|
|
|
// We don't want to allocate stupidly large amounts of memory for no reason
|
|
|
|
assert(w->no_list_items > 0 && w->no_list_items <= OBJECT_ENTRY_COUNT);
|
2017-06-06 15:34:30 +02:00
|
|
|
|
|
|
|
// No system has a newline over 2 characters
|
|
|
|
size_t line_sep_len = strnlen(PLATFORM_NEWLINE, 2);
|
2018-06-22 23:21:44 +02:00
|
|
|
size_t buffer_len = (w->no_list_items * (8 + line_sep_len)) + 1;
|
|
|
|
utf8* buffer = new utf8[buffer_len]{};
|
2017-12-05 09:22:07 +01:00
|
|
|
|
2017-06-06 15:34:30 +02:00
|
|
|
size_t cur_len = 0;
|
2018-06-22 23:21:44 +02:00
|
|
|
for (uint16_t i = 0; i < w->no_list_items; i++)
|
|
|
|
{
|
2017-06-06 15:34:30 +02:00
|
|
|
cur_len += (8 + line_sep_len);
|
|
|
|
assert(cur_len < buffer_len);
|
2017-12-05 09:22:07 +01:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
uint16_t nameLength = 8;
|
2017-12-05 09:22:07 +01:00
|
|
|
for (; nameLength > 0; nameLength--)
|
|
|
|
{
|
|
|
|
if (_invalid_entries[i].name[nameLength - 1] != ' ')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
strncat(buffer, _invalid_entries[i].name, nameLength);
|
2017-06-06 15:34:30 +02:00
|
|
|
strncat(buffer, PLATFORM_NEWLINE, line_sep_len);
|
|
|
|
}
|
2017-12-05 09:22:07 +01:00
|
|
|
|
|
|
|
platform_place_string_on_clipboard(buffer);
|
|
|
|
delete[] buffer;
|
2017-06-06 15:34:30 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
rct_window* window_object_load_error_open(utf8* path, size_t numMissingObjects, const rct_object_entry* missingObjects)
|
2017-06-06 15:34:30 +02:00
|
|
|
{
|
2018-01-19 13:46:13 +01:00
|
|
|
_invalid_entries = std::vector<rct_object_entry>(missingObjects, missingObjects + numMissingObjects);
|
2017-06-06 15:34:30 +02:00
|
|
|
|
|
|
|
// Check if window is already open
|
2018-06-22 23:21:44 +02:00
|
|
|
rct_window* window = window_bring_to_front_by_class(WC_OBJECT_LOAD_ERROR);
|
|
|
|
if (window == nullptr)
|
|
|
|
{
|
|
|
|
window = window_create_centred(WW, WH, &window_object_load_error_events, WC_OBJECT_LOAD_ERROR, 0);
|
2017-06-06 15:34:30 +02:00
|
|
|
|
|
|
|
window->widgets = window_object_load_error_widgets;
|
2019-02-02 18:49:34 +01:00
|
|
|
window->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_COPY_CURRENT) | (1 << WIDX_COPY_ALL)
|
|
|
|
| (1 << WIDX_DOWNLOAD_ALL);
|
2017-06-06 15:34:30 +02:00
|
|
|
|
|
|
|
window_init_scroll_widgets(window);
|
|
|
|
window->colours[0] = COLOUR_LIGHT_BLUE;
|
|
|
|
window->colours[1] = COLOUR_LIGHT_BLUE;
|
|
|
|
window->colours[2] = COLOUR_LIGHT_BLUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Refresh list items and path
|
2018-06-20 17:28:51 +02:00
|
|
|
window->no_list_items = (uint16_t)numMissingObjects;
|
2018-01-19 13:46:13 +01:00
|
|
|
file_path = path;
|
2017-06-06 15:34:30 +02:00
|
|
|
|
|
|
|
window_invalidate(window);
|
|
|
|
return window;
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
static void window_object_load_error_close(rct_window* w)
|
2017-06-06 15:34:30 +02:00
|
|
|
{
|
2018-01-19 13:46:13 +01:00
|
|
|
_invalid_entries.clear();
|
|
|
|
_invalid_entries.shrink_to_fit();
|
2017-06-06 15:34:30 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
static void window_object_load_error_update(rct_window* w)
|
2017-06-06 15:34:30 +02:00
|
|
|
{
|
|
|
|
// Check if the mouse is hovering over the list
|
2018-06-22 23:21:44 +02:00
|
|
|
if (!widget_is_highlighted(w, WIDX_SCROLL))
|
|
|
|
{
|
2017-06-06 15:34:30 +02:00
|
|
|
highlighted_index = -1;
|
|
|
|
widget_invalidate(w, WIDX_SCROLL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
static void window_object_load_error_mouseup(rct_window* w, rct_widgetindex widgetIndex)
|
2017-06-06 15:34:30 +02:00
|
|
|
{
|
2018-06-22 23:21:44 +02:00
|
|
|
switch (widgetIndex)
|
|
|
|
{
|
2017-06-06 15:34:30 +02:00
|
|
|
case WIDX_CLOSE:
|
|
|
|
window_close(w);
|
|
|
|
break;
|
|
|
|
case WIDX_COPY_CURRENT:
|
2017-12-05 09:22:07 +01:00
|
|
|
if (w->selected_list_item > -1 && w->selected_list_item < w->no_list_items)
|
|
|
|
{
|
2018-06-22 23:21:44 +02:00
|
|
|
utf8* selected_name = strndup(_invalid_entries[w->selected_list_item].name, 8);
|
|
|
|
utf8* strp = strchr(selected_name, ' ');
|
2017-12-05 09:22:07 +01:00
|
|
|
if (strp != nullptr)
|
|
|
|
*strp = '\0';
|
|
|
|
|
2017-06-06 15:34:30 +02:00
|
|
|
platform_place_string_on_clipboard(selected_name);
|
|
|
|
SafeFree(selected_name);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WIDX_COPY_ALL:
|
2017-12-05 09:22:07 +01:00
|
|
|
copy_object_names_to_clipboard(w);
|
2017-06-06 15:34:30 +02:00
|
|
|
break;
|
2019-02-02 18:49:34 +01:00
|
|
|
case WIDX_DOWNLOAD_ALL:
|
|
|
|
window_object_load_error_download_all(w);
|
|
|
|
break;
|
2017-06-06 15:34:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
static void window_object_load_error_scrollmouseover(rct_window* w, int32_t scrollIndex, int32_t x, int32_t y)
|
2017-06-06 15:34:30 +02:00
|
|
|
{
|
|
|
|
// Highlight item that the cursor is over, or remove highlighting if none
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t selected_item;
|
2018-04-16 20:27:30 +02:00
|
|
|
selected_item = y / SCROLLABLE_ROW_HEIGHT;
|
2017-06-06 15:34:30 +02:00
|
|
|
if (selected_item < 0 || selected_item >= w->no_list_items)
|
|
|
|
highlighted_index = -1;
|
|
|
|
else
|
|
|
|
highlighted_index = selected_item;
|
|
|
|
|
|
|
|
widget_invalidate(w, WIDX_SCROLL);
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
static void window_object_load_error_select_element_from_list(rct_window* w, int32_t index)
|
2017-06-06 15:34:30 +02:00
|
|
|
{
|
2018-06-22 23:21:44 +02:00
|
|
|
if (index < 0 || index > w->no_list_items)
|
|
|
|
{
|
2017-06-06 15:34:30 +02:00
|
|
|
w->selected_list_item = -1;
|
|
|
|
}
|
2018-06-22 23:21:44 +02:00
|
|
|
else
|
|
|
|
{
|
2017-06-06 15:34:30 +02:00
|
|
|
w->selected_list_item = index;
|
|
|
|
}
|
2017-07-04 22:51:56 +02:00
|
|
|
widget_invalidate(w, WIDX_SCROLL);
|
2017-06-06 15:34:30 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
static void window_object_load_error_scrollmousedown(rct_window* w, int32_t scrollIndex, int32_t x, int32_t y)
|
2017-06-06 15:34:30 +02:00
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t selected_item;
|
2018-04-16 20:27:30 +02:00
|
|
|
selected_item = y / SCROLLABLE_ROW_HEIGHT;
|
2017-06-06 15:34:30 +02:00
|
|
|
window_object_load_error_select_element_from_list(w, selected_item);
|
|
|
|
}
|
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
static void window_object_load_error_scrollgetsize(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height)
|
2017-06-06 15:34:30 +02:00
|
|
|
{
|
2018-04-16 20:27:30 +02:00
|
|
|
*height = w->no_list_items * SCROLLABLE_ROW_HEIGHT;
|
2017-06-06 15:34:30 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
static void window_object_load_error_paint(rct_window* w, rct_drawpixelinfo* dpi)
|
2017-06-06 15:34:30 +02:00
|
|
|
{
|
|
|
|
window_draw_widgets(w, dpi);
|
|
|
|
|
|
|
|
// Draw explanatory message
|
|
|
|
set_format_arg(0, rct_string_id, STR_OBJECT_ERROR_WINDOW_EXPLANATION);
|
2018-06-22 23:21:44 +02:00
|
|
|
gfx_draw_string_left_wrapped(dpi, gCommonFormatArgs, w->x + 5, w->y + 18, WW - 10, STR_BLACK_STRING, COLOUR_BLACK);
|
2017-06-06 15:34:30 +02:00
|
|
|
|
|
|
|
// Draw file name
|
|
|
|
set_format_arg(0, rct_string_id, STR_OBJECT_ERROR_WINDOW_FILE);
|
2018-01-19 13:46:13 +01:00
|
|
|
set_format_arg(2, utf8*, file_path.c_str());
|
2018-06-22 23:21:44 +02:00
|
|
|
gfx_draw_string_left_clipped(dpi, STR_BLACK_STRING, gCommonFormatArgs, COLOUR_BLACK, w->x + 5, w->y + 43, WW - 5);
|
2017-06-06 15:34:30 +02:00
|
|
|
}
|
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
static void window_object_load_error_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex)
|
2017-06-06 15:34:30 +02:00
|
|
|
{
|
|
|
|
gfx_fill_rect(dpi, dpi->x, dpi->y, dpi->x + dpi->width - 1, dpi->y + dpi->height - 1, ColourMapA[w->colours[1]].mid_light);
|
2018-06-20 17:28:51 +02:00
|
|
|
const int32_t list_width = w->widgets[WIDX_SCROLL].right - w->widgets[WIDX_SCROLL].left;
|
2017-06-06 15:34:30 +02:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
for (int32_t i = 0; i < w->no_list_items; i++)
|
2018-04-16 20:27:30 +02:00
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t y = i * SCROLLABLE_ROW_HEIGHT;
|
2017-06-06 15:34:30 +02:00
|
|
|
if (y > dpi->y + dpi->height)
|
|
|
|
break;
|
|
|
|
|
2018-04-16 20:27:30 +02:00
|
|
|
if (y + SCROLLABLE_ROW_HEIGHT < dpi->y)
|
2017-06-06 15:34:30 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// If hovering over item, change the color and fill the backdrop.
|
2018-04-16 20:27:30 +02:00
|
|
|
if (i == w->selected_list_item)
|
|
|
|
gfx_fill_rect(dpi, 0, y, list_width, y + SCROLLABLE_ROW_HEIGHT - 1, ColourMapA[w->colours[1]].darker);
|
|
|
|
else if (i == highlighted_index)
|
|
|
|
gfx_fill_rect(dpi, 0, y, list_width, y + SCROLLABLE_ROW_HEIGHT - 1, ColourMapA[w->colours[1]].mid_dark);
|
2018-04-16 21:33:26 +02:00
|
|
|
else if ((i & 1) != 0) // odd / even check
|
|
|
|
gfx_fill_rect(dpi, 0, y, list_width, y + SCROLLABLE_ROW_HEIGHT - 1, ColourMapA[w->colours[1]].light);
|
2017-06-06 15:34:30 +02:00
|
|
|
|
|
|
|
// Draw the actual object entry's name...
|
2018-04-16 20:27:30 +02:00
|
|
|
gfx_draw_string(dpi, strndup(_invalid_entries[i].name, 8), COLOUR_DARK_GREEN, NAME_COL_LEFT - 3, y);
|
2017-07-19 11:04:00 +02:00
|
|
|
|
|
|
|
// ... source game ...
|
2018-07-03 13:46:45 +02:00
|
|
|
rct_string_id sourceStringId = object_manager_get_source_game_string(
|
2018-07-30 22:44:59 +02:00
|
|
|
object_entry_get_source_game_legacy(&_invalid_entries[i]));
|
2018-04-16 20:27:30 +02:00
|
|
|
gfx_draw_string_left(dpi, sourceStringId, nullptr, COLOUR_DARK_GREEN, SOURCE_COL_LEFT - 3, y);
|
2017-06-06 15:34:30 +02:00
|
|
|
|
|
|
|
// ... and type
|
2017-09-23 12:35:05 +02:00
|
|
|
rct_string_id type = get_object_type_string(&_invalid_entries[i]);
|
2018-04-16 20:27:30 +02:00
|
|
|
gfx_draw_string_left(dpi, type, nullptr, COLOUR_DARK_GREEN, TYPE_COL_LEFT - 3, y);
|
2017-06-06 15:34:30 +02:00
|
|
|
}
|
|
|
|
}
|
2019-02-02 18:49:34 +01:00
|
|
|
|
2019-02-03 23:42:25 +01:00
|
|
|
static void show_progress(const std::string& name, int32_t count, int32_t total)
|
|
|
|
{
|
|
|
|
char str_downloading_objects[256];
|
|
|
|
set_format_arg(0, int16_t, count);
|
|
|
|
set_format_arg(2, int16_t, total);
|
|
|
|
set_format_arg(4, char*, name.c_str());
|
|
|
|
|
|
|
|
format_string(str_downloading_objects, sizeof(str_downloading_objects), STR_DOWNLOADING_OBJECTS, gCommonFormatArgs);
|
|
|
|
|
|
|
|
auto intent = Intent(WC_NETWORK_STATUS);
|
|
|
|
intent.putExtra(INTENT_EXTRA_MESSAGE, std::string(str_downloading_objects));
|
|
|
|
intent.putExtra(INTENT_EXTRA_CALLBACK, []() -> void { _downloadingObjects = false; });
|
|
|
|
context_open_intent(&intent);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void DownloadObject(const std::string name, const std::string_view url)
|
2019-02-02 18:49:34 +01:00
|
|
|
{
|
|
|
|
using namespace OpenRCT2::Network;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Http::Request req;
|
|
|
|
req.method = Http::Method::GET;
|
|
|
|
req.url = url;
|
2019-02-03 23:42:25 +01:00
|
|
|
Http::DoAsync(req, [name](Http::Response response) {
|
|
|
|
if (response.status == Http::Status::OK)
|
|
|
|
{
|
|
|
|
auto data = (uint8_t*)response.body.data();
|
|
|
|
auto dataLen = response.body.size();
|
|
|
|
|
|
|
|
auto& objRepo = OpenRCT2::GetContext()->GetObjectRepository();
|
|
|
|
objRepo.AddObjectFromFile(name, data, dataLen);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Non 200 status");
|
|
|
|
}
|
|
|
|
next_download();
|
|
|
|
});
|
2019-02-02 18:49:34 +01:00
|
|
|
}
|
|
|
|
catch (const std::exception&)
|
|
|
|
{
|
|
|
|
std::printf(" Failed to download %s\n", name.c_str());
|
2019-02-03 23:42:25 +01:00
|
|
|
next_download();
|
2019-02-02 18:49:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-03 23:42:25 +01:00
|
|
|
static void next_download()
|
2019-02-02 18:49:34 +01:00
|
|
|
{
|
|
|
|
using namespace OpenRCT2::Network;
|
|
|
|
|
2019-02-03 23:42:25 +01:00
|
|
|
if (!_downloadingObjects || _currentDownloadIndex >= _invalid_entries.size())
|
2019-02-02 18:49:34 +01:00
|
|
|
{
|
2019-02-03 23:42:25 +01:00
|
|
|
// Finished...
|
|
|
|
return;
|
|
|
|
}
|
2019-02-02 18:49:34 +01:00
|
|
|
|
2019-02-03 23:42:25 +01:00
|
|
|
auto& entry = _invalid_entries[_currentDownloadIndex];
|
|
|
|
auto name = String::Trim(std::string(entry.name, sizeof(entry.name)));
|
|
|
|
show_progress(name, _currentDownloadIndex + 1, (int32_t)_invalid_entries.size());
|
|
|
|
std::printf("Downloading %s...\n", name.c_str());
|
|
|
|
_currentDownloadIndex++;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Http::Request req;
|
|
|
|
req.method = Http::Method::GET;
|
|
|
|
req.url = OPENRCT2_API_LEGACY_OBJECT_URL + name;
|
|
|
|
Http::DoAsync(req, [name](Http::Response response) {
|
2019-02-02 18:49:34 +01:00
|
|
|
if (response.status == Http::Status::OK)
|
|
|
|
{
|
|
|
|
auto jresponse = Json::FromString(response.body);
|
|
|
|
if (jresponse != nullptr)
|
|
|
|
{
|
|
|
|
auto objName = json_string_value(json_object_get(jresponse, "name"));
|
|
|
|
auto downloadLink = json_string_value(json_object_get(jresponse, "download"));
|
|
|
|
if (downloadLink != nullptr)
|
|
|
|
{
|
2019-02-03 23:42:25 +01:00
|
|
|
DownloadObject(objName, downloadLink);
|
2019-02-02 18:49:34 +01:00
|
|
|
}
|
|
|
|
json_decref(jresponse);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::printf(" %s not found\n", name.c_str());
|
2019-02-03 23:42:25 +01:00
|
|
|
next_download();
|
2019-02-02 18:49:34 +01:00
|
|
|
}
|
2019-02-03 23:42:25 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
catch (const std::exception&)
|
|
|
|
{
|
|
|
|
std::printf(" Failed to query %s\n", name.c_str());
|
2019-02-02 18:49:34 +01:00
|
|
|
}
|
|
|
|
}
|
2019-02-03 23:42:25 +01:00
|
|
|
|
|
|
|
static void window_object_load_error_download_all(rct_window* w)
|
|
|
|
{
|
|
|
|
_currentDownloadIndex = 0;
|
|
|
|
_downloadingObjects = true;
|
|
|
|
next_download();
|
|
|
|
}
|