Fix #8829: invalid read in window_guest_open

This commit is contained in:
Ted John 2019-03-09 12:29:33 +00:00
parent d708234489
commit ca023f7c5e
15 changed files with 102 additions and 135 deletions

View File

@ -153,7 +153,7 @@ rct_window* window_banner_open(rct_windownumber number)
viewportWidget = &window_banner_widgets[WIDX_VIEWPORT];
viewport_create(
w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 2,
(viewportWidget->bottom - viewportWidget->top) - 2, 0, view_x, view_y, view_z, 0, -1);
(viewportWidget->bottom - viewportWidget->top) - 2, 0, view_x, view_y, view_z, 0, SPRITE_INDEX_NULL);
w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
window_invalidate(w);
@ -345,7 +345,7 @@ static void window_banner_viewport_rotate(rct_window* w)
rct_widget* viewportWidget = &window_banner_widgets[WIDX_VIEWPORT];
viewport_create(
w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 1,
(viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, -1);
(viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, SPRITE_INDEX_NULL);
w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
window_invalidate(w);

View File

@ -13,6 +13,7 @@
#include <openrct2/Context.h>
#include <openrct2/localisation/StringIds.h>
#include <openrct2/world/Footpath.h>
#include <openrct2/world/Sprite.h>
static void window_editor_main_paint(rct_window* w, rct_drawpixelinfo* dpi);
@ -65,7 +66,7 @@ rct_window* window_editor_main_open()
WC_MAIN_WINDOW, WF_STICK_TO_BACK);
window->widgets = window_editor_main_widgets;
viewport_create(window, window->x, window->y, window->width, window->height, 0, 0x0FFF, 0x0FFF, 0, 0x1, -1);
viewport_create(window, window->x, window->y, window->width, window->height, 0, 0x0FFF, 0x0FFF, 0, 0x1, SPRITE_INDEX_NULL);
window->viewport->flags |= 0x0400;
gCurrentRotation = 0;

View File

@ -701,98 +701,38 @@ void window_guest_viewport_init(rct_window* w)
if (w->page != WINDOW_GUEST_OVERVIEW)
return;
union
auto peep = GET_PEEP(w->number);
if (peep != nullptr)
{
sprite_focus sprite;
coordinate_focus coordinate;
} focus = {}; // The focus will be either a sprite or a coordinate.
focus.sprite.sprite_id = w->number;
Peep* peep = GET_PEEP(w->number);
if (peep->state == PEEP_STATE_PICKED)
{
focus.sprite.sprite_id = SPRITE_INDEX_NULL;
}
else
{
uint8_t final_check = 1;
if (peep->state == PEEP_STATE_ON_RIDE || peep->state == PEEP_STATE_ENTERING_RIDE
|| (peep->state == PEEP_STATE_LEAVING_RIDE && peep->x == LOCATION_NULL))
auto focus = viewport_update_smart_guest_follow(w, peep);
bool reCreateViewport = false;
uint16_t origViewportFlags{};
if (w->viewport != nullptr)
{
Ride* ride = get_ride(peep->current_ride);
if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)
{
rct_vehicle* train = GET_VEHICLE(ride->vehicles[peep->current_train]);
int32_t car = peep->current_car;
// Check all combos, for now skipping y and rot
if (focus.coordinate.x == w->viewport_focus_coordinates.x
&& (focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK) == w->viewport_focus_coordinates.y
&& focus.coordinate.z == w->viewport_focus_coordinates.z
&& focus.coordinate.rotation == w->viewport_focus_coordinates.rotation)
return;
for (; car != 0; car--)
{
train = GET_VEHICLE(train->next_vehicle_on_train);
}
origViewportFlags = w->viewport->flags;
focus.sprite.sprite_id = train->sprite_index;
final_check = 0;
}
reCreateViewport = true;
w->viewport->width = 0;
w->viewport = nullptr;
}
if (peep->x == LOCATION_NULL && final_check)
window_event_invalidate_call(w);
w->viewport_focus_coordinates.x = focus.coordinate.x;
w->viewport_focus_coordinates.y = focus.coordinate.y;
w->viewport_focus_coordinates.z = focus.coordinate.z;
w->viewport_focus_coordinates.rotation = focus.coordinate.rotation;
if (peep->state != PEEP_STATE_PICKED && w->viewport == nullptr)
{
Ride* ride = get_ride(peep->current_ride);
int32_t x = ride->overall_view.x * 32 + 16;
int32_t y = ride->overall_view.y * 32 + 16;
int32_t height = tile_element_height(x, y);
height += 32;
focus.coordinate.x = x;
focus.coordinate.y = y;
focus.coordinate.z = height;
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE;
}
else
{
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE;
focus.sprite.pad_486 &= 0xFFFF;
}
focus.coordinate.rotation = get_current_rotation();
}
uint16_t viewport_flags;
if (w->viewport)
{
// Check all combos, for now skipping y and rot
if (focus.coordinate.x == w->viewport_focus_coordinates.x
&& (focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK) == w->viewport_focus_coordinates.y
&& focus.coordinate.z == w->viewport_focus_coordinates.z
&& focus.coordinate.rotation == w->viewport_focus_coordinates.rotation)
return;
viewport_flags = w->viewport->flags;
w->viewport->width = 0;
w->viewport = nullptr;
}
else
{
viewport_flags = 0;
if (gConfigGeneral.always_show_gridlines)
{
viewport_flags |= VIEWPORT_FLAG_GRIDLINES;
}
}
window_event_invalidate_call(w);
w->viewport_focus_coordinates.x = focus.coordinate.x;
w->viewport_focus_coordinates.y = focus.coordinate.y;
w->viewport_focus_coordinates.z = focus.coordinate.z;
w->viewport_focus_coordinates.rotation = focus.coordinate.rotation;
if (peep->state != PEEP_STATE_PICKED)
{
if (!(w->viewport))
{
rct_widget* view_widget = &w->widgets[WIDX_VIEWPORT];
auto view_widget = &w->widgets[WIDX_VIEWPORT];
int32_t x = view_widget->left + 1 + w->x;
int32_t y = view_widget->top + 1 + w->y;
int32_t width = view_widget->right - view_widget->left - 1;
@ -801,15 +741,15 @@ void window_guest_viewport_init(rct_window* w)
viewport_create(
w, x, y, width, height, 0, focus.coordinate.x, focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK, focus.coordinate.z,
focus.sprite.type & VIEWPORT_FOCUS_TYPE_MASK, focus.sprite.sprite_id);
if (w->viewport != nullptr && reCreateViewport)
{
w->viewport->flags = origViewportFlags;
}
w->flags |= WF_NO_SCROLLING;
window_invalidate(w);
}
window_invalidate(w);
}
if (w->viewport)
w->viewport->flags = viewport_flags;
window_invalidate(w);
}
/**

View File

@ -13,6 +13,7 @@
#include <openrct2/Context.h>
#include <openrct2/localisation/StringIds.h>
#include <openrct2/world/Footpath.h>
#include <openrct2/world/Sprite.h>
// clang-format off
static rct_widget window_main_widgets[] = {
@ -67,7 +68,7 @@ rct_window* window_main_open()
WF_STICK_TO_BACK);
window->widgets = window_main_widgets;
viewport_create(window, window->x, window->y, window->width, window->height, 0, 0x0FFF, 0x0FFF, 0, 0x1, -1);
viewport_create(window, window->x, window->y, window->width, window->height, 0, 0x0FFF, 0x0FFF, 0, 0x1, SPRITE_INDEX_NULL);
window->viewport->flags |= VIEWPORT_FLAG_SOUND_ON;
gCurrentRotation = 0;
gShowGridLinesRefCount = 0;

View File

@ -923,7 +923,7 @@ static void window_park_init_viewport(rct_window* w)
viewport_create(
w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1,
(viewportWidget->right - viewportWidget->left) - 1, (viewportWidget->bottom - viewportWidget->top) - 1, 0, x, y,
z, w->viewport_focus_sprite.type & VIEWPORT_FOCUS_TYPE_MASK, -1);
z, w->viewport_focus_sprite.type & VIEWPORT_FOCUS_TYPE_MASK, SPRITE_INDEX_NULL);
w->flags |= (1 << 2);
window_invalidate(w);
}

View File

@ -565,7 +565,7 @@ static void window_player_set_page(rct_window* w, int32_t page)
{
if (w->viewport == nullptr)
{
viewport_create(w, w->x, w->y, w->width, w->height, 0, 128 * 32, 128 * 32, 0, 1, -1);
viewport_create(w, w->x, w->y, w->width, w->height, 0, 128 * 32, 128 * 32, 0, 1, SPRITE_INDEX_NULL);
w->flags |= WF_NO_SCROLLING;
window_event_invalidate_call(w);
window_player_update_viewport(w, false);

View File

@ -188,7 +188,7 @@ rct_window* window_sign_open(rct_windownumber number)
viewportWidget = &window_sign_widgets[WIDX_VIEWPORT];
viewport_create(
w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 1,
(viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, -1);
(viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, SPRITE_INDEX_NULL);
w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
window_invalidate(w);
@ -381,7 +381,7 @@ static void window_sign_viewport_rotate(rct_window* w)
rct_widget* viewportWidget = &window_sign_widgets[WIDX_VIEWPORT];
viewport_create(
w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 1,
(viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, -1);
(viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, SPRITE_INDEX_NULL);
w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
window_invalidate(w);
@ -445,7 +445,7 @@ rct_window* window_sign_small_open(rct_windownumber number)
viewportWidget = &window_sign_widgets[WIDX_VIEWPORT];
viewport_create(
w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 1,
(viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, -1);
(viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, SPRITE_INDEX_NULL);
w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
w->flags |= WF_NO_SCROLLING;

View File

@ -251,7 +251,8 @@ void window_title_command_editor_open(TitleSequence* sequence, int32_t index, bo
rct_widget* const viewportWidget = &window_title_command_editor_widgets[WIDX_VIEWPORT];
viewport_create(
window, window->x + viewportWidget->left + 1, window->y + viewportWidget->top + 1,
viewportWidget->right - viewportWidget->left - 1, viewportWidget->bottom - viewportWidget->top - 1, 0, 0, 0, 0, 0, -1);
viewportWidget->right - viewportWidget->left - 1, viewportWidget->bottom - viewportWidget->top - 1, 0, 0, 0, 0, 0,
SPRITE_INDEX_NULL);
_window_title_command_editor_index = index;
_window_title_command_editor_insert = insert;

View File

@ -94,7 +94,7 @@ rct_window* window_viewport_open()
w->number = _viewportNumber++;
// Create viewport
viewport_create(w, w->x, w->y, w->width, w->height, 0, 128 * 32, 128 * 32, 0, 1, -1);
viewport_create(w, w->x, w->y, w->width, w->height, 0, 128 * 32, 128 * 32, 0, 1, SPRITE_INDEX_NULL);
rct_window* mainWindow = window_get_main();
if (mainWindow != nullptr)
{

View File

@ -145,7 +145,7 @@ void centre_2d_coordinates(int32_t x, int32_t y, int32_t z, int32_t* out_x, int3
*/
void viewport_create(
rct_window* w, int32_t x, int32_t y, int32_t width, int32_t height, int32_t zoom, int32_t centre_x, int32_t centre_y,
int32_t centre_z, char flags, int16_t sprite)
int32_t centre_z, char flags, uint16_t sprite)
{
rct_viewport* viewport = nullptr;
for (int32_t i = 0; i < MAX_VIEWPORT_COUNT; i++)
@ -686,55 +686,53 @@ void viewport_update_smart_sprite_follow(rct_window* window)
}
}
void viewport_update_smart_guest_follow(rct_window* window, Peep* peep)
viewport_focus viewport_update_smart_guest_follow(rct_window* window, Peep* peep)
{
union
{
sprite_focus sprite;
coordinate_focus coordinate;
} focus = {}; // The focus will be either a sprite or a coordinate.
focus.sprite.sprite_id = window->viewport_smart_follow_sprite;
viewport_focus focus{};
focus.type = VIEWPORT_FOCUS_TYPE_SPRITE;
focus.sprite.sprite_id = peep->sprite_index;
if (peep->state == PEEP_STATE_PICKED)
{
// focus.sprite.sprite_id = SPRITE_INDEX_NULL;
focus.sprite.sprite_id = SPRITE_INDEX_NULL;
window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL;
window->viewport_target_sprite = SPRITE_INDEX_NULL;
return;
return focus;
}
else
{
uint8_t final_check = 1;
bool overallFocus = true;
if (peep->state == PEEP_STATE_ON_RIDE || peep->state == PEEP_STATE_ENTERING_RIDE
|| (peep->state == PEEP_STATE_LEAVING_RIDE && peep->x == LOCATION_NULL))
{
Ride* ride = get_ride(peep->current_ride);
if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)
{
rct_vehicle* train = GET_VEHICLE(ride->vehicles[peep->current_train]);
int32_t car = peep->current_car;
for (; car != 0; car--)
auto train = GET_VEHICLE(ride->vehicles[peep->current_train]);
if (train != nullptr)
{
train = GET_VEHICLE(train->next_vehicle_on_train);
auto car = train->GetCar(peep->current_car);
if (car != nullptr)
{
focus.sprite.sprite_id = car->sprite_index;
overallFocus = false;
}
}
focus.sprite.sprite_id = train->sprite_index;
final_check = 0;
}
}
if (peep->x == LOCATION_NULL && final_check)
if (peep->x == LOCATION_NULL && overallFocus)
{
Ride* ride = get_ride(peep->current_ride);
int32_t x = ride->overall_view.x * 32 + 16;
int32_t y = ride->overall_view.y * 32 + 16;
int32_t height = tile_element_height(x, y);
height += 32;
focus.coordinate.x = x;
focus.coordinate.y = y;
focus.coordinate.z = height;
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE;
auto ride = get_ride(peep->current_ride);
if (ride != nullptr)
{
auto x = (int32_t)ride->overall_view.x * 32 + 16;
auto y = (int32_t)ride->overall_view.y * 32 + 16;
focus.type = VIEWPORT_FOCUS_TYPE_COORDINATE;
focus.coordinate.x = x;
focus.coordinate.y = y;
focus.coordinate.z = tile_element_height(x, y) + 32;
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE;
}
}
else
{
@ -746,6 +744,7 @@ void viewport_update_smart_guest_follow(rct_window* window, Peep* peep)
window->viewport_focus_sprite = focus.sprite;
window->viewport_target_sprite = window->viewport_focus_sprite.sprite_id;
return focus;
}
void viewport_update_smart_staff_follow(rct_window* window, Peep* peep)

View File

@ -122,11 +122,11 @@ void viewport_init_all();
void centre_2d_coordinates(int32_t x, int32_t y, int32_t z, int32_t* out_x, int32_t* out_y, rct_viewport* viewport);
void viewport_create(
rct_window* w, int32_t x, int32_t y, int32_t width, int32_t height, int32_t zoom, int32_t centre_x, int32_t centre_y,
int32_t centre_z, char flags, int16_t sprite);
int32_t centre_z, char flags, uint16_t sprite);
void viewport_update_position(rct_window* window);
void viewport_update_sprite_follow(rct_window* window);
void viewport_update_smart_sprite_follow(rct_window* window);
void viewport_update_smart_guest_follow(rct_window* window, Peep* peep);
viewport_focus viewport_update_smart_guest_follow(rct_window* window, Peep* peep);
void viewport_update_smart_staff_follow(rct_window* window, Peep* peep);
void viewport_update_smart_vehicle_follow(rct_window* window);
void viewport_render(

View File

@ -148,13 +148,23 @@ struct sprite_focus
};
#define VIEWPORT_FOCUS_TYPE_MASK 0xC0
enum
enum VIEWPORT_FOCUS_TYPE : uint8_t
{
VIEWPORT_FOCUS_TYPE_COORDINATE = (1 << 6),
VIEWPORT_FOCUS_TYPE_SPRITE = (1 << 7)
};
#define VIEWPORT_FOCUS_Y_MASK 0x3FFF
struct viewport_focus
{
VIEWPORT_FOCUS_TYPE type{};
union
{
sprite_focus sprite;
coordinate_focus coordinate;
};
};
struct rct_window_event_list
{
void (*close)(struct rct_window*);

View File

@ -10002,3 +10002,13 @@ const rct_vehicle* rct_vehicle::GetHead() const
{
return ((rct_vehicle*)this)->GetHead();
}
const rct_vehicle* rct_vehicle::GetCar(size_t carIndex) const
{
auto car = this;
for (; carIndex != 0; carIndex--)
{
car = GET_VEHICLE(car->next_vehicle_on_train);
}
return car;
}

View File

@ -233,6 +233,7 @@ struct rct_vehicle : rct_sprite_common
}
rct_vehicle* GetHead();
const rct_vehicle* GetHead() const;
const rct_vehicle* GetCar(size_t carIndex) const;
};
struct train_ref

View File

@ -80,6 +80,10 @@ rct_sprite* try_get_sprite(size_t spriteIndex)
rct_sprite* get_sprite(size_t sprite_idx)
{
if (sprite_idx == SPRITE_INDEX_NULL)
{
return nullptr;
}
openrct2_assert(sprite_idx < MAX_SPRITES, "Tried getting sprite %u", sprite_idx);
return &_spriteList[sprite_idx];
}