From e402701c66680c160a474ed3b96fe2d9430e13c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Tue, 14 Feb 2017 00:15:08 +0100 Subject: [PATCH] Verify element indices for tile inspector --- src/openrct2/world/map.c | 23 +++++++ src/openrct2/world/map.h | 1 + src/openrct2/world/tile_inspector.c | 99 +++++++++-------------------- 3 files changed, 55 insertions(+), 68 deletions(-) diff --git a/src/openrct2/world/map.c b/src/openrct2/world/map.c index 9d3e0e7902..1694d67d55 100644 --- a/src/openrct2/world/map.c +++ b/src/openrct2/world/map.c @@ -234,6 +234,29 @@ rct_map_element *map_get_first_element_at(sint32 x, sint32 y) return gMapElementTilePointers[x + y * 256]; } +rct_map_element *map_get_nth_element_at(sint32 x, sint32 y, sint32 n) +{ + rct_map_element * mapElement = map_get_first_element_at(x, y); + if (mapElement == NULL) { + return NULL; + } + // Iterate through elements on this tile. This has to be walked, rather than + // jumped directly to, because n may exceed element count for given tile, + // and the order of tiles (unlike elements) is not synced over multiplayer. + while (n >= 0) { + if (n == 0) { + return mapElement; + } + if (!map_element_is_last_for_tile(mapElement)) { + break; + } + mapElement++; + n--; + } + // The element sought for is not within given tile. + return NULL; +} + void map_set_tile_elements(sint32 x, sint32 y, rct_map_element *elements) { if (x < 0 || y < 0 || x > 255 || y > 255) { diff --git a/src/openrct2/world/map.h b/src/openrct2/world/map.h index 0ec58c4ebd..eedcd17084 100644 --- a/src/openrct2/world/map.h +++ b/src/openrct2/world/map.h @@ -399,6 +399,7 @@ void map_count_remaining_land_rights(); void map_strip_ghost_flag_from_elements(); void map_update_tile_pointers(); rct_map_element *map_get_first_element_at(sint32 x, sint32 y); +rct_map_element *map_get_nth_element_at(sint32 x, sint32 y, sint32 n); void map_set_tile_elements(sint32 x, sint32 y, rct_map_element *elements); sint32 map_element_is_last_for_tile(const rct_map_element *element); uint8 map_element_get_scenery_quadrant(const rct_map_element *element); diff --git a/src/openrct2/world/tile_inspector.c b/src/openrct2/world/tile_inspector.c index 8297bef75e..16b8150863 100644 --- a/src/openrct2/world/tile_inspector.c +++ b/src/openrct2/world/tile_inspector.c @@ -26,23 +26,12 @@ static void map_swap_elements_at(sint32 x, sint32 y, sint16 first, sint16 second) { - rct_map_element *mapElement = map_get_first_element_at(x, y); - rct_map_element *const firstElement = mapElement + first; - rct_map_element *const secondElement = mapElement + second; - bool isValid = map_element_check_address(firstElement) && map_element_check_address(secondElement); + rct_map_element *const firstElement = map_get_nth_element_at(x, y, first); + rct_map_element *const secondElement = map_get_nth_element_at(x, y, second); - openrct2_assert(mapElement != NULL, "Tried swapping elements on a null tile"); - openrct2_assert(isValid, "Tried swapping elements outside of range"); - // swap_elements shouldn't be called when there is only one element on the tile - openrct2_assert(!map_element_is_last_for_tile(mapElement), "Can't swap, there is only one element on the tile"); - - // Make sure both elements are actually on the current tile - sint16 elementCount = 0; - do - { - elementCount++; - } while (!map_element_is_last_for_tile(mapElement++)); - openrct2_assert(elementCount > max(first, second), "first or second is out of range"); + openrct2_assert(firstElement != NULL, "First element is out of range for the tile"); + openrct2_assert(secondElement != NULL, "Second element is out of range for the tile"); + openrct2_assert(firstElement != secondElement, "Can't swap the element with itself"); // Swap their memory rct_map_element temp = *firstElement; @@ -83,10 +72,8 @@ sint32 tile_inspector_insert_corrupt_at(sint32 x, sint32 y, sint16 elementIndex, curruptElement->type = MAP_ELEMENT_TYPE_CORRUPT; // Set the base height to be the same as the selected element - rct_map_element *const baseSelectedElement = map_get_first_element_at(x, y); - rct_map_element *const selectedElement = baseSelectedElement + elementIndex; - bool isValid = map_element_check_address(selectedElement); - if (!baseSelectedElement || !isValid) { + rct_map_element *const selectedElement = map_get_nth_element_at(x, y, elementIndex); + if (!selectedElement) { return MONEY32_UNDEFINED; } curruptElement->base_height = curruptElement->clearance_height = selectedElement->base_height; @@ -136,10 +123,8 @@ sint32 tile_inspector_remove_element_at(sint32 x, sint32 y, sint16 elementIndex, if (flags & GAME_COMMAND_FLAG_APPLY) { // Forcefully remove the element - rct_map_element *const baseMapElement = map_get_first_element_at(x, y); - rct_map_element *const mapElement = baseMapElement + elementIndex; - bool isValid = map_element_check_address(mapElement); - if (!baseMapElement || !isValid) { + rct_map_element *const mapElement = map_get_nth_element_at(x, y, elementIndex); + if (!mapElement) { return MONEY32_UNDEFINED; } map_element_remove(mapElement); @@ -200,10 +185,8 @@ sint32 tile_inspector_rotate_element_at(sint32 x, sint32 y, sint32 elementIndex, { uint8 newRotation, pathEdges, pathCorners; - rct_map_element *const baseMapElement = map_get_first_element_at(x, y); - rct_map_element *const mapElement = baseMapElement + elementIndex; - bool isValid = map_element_check_address(mapElement); - if (!baseMapElement || !isValid) { + rct_map_element *const mapElement = map_get_nth_element_at(x, y, elementIndex); + if (!mapElement) { return MONEY32_UNDEFINED; } switch (map_element_get_type(mapElement)) @@ -341,10 +324,8 @@ sint32 tile_inspector_sort_elements_at(sint32 x, sint32 y, sint32 flags) sint32 tile_inspector_any_base_height_offset(sint32 x, sint32 y, sint16 elementIndex, sint8 heightOffset, sint32 flags) { - rct_map_element *const baseMapElement = map_get_first_element_at(x, y); - rct_map_element *const mapElement = baseMapElement + elementIndex; - bool isValid = map_element_check_address(mapElement); - if (!baseMapElement || !isValid) { + rct_map_element *const mapElement = map_get_nth_element_at(x, y, elementIndex); + if (!mapElement) { return MONEY32_UNDEFINED; } sint16 newBaseHeight = (sint16)mapElement->base_height + heightOffset; @@ -492,11 +473,9 @@ sint32 tile_inspector_surface_toggle_diagonal(sint32 x, sint32 y, sint32 flags) sint32 tile_inspector_path_set_sloped(sint32 x, sint32 y, sint32 elementIndex, bool sloped, sint32 flags) { - rct_map_element *const basePathElement = map_get_first_element_at(x, y); - rct_map_element *const pathElement = basePathElement + elementIndex; - bool isValid = map_element_check_address(pathElement); + rct_map_element *const pathElement = map_get_nth_element_at(x, y, elementIndex); - if (!isValid || !basePathElement || map_element_get_type(pathElement) != MAP_ELEMENT_TYPE_PATH) + if (!pathElement || map_element_get_type(pathElement) != MAP_ELEMENT_TYPE_PATH) { return MONEY32_UNDEFINED; } @@ -523,11 +502,9 @@ sint32 tile_inspector_path_set_sloped(sint32 x, sint32 y, sint32 elementIndex, b sint32 tile_inspector_path_toggle_edge(sint32 x, sint32 y, sint32 elementIndex, sint32 edgeIndex, sint32 flags) { - rct_map_element *const basePathElement = map_get_first_element_at(x, y); - rct_map_element *const pathElement = basePathElement + elementIndex; - bool isValid = map_element_check_address(pathElement); + rct_map_element *const pathElement = map_get_nth_element_at(x, y, elementIndex); - if (!isValid || !basePathElement || map_element_get_type(pathElement) != MAP_ELEMENT_TYPE_PATH) + if (!pathElement || map_element_get_type(pathElement) != MAP_ELEMENT_TYPE_PATH) { return MONEY32_UNDEFINED; } @@ -550,11 +527,9 @@ sint32 tile_inspector_path_toggle_edge(sint32 x, sint32 y, sint32 elementIndex, sint32 tile_inspector_fence_set_slope(sint32 x, sint32 y, sint32 elementIndex, sint32 slopeValue, sint32 flags) { - rct_map_element *const baseFenceElement = map_get_first_element_at(x, y); - rct_map_element *const fenceElement = baseFenceElement + elementIndex; - bool isValid = map_element_check_address(fenceElement); + rct_map_element *const fenceElement = map_get_nth_element_at(x, y, elementIndex); - if (!isValid || !baseFenceElement || map_element_get_type(fenceElement) != MAP_ELEMENT_TYPE_FENCE) + if (!fenceElement || map_element_get_type(fenceElement) != MAP_ELEMENT_TYPE_FENCE) { return MONEY32_UNDEFINED; } @@ -581,16 +556,14 @@ sint32 tile_inspector_fence_set_slope(sint32 x, sint32 y, sint32 elementIndex, s // Broxzier: Copied from track_remove and stripped of unneeded code, but I think this should be smaller sint32 tile_inspector_track_base_height_offset(sint32 x, sint32 y, sint32 elementIndex, sint8 offset, sint32 flags) { - rct_map_element *const baseTrackElement = map_get_first_element_at(x, y); - rct_map_element *const trackElement = baseTrackElement + elementIndex; - bool isValid = map_element_check_address(trackElement); + rct_map_element *const trackElement = map_get_nth_element_at(x, y, elementIndex); if (offset == 0) { return MONEY32_UNDEFINED; } - if (!isValid || !baseTrackElement || map_element_get_type(trackElement) != MAP_ELEMENT_TYPE_TRACK) + if (!trackElement || map_element_get_type(trackElement) != MAP_ELEMENT_TYPE_TRACK) { return MONEY32_UNDEFINED; } @@ -709,11 +682,9 @@ sint32 tile_inspector_track_base_height_offset(sint32 x, sint32 y, sint32 elemen // Broxzier: Basically a copy of the above function, with just two different lines... should probably be combined somehow sint32 tile_inspector_track_set_chain(sint32 x, sint32 y, sint32 elementIndex, bool entireTrackBlock, bool setChain, sint32 flags) { - rct_map_element *const baseTrackElement = map_get_first_element_at(x, y); - rct_map_element *const trackElement = baseTrackElement + elementIndex; - bool isValid = map_element_check_address(trackElement); + rct_map_element *const trackElement = map_get_nth_element_at(x, y, elementIndex); - if (!isValid || !baseTrackElement || map_element_get_type(trackElement) != MAP_ELEMENT_TYPE_TRACK) + if (!trackElement || map_element_get_type(trackElement) != MAP_ELEMENT_TYPE_TRACK) { return MONEY32_UNDEFINED; } @@ -843,11 +814,9 @@ sint32 tile_inspector_track_set_chain(sint32 x, sint32 y, sint32 elementIndex, b sint32 tile_inspector_scenery_set_quarter_location(sint32 x, sint32 y, sint32 elementIndex, sint32 quarterIndex, sint32 flags) { - rct_map_element *const baseMapElement = map_get_first_element_at(x, y); - rct_map_element *const mapElement = baseMapElement + elementIndex; - bool isValid = map_element_check_address(mapElement); + rct_map_element *const mapElement = map_get_nth_element_at(x, y, elementIndex); - if (!isValid || !baseMapElement || map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SCENERY) + if (!mapElement || map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SCENERY) { return MONEY32_UNDEFINED; } @@ -874,11 +843,9 @@ sint32 tile_inspector_scenery_set_quarter_location(sint32 x, sint32 y, sint32 el sint32 tile_inspector_scenery_set_quarter_collision(sint32 x, sint32 y, sint32 elementIndex, sint32 quarterIndex, sint32 flags) { - rct_map_element *const baseMapElement = map_get_first_element_at(x, y); - rct_map_element *const mapElement = baseMapElement + elementIndex; - bool isValid = map_element_check_address(mapElement); + rct_map_element *const mapElement = map_get_nth_element_at(x, y, elementIndex); - if (!isValid || !baseMapElement || map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SCENERY) + if (!mapElement || map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_SCENERY) { return MONEY32_UNDEFINED; } @@ -899,11 +866,9 @@ sint32 tile_inspector_scenery_set_quarter_collision(sint32 x, sint32 y, sint32 e sint32 tile_inspector_banner_toggle_blocking_edge(sint32 x, sint32 y, sint32 elementIndex, sint32 edgeIndex, sint32 flags) { - rct_map_element *const baseBannerElement = map_get_first_element_at(x, y); - rct_map_element *const bannerElement = baseBannerElement + elementIndex; - bool isValid = map_element_check_address(bannerElement); + rct_map_element *const bannerElement = map_get_nth_element_at(x, y, elementIndex); - if (!isValid || !baseBannerElement || map_element_get_type(bannerElement) != MAP_ELEMENT_TYPE_BANNER) + if (!bannerElement || map_element_get_type(bannerElement) != MAP_ELEMENT_TYPE_BANNER) { return MONEY32_UNDEFINED; } @@ -923,11 +888,9 @@ sint32 tile_inspector_banner_toggle_blocking_edge(sint32 x, sint32 y, sint32 ele sint32 tile_inspector_corrupt_clamp(sint32 x, sint32 y, sint32 elementIndex, sint32 flags) { - rct_map_element *const baseCorruptElement = map_get_first_element_at(x, y); - rct_map_element *const corruptElement = baseCorruptElement + elementIndex; - bool isValid = map_element_check_address(corruptElement); + rct_map_element *const corruptElement = map_get_nth_element_at(x, y, elementIndex); - if (!isValid || !baseCorruptElement || map_element_get_type(corruptElement) != MAP_ELEMENT_TYPE_CORRUPT) + if (!corruptElement || map_element_get_type(corruptElement) != MAP_ELEMENT_TYPE_CORRUPT) { return MONEY32_UNDEFINED; }